aboutsummaryrefslogtreecommitdiff
path: root/src/entity_number.rs
blob: f96c3c7decb7caf9897ea03a45d3a02f143c8d13 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
use crate::{
    Entity, EntityCommonConfig, EntityConfig, NumberCommand, NumberState, NumberUnit, constants,
};

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum NumberMode {
    #[default]
    Auto,
    Box,
    Slider,
}

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum NumberClass {
    #[default]
    Generic,
    ApparentPower,
    Aqi,
    AtmosphericPressure,
    Battery,
    CarbonDioxide,
    CarbonMonoxide,
    Current,
    DataRate,
    DataSize,
    Distance,
    Duration,
    Energy,
    Frequency,
    Gas,
    Humidity,
    Illuminance,
    Irradiance,
    Moisture,
    Monetary,
    NitrogenDioxide,
    NitrogenMonoxide,
    NitrousOxide,
    Ozone,
    Ph,
    Pm1,
    Pm25,
    Pm10,
    PowerFactor,
    Power,
    Precipitation,
    PrecipitationIntensity,
    Pressure,
    ReactivePower,
    SignalStrength,
    SoundPressure,
    Speed,
    SulphurDioxide,
    Temperature,
    VolatileOrganicCompounds,
    VolatileOrganicCompoundsParts,
    Voltage,
    Volume,
    Water,
    Weight,
    WindSpeed,
}

#[derive(Debug)]
pub struct NumberConfig {
    pub common: EntityCommonConfig,
    pub unit: Option<NumberUnit>,
    pub min: Option<f32>,
    pub max: Option<f32>,
    pub step: Option<f32>,
    pub mode: NumberMode,
    pub class: NumberClass,
}

impl Default for NumberConfig {
    fn default() -> Self {
        Self {
            common: EntityCommonConfig::default(),
            unit: None,
            min: None,
            max: None,
            step: None,
            mode: NumberMode::Auto,
            class: NumberClass::Generic,
        }
    }
}

impl NumberConfig {
    pub(crate) fn populate(&self, config: &mut EntityConfig) {
        self.common.populate(config);
        config.domain = constants::HA_DOMAIN_NUMBER;
        config.mode = Some(match self.mode {
            NumberMode::Auto => constants::HA_NUMBER_MODE_AUTO,
            NumberMode::Box => constants::HA_NUMBER_MODE_BOX,
            NumberMode::Slider => constants::HA_NUMBER_MODE_SLIDER,
        });
        config.device_class = match self.class {
            NumberClass::Generic => None,
            NumberClass::ApparentPower => Some(constants::HA_DEVICE_CLASS_NUMBER_APPARENT_POWER),
            NumberClass::Aqi => Some(constants::HA_DEVICE_CLASS_NUMBER_AQI),
            NumberClass::AtmosphericPressure => {
                Some(constants::HA_DEVICE_CLASS_NUMBER_ATMOSPHERIC_PRESSURE)
            }
            NumberClass::Battery => Some(constants::HA_DEVICE_CLASS_NUMBER_BATTERY),
            NumberClass::CarbonDioxide => Some(constants::HA_DEVICE_CLASS_NUMBER_CARBON_DIOXIDE),
            NumberClass::CarbonMonoxide => Some(constants::HA_DEVICE_CLASS_NUMBER_CARBON_MONOXIDE),
            NumberClass::Current => Some(constants::HA_DEVICE_CLASS_NUMBER_CURRENT),
            NumberClass::DataRate => Some(constants::HA_DEVICE_CLASS_NUMBER_DATA_RATE),
            NumberClass::DataSize => Some(constants::HA_DEVICE_CLASS_NUMBER_DATA_SIZE),
            NumberClass::Distance => Some(constants::HA_DEVICE_CLASS_NUMBER_DISTANCE),
            NumberClass::Duration => Some(constants::HA_DEVICE_CLASS_NUMBER_DURATION),
            NumberClass::Energy => Some(constants::HA_DEVICE_CLASS_NUMBER_ENERGY),
            NumberClass::Frequency => Some(constants::HA_DEVICE_CLASS_NUMBER_FREQUENCY),
            NumberClass::Gas => Some(constants::HA_DEVICE_CLASS_NUMBER_GAS),
            NumberClass::Humidity => Some(constants::HA_DEVICE_CLASS_NUMBER_HUMIDITY),
            NumberClass::Illuminance => Some(constants::HA_DEVICE_CLASS_NUMBER_ILLUMINANCE),
            NumberClass::Irradiance => Some(constants::HA_DEVICE_CLASS_NUMBER_IRRADIANCE),
            NumberClass::Moisture => Some(constants::HA_DEVICE_CLASS_NUMBER_MOISTURE),
            NumberClass::Monetary => Some(constants::HA_DEVICE_CLASS_NUMBER_MONETARY),
            NumberClass::NitrogenDioxide => {
                Some(constants::HA_DEVICE_CLASS_NUMBER_NITROGEN_DIOXIDE)
            }
            NumberClass::NitrogenMonoxide => {
                Some(constants::HA_DEVICE_CLASS_NUMBER_NITROGEN_MONOXIDE)
            }
            NumberClass::NitrousOxide => Some(constants::HA_DEVICE_CLASS_NUMBER_NITROUS_OXIDE),
            NumberClass::Ozone => Some(constants::HA_DEVICE_CLASS_NUMBER_OZONE),
            NumberClass::Ph => Some(constants::HA_DEVICE_CLASS_NUMBER_PH),
            NumberClass::Pm1 => Some(constants::HA_DEVICE_CLASS_NUMBER_PM1),
            NumberClass::Pm25 => Some(constants::HA_DEVICE_CLASS_NUMBER_PM25),
            NumberClass::Pm10 => Some(constants::HA_DEVICE_CLASS_NUMBER_PM10),
            NumberClass::PowerFactor => Some(constants::HA_DEVICE_CLASS_NUMBER_POWER_FACTOR),
            NumberClass::Power => Some(constants::HA_DEVICE_CLASS_NUMBER_POWER),
            NumberClass::Precipitation => Some(constants::HA_DEVICE_CLASS_NUMBER_PRECIPITATION),
            NumberClass::PrecipitationIntensity => {
                Some(constants::HA_DEVICE_CLASS_NUMBER_PRECIPITATION_INTENSITY)
            }
            NumberClass::Pressure => Some(constants::HA_DEVICE_CLASS_NUMBER_PRESSURE),
            NumberClass::ReactivePower => Some(constants::HA_DEVICE_CLASS_NUMBER_REACTIVE_POWER),
            NumberClass::SignalStrength => Some(constants::HA_DEVICE_CLASS_NUMBER_SIGNAL_STRENGTH),
            NumberClass::SoundPressure => Some(constants::HA_DEVICE_CLASS_NUMBER_SOUND_PRESSURE),
            NumberClass::Speed => Some(constants::HA_DEVICE_CLASS_NUMBER_SPEED),
            NumberClass::SulphurDioxide => Some(constants::HA_DEVICE_CLASS_NUMBER_SULPHUR_DIOXIDE),
            NumberClass::Temperature => Some(constants::HA_DEVICE_CLASS_NUMBER_TEMPERATURE),
            NumberClass::VolatileOrganicCompounds => {
                Some(constants::HA_DEVICE_CLASS_NUMBER_VOLATILE_ORGANIC_COMPOUNDS)
            }
            NumberClass::VolatileOrganicCompoundsParts => {
                Some(constants::HA_DEVICE_CLASS_NUMBER_VOLATILE_ORGANIC_COMPOUNDS_PARTS)
            }
            NumberClass::Voltage => Some(constants::HA_DEVICE_CLASS_NUMBER_VOLTAGE),
            NumberClass::Volume => Some(constants::HA_DEVICE_CLASS_NUMBER_VOLUME),
            NumberClass::Water => Some(constants::HA_DEVICE_CLASS_NUMBER_WATER),
            NumberClass::Weight => Some(constants::HA_DEVICE_CLASS_NUMBER_WEIGHT),
            NumberClass::WindSpeed => Some(constants::HA_DEVICE_CLASS_NUMBER_WIND_SPEED),
        };
        config.measurement_unit = self.unit.as_ref().map(|u| u.as_str());
        config.min = self.min;
        config.max = self.max;
        config.step = self.step;
    }
}

pub struct Number<'a>(Entity<'a>);

impl<'a> Number<'a> {
    pub(crate) fn new(entity: Entity<'a>) -> Self {
        Self(entity)
    }

    pub fn get(&mut self) -> Option<f32> {
        self.0.with_data(|data| {
            let storage = data.storage.as_number_mut();
            storage.state.as_ref().map(|s| s.value)
        })
    }

    pub async fn wait(&mut self) -> f32 {
        loop {
            self.0.wait_command().await;
            match self.get() {
                Some(value) => return value,
                None => continue,
            }
        }
    }

    pub fn set(&mut self, value: f32) {
        let publish = self.0.with_data(|data| {
            let storage = data.storage.as_number_mut();
            let timestamp = embassy_time::Instant::now();
            let publish = match &storage.command {
                Some(command) => command.value != value,
                None => true,
            };
            storage.state = Some(NumberState { value, timestamp });
            storage.command = Some(NumberCommand { value, timestamp });
            publish
        });
        if publish {
            self.0.queue_publish();
        }
    }
}