embassy_ha/
entity_sensor.rs

1use crate::{Entity, EntityCommonConfig, EntityConfig, NumericSensorState, constants};
2
3#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
4pub enum StateClass {
5    #[default]
6    Measurement,
7    Total,
8    TotalIncreasing,
9}
10
11impl StateClass {
12    pub fn as_str(&self) -> &'static str {
13        match self {
14            StateClass::Measurement => constants::HA_STATE_CLASS_MEASUREMENT,
15            StateClass::Total => constants::HA_STATE_CLASS_TOTAL,
16            StateClass::TotalIncreasing => constants::HA_STATE_CLASS_TOTAL_INCREASING,
17        }
18    }
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
22pub enum SensorClass {
23    #[default]
24    Generic,
25    ApparentPower,
26    Aqi,
27    AtmosphericPressure,
28    Battery,
29    CarbonDioxide,
30    CarbonMonoxide,
31    Current,
32    DataRate,
33    DataSize,
34    Date,
35    Distance,
36    Duration,
37    Energy,
38    EnergyStorage,
39    Enum,
40    Frequency,
41    Gas,
42    Humidity,
43    Illuminance,
44    Irradiance,
45    Moisture,
46    Monetary,
47    NitrogenDioxide,
48    NitrogenMonoxide,
49    NitrousOxide,
50    Ozone,
51    Ph,
52    Pm1,
53    Pm25,
54    Pm10,
55    PowerFactor,
56    Power,
57    Precipitation,
58    PrecipitationIntensity,
59    Pressure,
60    ReactivePower,
61    SignalStrength,
62    SoundPressure,
63    Speed,
64    SulphurDioxide,
65    Temperature,
66    Timestamp,
67    VolatileOrganicCompounds,
68    VolatileOrganicCompoundsParts,
69    Voltage,
70    Volume,
71    VolumeFlowRate,
72    VolumeStorage,
73    Water,
74    Weight,
75    WindSpeed,
76    Other(&'static str),
77}
78
79impl SensorClass {
80    pub fn as_str(&self) -> Option<&'static str> {
81        match self {
82            SensorClass::Generic => None,
83            SensorClass::Other(s) => Some(s),
84            SensorClass::ApparentPower => Some(constants::HA_DEVICE_CLASS_SENSOR_APPARENT_POWER),
85            SensorClass::Aqi => Some(constants::HA_DEVICE_CLASS_SENSOR_AQI),
86            SensorClass::AtmosphericPressure => {
87                Some(constants::HA_DEVICE_CLASS_SENSOR_ATMOSPHERIC_PRESSURE)
88            }
89            SensorClass::Battery => Some(constants::HA_DEVICE_CLASS_SENSOR_BATTERY),
90            SensorClass::CarbonDioxide => Some(constants::HA_DEVICE_CLASS_SENSOR_CARBON_DIOXIDE),
91            SensorClass::CarbonMonoxide => Some(constants::HA_DEVICE_CLASS_SENSOR_CARBON_MONOXIDE),
92            SensorClass::Current => Some(constants::HA_DEVICE_CLASS_SENSOR_CURRENT),
93            SensorClass::DataRate => Some(constants::HA_DEVICE_CLASS_SENSOR_DATA_RATE),
94            SensorClass::DataSize => Some(constants::HA_DEVICE_CLASS_SENSOR_DATA_SIZE),
95            SensorClass::Date => Some(constants::HA_DEVICE_CLASS_SENSOR_DATE),
96            SensorClass::Distance => Some(constants::HA_DEVICE_CLASS_SENSOR_DISTANCE),
97            SensorClass::Duration => Some(constants::HA_DEVICE_CLASS_SENSOR_DURATION),
98            SensorClass::Energy => Some(constants::HA_DEVICE_CLASS_SENSOR_ENERGY),
99            SensorClass::EnergyStorage => Some(constants::HA_DEVICE_CLASS_SENSOR_ENERGY_STORAGE),
100            SensorClass::Enum => Some(constants::HA_DEVICE_CLASS_SENSOR_ENUM),
101            SensorClass::Frequency => Some(constants::HA_DEVICE_CLASS_SENSOR_FREQUENCY),
102            SensorClass::Gas => Some(constants::HA_DEVICE_CLASS_SENSOR_GAS),
103            SensorClass::Humidity => Some(constants::HA_DEVICE_CLASS_SENSOR_HUMIDITY),
104            SensorClass::Illuminance => Some(constants::HA_DEVICE_CLASS_SENSOR_ILLUMINANCE),
105            SensorClass::Irradiance => Some(constants::HA_DEVICE_CLASS_SENSOR_IRRADIANCE),
106            SensorClass::Moisture => Some(constants::HA_DEVICE_CLASS_SENSOR_MOISTURE),
107            SensorClass::Monetary => Some(constants::HA_DEVICE_CLASS_SENSOR_MONETARY),
108            SensorClass::NitrogenDioxide => {
109                Some(constants::HA_DEVICE_CLASS_SENSOR_NITROGEN_DIOXIDE)
110            }
111            SensorClass::NitrogenMonoxide => {
112                Some(constants::HA_DEVICE_CLASS_SENSOR_NITROGEN_MONOXIDE)
113            }
114            SensorClass::NitrousOxide => Some(constants::HA_DEVICE_CLASS_SENSOR_NITROUS_OXIDE),
115            SensorClass::Ozone => Some(constants::HA_DEVICE_CLASS_SENSOR_OZONE),
116            SensorClass::Ph => Some(constants::HA_DEVICE_CLASS_SENSOR_PH),
117            SensorClass::Pm1 => Some(constants::HA_DEVICE_CLASS_SENSOR_PM1),
118            SensorClass::Pm25 => Some(constants::HA_DEVICE_CLASS_SENSOR_PM25),
119            SensorClass::Pm10 => Some(constants::HA_DEVICE_CLASS_SENSOR_PM10),
120            SensorClass::PowerFactor => Some(constants::HA_DEVICE_CLASS_SENSOR_POWER_FACTOR),
121            SensorClass::Power => Some(constants::HA_DEVICE_CLASS_SENSOR_POWER),
122            SensorClass::Precipitation => Some(constants::HA_DEVICE_CLASS_SENSOR_PRECIPITATION),
123            SensorClass::PrecipitationIntensity => {
124                Some(constants::HA_DEVICE_CLASS_SENSOR_PRECIPITATION_INTENSITY)
125            }
126            SensorClass::Pressure => Some(constants::HA_DEVICE_CLASS_SENSOR_PRESSURE),
127            SensorClass::ReactivePower => Some(constants::HA_DEVICE_CLASS_SENSOR_REACTIVE_POWER),
128            SensorClass::SignalStrength => Some(constants::HA_DEVICE_CLASS_SENSOR_SIGNAL_STRENGTH),
129            SensorClass::SoundPressure => Some(constants::HA_DEVICE_CLASS_SENSOR_SOUND_PRESSURE),
130            SensorClass::Speed => Some(constants::HA_DEVICE_CLASS_SENSOR_SPEED),
131            SensorClass::SulphurDioxide => Some(constants::HA_DEVICE_CLASS_SENSOR_SULPHUR_DIOXIDE),
132            SensorClass::Temperature => Some(constants::HA_DEVICE_CLASS_SENSOR_TEMPERATURE),
133            SensorClass::Timestamp => Some(constants::HA_DEVICE_CLASS_SENSOR_TIMESTAMP),
134            SensorClass::VolatileOrganicCompounds => {
135                Some(constants::HA_DEVICE_CLASS_SENSOR_VOLATILE_ORGANIC_COMPOUNDS)
136            }
137            SensorClass::VolatileOrganicCompoundsParts => {
138                Some(constants::HA_DEVICE_CLASS_SENSOR_VOLATILE_ORGANIC_COMPOUNDS_PARTS)
139            }
140            SensorClass::Voltage => Some(constants::HA_DEVICE_CLASS_SENSOR_VOLTAGE),
141            SensorClass::Volume => Some(constants::HA_DEVICE_CLASS_SENSOR_VOLUME),
142            SensorClass::VolumeFlowRate => Some(constants::HA_DEVICE_CLASS_SENSOR_VOLUME_FLOW_RATE),
143            SensorClass::VolumeStorage => Some(constants::HA_DEVICE_CLASS_SENSOR_VOLUME_STORAGE),
144            SensorClass::Water => Some(constants::HA_DEVICE_CLASS_SENSOR_WATER),
145            SensorClass::Weight => Some(constants::HA_DEVICE_CLASS_SENSOR_WEIGHT),
146            SensorClass::WindSpeed => Some(constants::HA_DEVICE_CLASS_SENSOR_WIND_SPEED),
147        }
148    }
149}
150
151#[derive(Debug, Default)]
152pub struct SensorConfig {
153    pub common: EntityCommonConfig,
154    pub class: SensorClass,
155    pub state_class: StateClass,
156    pub unit: Option<&'static str>,
157    pub suggested_display_precision: Option<u8>,
158}
159
160impl SensorConfig {
161    pub(crate) fn populate(&self, config: &mut EntityConfig) {
162        self.common.populate(config);
163        config.domain = constants::HA_DOMAIN_SENSOR;
164        config.device_class = self.class.as_str();
165        config.state_class = Some(self.state_class.as_str());
166        config.measurement_unit = self.unit;
167        config.suggested_display_precision = self.suggested_display_precision;
168    }
169}
170
171pub struct Sensor<'a>(Entity<'a>);
172
173impl<'a> Sensor<'a> {
174    pub(crate) fn new(entity: Entity<'a>) -> Self {
175        Self(entity)
176    }
177
178    pub fn publish(&mut self, value: f32) {
179        let publish = self.0.with_data(|data| {
180            let storage = data.storage.as_numeric_sensor_mut();
181            let prev_state = storage.state.replace(NumericSensorState {
182                value,
183                timestamp: embassy_time::Instant::now(),
184            });
185            match prev_state {
186                Some(state) => state.value != value,
187                None => true,
188            }
189        });
190        if publish {
191            self.0.queue_publish();
192        }
193    }
194}