aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binary_state.rs9
-rw-r--r--src/constants.rs2
-rw-r--r--src/entity_binary_sensor.rs25
-rw-r--r--src/entity_button.rs17
-rw-r--r--src/entity_number.rs34
-rw-r--r--src/entity_sensor.rs21
-rw-r--r--src/entity_switch.rs16
-rw-r--r--src/lib.rs325
8 files changed, 335 insertions, 114 deletions
diff --git a/src/binary_state.rs b/src/binary_state.rs
index d512856..5648a18 100644
--- a/src/binary_state.rs
+++ b/src/binary_state.rs
@@ -2,8 +2,17 @@ use core::str::FromStr;
2 2
3use crate::constants; 3use crate::constants;
4 4
5#[derive(Debug)]
5pub struct InvalidBinaryState; 6pub struct InvalidBinaryState;
6 7
8impl core::fmt::Display for InvalidBinaryState {
9 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
10 f.write_str("invalid binary state, allowed values are 'ON' and 'OFF' (case insensitive)")
11 }
12}
13
14impl core::error::Error for InvalidBinaryState {}
15
7#[derive(Debug, Clone, Copy, PartialEq, Eq)] 16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum BinaryState { 17pub enum BinaryState {
9 On, 18 On,
diff --git a/src/constants.rs b/src/constants.rs
index 8c48bed..2b1a8bf 100644
--- a/src/constants.rs
+++ b/src/constants.rs
@@ -200,6 +200,8 @@ pub const HA_SWITCH_STATE_OFF: &str = "OFF";
200pub const HA_BINARY_SENSOR_STATE_ON: &str = "ON"; 200pub const HA_BINARY_SENSOR_STATE_ON: &str = "ON";
201pub const HA_BINARY_SENSOR_STATE_OFF: &str = "OFF"; 201pub const HA_BINARY_SENSOR_STATE_OFF: &str = "OFF";
202 202
203pub const HA_BUTTON_PAYLOAD_PRESS: &str = "PRESS";
204
203// Number units - Energy 205// Number units - Energy
204pub const HA_UNIT_ENERGY_JOULE: &str = "J"; 206pub const HA_UNIT_ENERGY_JOULE: &str = "J";
205pub const HA_UNIT_ENERGY_KILOJOULE: &str = "kJ"; 207pub const HA_UNIT_ENERGY_KILOJOULE: &str = "kJ";
diff --git a/src/entity_binary_sensor.rs b/src/entity_binary_sensor.rs
index b80f718..ea270f2 100644
--- a/src/entity_binary_sensor.rs
+++ b/src/entity_binary_sensor.rs
@@ -1,4 +1,4 @@
1use crate::{BinaryState, Entity, EntityCommonConfig, EntityConfig, constants}; 1use crate::{BinarySensorState, BinaryState, Entity, EntityCommonConfig, EntityConfig, constants};
2 2
3#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] 3#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
4pub enum BinarySensorClass { 4pub enum BinarySensorClass {
@@ -66,13 +66,28 @@ impl<'a> BinarySensor<'a> {
66 } 66 }
67 67
68 pub fn set(&mut self, state: BinaryState) { 68 pub fn set(&mut self, state: BinaryState) {
69 self.0.publish(state.as_str().as_bytes()); 69 let publish = self.0.with_data(|data| {
70 let storage = data.storage.as_binary_sensor_mut();
71 let publish = match &storage.state {
72 Some(s) => s.value != state,
73 None => true,
74 };
75 storage.state = Some(BinarySensorState {
76 value: state,
77 timestamp: embassy_time::Instant::now(),
78 });
79 publish
80 });
81 if publish {
82 self.0.queue_publish();
83 }
70 } 84 }
71 85
72 pub fn value(&self) -> Option<BinaryState> { 86 pub fn value(&self) -> Option<BinaryState> {
73 self.0 87 self.0.with_data(|data| {
74 .with_data(|data| BinaryState::try_from(data.publish_value.as_slice())) 88 let storage = data.storage.as_binary_sensor_mut();
75 .ok() 89 storage.state.as_ref().map(|s| s.value)
90 })
76 } 91 }
77 92
78 pub fn toggle(&mut self) -> BinaryState { 93 pub fn toggle(&mut self) -> BinaryState {
diff --git a/src/entity_button.rs b/src/entity_button.rs
index baa89a4..35f787f 100644
--- a/src/entity_button.rs
+++ b/src/entity_button.rs
@@ -36,6 +36,21 @@ impl<'a> Button<'a> {
36 } 36 }
37 37
38 pub async fn pressed(&mut self) { 38 pub async fn pressed(&mut self) {
39 self.0.wait_command().await; 39 loop {
40 self.0.wait_command().await;
41 let pressed = self.0.with_data(|data| {
42 let storage = data.storage.as_button_mut();
43 if !storage.consumed && storage.timestamp.is_some() {
44 storage.consumed = true;
45 true
46 } else {
47 false
48 }
49 });
50
51 if pressed {
52 break;
53 }
54 }
40 } 55 }
41} 56}
diff --git a/src/entity_number.rs b/src/entity_number.rs
index 90d849c..f96c3c7 100644
--- a/src/entity_number.rs
+++ b/src/entity_number.rs
@@ -1,4 +1,6 @@
1use crate::{Entity, EntityCommonConfig, EntityConfig, NumberUnit, constants}; 1use crate::{
2 Entity, EntityCommonConfig, EntityConfig, NumberCommand, NumberState, NumberUnit, constants,
3};
2 4
3#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] 5#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
4pub enum NumberMode { 6pub enum NumberMode {
@@ -167,27 +169,37 @@ impl<'a> Number<'a> {
167 Self(entity) 169 Self(entity)
168 } 170 }
169 171
170 pub fn value(&mut self) -> Option<f32> { 172 pub fn get(&mut self) -> Option<f32> {
171 self.0.with_data(|data| { 173 self.0.with_data(|data| {
172 str::from_utf8(&data.command_value) 174 let storage = data.storage.as_number_mut();
173 .ok() 175 storage.state.as_ref().map(|s| s.value)
174 .and_then(|v| v.parse::<f32>().ok())
175 }) 176 })
176 } 177 }
177 178
178 pub async fn value_wait(&mut self) -> f32 { 179 pub async fn wait(&mut self) -> f32 {
179 loop { 180 loop {
180 self.0.wait_command().await; 181 self.0.wait_command().await;
181 match self.value() { 182 match self.get() {
182 Some(value) => return value, 183 Some(value) => return value,
183 None => continue, 184 None => continue,
184 } 185 }
185 } 186 }
186 } 187 }
187 188
188 pub fn value_set(&mut self, value: f32) { 189 pub fn set(&mut self, value: f32) {
189 use core::fmt::Write; 190 let publish = self.0.with_data(|data| {
190 self.0 191 let storage = data.storage.as_number_mut();
191 .publish_with(|view| write!(view, "{}", value).unwrap()); 192 let timestamp = embassy_time::Instant::now();
193 let publish = match &storage.command {
194 Some(command) => command.value != value,
195 None => true,
196 };
197 storage.state = Some(NumberState { value, timestamp });
198 storage.command = Some(NumberCommand { value, timestamp });
199 publish
200 });
201 if publish {
202 self.0.queue_publish();
203 }
192 } 204 }
193} 205}
diff --git a/src/entity_sensor.rs b/src/entity_sensor.rs
index 5d7794f..d70e80e 100644
--- a/src/entity_sensor.rs
+++ b/src/entity_sensor.rs
@@ -1,4 +1,6 @@
1use crate::{Entity, EntityCommonConfig, EntityConfig, TemperatureUnit, constants}; 1use crate::{
2 Entity, EntityCommonConfig, EntityConfig, NumericSensorState, TemperatureUnit, constants,
3};
2 4
3#[derive(Debug, Default)] 5#[derive(Debug, Default)]
4pub struct TemperatureSensorConfig { 6pub struct TemperatureSensorConfig {
@@ -23,8 +25,19 @@ impl<'a> TemperatureSensor<'a> {
23 } 25 }
24 26
25 pub fn publish(&mut self, temperature: f32) { 27 pub fn publish(&mut self, temperature: f32) {
26 use core::fmt::Write; 28 let publish = self.0.with_data(|data| {
27 self.0 29 let storage = data.storage.as_numeric_sensor_mut();
28 .publish_with(|view| write!(view, "{}", temperature).unwrap()); 30 let prev_state = storage.state.replace(NumericSensorState {
31 value: temperature,
32 timestamp: embassy_time::Instant::now(),
33 });
34 match prev_state {
35 Some(state) => state.value != temperature,
36 None => true,
37 }
38 });
39 if publish {
40 self.0.queue_publish();
41 }
29 } 42 }
30} 43}
diff --git a/src/entity_switch.rs b/src/entity_switch.rs
index 4d2efdb..0277288 100644
--- a/src/entity_switch.rs
+++ b/src/entity_switch.rs
@@ -1,4 +1,4 @@
1use crate::{BinaryState, Entity, EntityCommonConfig, EntityConfig, constants}; 1use crate::{BinaryState, Entity, EntityCommonConfig, EntityConfig, SwitchState, constants};
2 2
3#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] 3#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
4pub enum SwitchClass { 4pub enum SwitchClass {
@@ -34,8 +34,10 @@ impl<'a> Switch<'a> {
34 } 34 }
35 35
36 pub fn state(&self) -> Option<BinaryState> { 36 pub fn state(&self) -> Option<BinaryState> {
37 self.0 37 self.0.with_data(|data| {
38 .with_data(|data| BinaryState::try_from(data.command_value.as_slice()).ok()) 38 let storage = data.storage.as_switch_mut();
39 storage.state.as_ref().map(|s| s.value)
40 })
39 } 41 }
40 42
41 pub fn toggle(&mut self) -> BinaryState { 43 pub fn toggle(&mut self) -> BinaryState {
@@ -45,7 +47,13 @@ impl<'a> Switch<'a> {
45 } 47 }
46 48
47 pub fn set(&mut self, state: BinaryState) { 49 pub fn set(&mut self, state: BinaryState) {
48 self.0.publish(state.as_str().as_bytes()); 50 self.0.with_data(|data| {
51 let storage = data.storage.as_switch_mut();
52 storage.state = Some(SwitchState {
53 value: state,
54 timestamp: embassy_time::Instant::now(),
55 });
56 })
49 } 57 }
50 58
51 pub async fn wait(&mut self) -> BinaryState { 59 pub async fn wait(&mut self) -> BinaryState {
diff --git a/src/lib.rs b/src/lib.rs
index 8d7bfaf..ac26a45 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -181,49 +181,133 @@ impl Default for DeviceResources {
181 } 181 }
182} 182}
183 183
184struct EntityData { 184#[derive(Debug, Default)]
185 config: EntityConfig, 185pub struct ButtonStorage {
186 publish_dirty: bool, 186 pub timestamp: Option<embassy_time::Instant>,
187 publish_value: heapless::Vec<u8, 64>, 187 pub consumed: bool,
188 command_dirty: bool,
189 command_value: heapless::Vec<u8, 64>,
190 command_wait_waker: Option<Waker>,
191 command_instant: Option<embassy_time::Instant>,
192} 188}
193 189
194pub struct Entity<'a> { 190#[derive(Debug)]
195 pub(crate) data: &'a RefCell<Option<EntityData>>, 191pub struct SwitchCommand {
196 pub(crate) waker: &'a AtomicWaker, 192 pub value: BinaryState,
193 pub timestamp: embassy_time::Instant,
197} 194}
198 195
199impl<'a> Entity<'a> { 196#[derive(Debug)]
200 pub fn publish(&mut self, payload: &[u8]) { 197pub struct SwitchState {
201 self.publish_with(|view| view.extend_from_slice(payload).unwrap()); 198 pub value: BinaryState,
199 pub timestamp: embassy_time::Instant,
200}
201
202#[derive(Debug, Default)]
203pub struct SwitchStorage {
204 pub state: Option<SwitchState>,
205 pub command: Option<SwitchCommand>,
206}
207
208#[derive(Debug)]
209pub struct BinarySensorState {
210 pub value: BinaryState,
211 pub timestamp: embassy_time::Instant,
212}
213
214#[derive(Debug, Default)]
215pub struct BinarySensorStorage {
216 pub state: Option<BinarySensorState>,
217}
218
219#[derive(Debug)]
220pub struct NumericSensorState {
221 pub value: f32,
222 pub timestamp: embassy_time::Instant,
223}
224
225#[derive(Debug, Default)]
226pub struct NumericSensorStorage {
227 pub state: Option<NumericSensorState>,
228}
229
230#[derive(Debug)]
231pub struct NumberState {
232 pub value: f32,
233 pub timestamp: embassy_time::Instant,
234}
235
236#[derive(Debug)]
237pub struct NumberCommand {
238 pub value: f32,
239 pub timestamp: embassy_time::Instant,
240}
241
242#[derive(Debug, Default)]
243pub struct NumberStorage {
244 pub state: Option<NumberState>,
245 pub command: Option<NumberCommand>,
246}
247
248#[derive(Debug)]
249pub enum EntityStorage {
250 Button(ButtonStorage),
251 Switch(SwitchStorage),
252 BinarySensor(BinarySensorStorage),
253 NumericSensor(NumericSensorStorage),
254 Number(NumberStorage),
255}
256
257impl EntityStorage {
258 pub fn as_button_mut(&mut self) -> &mut ButtonStorage {
259 match self {
260 EntityStorage::Button(storage) => storage,
261 _ => panic!("expected storage type to be button"),
262 }
202 } 263 }
203 264
204 pub fn publish_with<F>(&mut self, f: F) 265 pub fn as_switch_mut(&mut self) -> &mut SwitchStorage {
205 where 266 match self {
206 F: FnOnce(&mut VecView<u8>), 267 EntityStorage::Switch(storage) => storage,
207 { 268 _ => panic!("expected storage type to be switch"),
208 self.with_data(move |data| { 269 }
209 data.publish_value.clear();
210 f(data.publish_value.as_mut_view());
211 data.publish_dirty = true;
212 });
213 self.waker.wake();
214 } 270 }
215 271
216 pub fn publish_str(&mut self, payload: &str) { 272 pub fn as_binary_sensor_mut(&mut self) -> &mut BinarySensorStorage {
217 self.publish(payload.as_bytes()); 273 match self {
274 EntityStorage::BinarySensor(storage) => storage,
275 _ => panic!("expected storage type to be binary_sensor"),
276 }
218 } 277 }
219 278
220 pub fn publish_display(&mut self, payload: &impl core::fmt::Display) { 279 pub fn as_numeric_sensor_mut(&mut self) -> &mut NumericSensorStorage {
221 use core::fmt::Write; 280 match self {
281 EntityStorage::NumericSensor(storage) => storage,
282 _ => panic!("expected storage type to be numeric_sensor"),
283 }
284 }
222 285
223 self.publish_with(|view| { 286 pub fn as_number_mut(&mut self) -> &mut NumberStorage {
224 view.clear(); 287 match self {
225 write!(view, "{}", payload).unwrap(); 288 EntityStorage::Number(storage) => storage,
226 }); 289 _ => panic!("expected storage type to be number"),
290 }
291 }
292}
293
294struct EntityData {
295 config: EntityConfig,
296 storage: EntityStorage,
297 publish: bool,
298 command: bool,
299 command_waker: Option<Waker>,
300}
301
302pub struct Entity<'a> {
303 pub(crate) data: &'a RefCell<Option<EntityData>>,
304 pub(crate) waker: &'a AtomicWaker,
305}
306
307impl<'a> Entity<'a> {
308 pub fn queue_publish(&mut self) {
309 self.with_data(|data| data.publish = true);
310 self.waker.wake();
227 } 311 }
228 312
229 pub async fn wait_command(&mut self) { 313 pub async fn wait_command(&mut self) {
@@ -238,14 +322,14 @@ impl<'a> Entity<'a> {
238 ) -> core::task::Poll<Self::Output> { 322 ) -> core::task::Poll<Self::Output> {
239 let this = &mut self.as_mut().0; 323 let this = &mut self.as_mut().0;
240 this.with_data(|data| { 324 this.with_data(|data| {
241 let dirty = data.command_dirty; 325 let dirty = data.command;
242 if dirty { 326 if dirty {
243 data.command_dirty = false; 327 data.command = false;
244 data.command_wait_waker = None; 328 data.command_waker = None;
245 core::task::Poll::Ready(()) 329 core::task::Poll::Ready(())
246 } else { 330 } else {
247 // TODO: avoid clone if waker would wake 331 // TODO: avoid clone if waker would wake
248 data.command_wait_waker = Some(cx.waker().clone()); 332 data.command_waker = Some(cx.waker().clone());
249 core::task::Poll::Pending 333 core::task::Poll::Pending
250 } 334 }
251 }) 335 })
@@ -255,13 +339,6 @@ impl<'a> Entity<'a> {
255 Fut(self).await 339 Fut(self).await
256 } 340 }
257 341
258 pub fn with_command<F, R>(&mut self, f: F) -> R
259 where
260 F: FnOnce(&[u8]) -> R,
261 {
262 self.with_data(|data| f(data.command_value.as_slice()))
263 }
264
265 fn with_data<F, R>(&self, f: F) -> R 342 fn with_data<F, R>(&self, f: F) -> R
266 where 343 where
267 F: FnOnce(&mut EntityData) -> R, 344 F: FnOnce(&mut EntityData) -> R,
@@ -303,7 +380,7 @@ impl<'a> Device<'a> {
303 } 380 }
304 } 381 }
305 382
306 pub fn create_entity(&self, config: EntityConfig) -> Entity<'a> { 383 pub fn create_entity(&self, config: EntityConfig, storage: EntityStorage) -> Entity<'a> {
307 let index = 'outer: { 384 let index = 'outer: {
308 for idx in 0..self.entities.len() { 385 for idx in 0..self.entities.len() {
309 if self.entities[idx].borrow().is_none() { 386 if self.entities[idx].borrow().is_none() {
@@ -315,12 +392,10 @@ impl<'a> Device<'a> {
315 392
316 let data = EntityData { 393 let data = EntityData {
317 config, 394 config,
318 publish_dirty: false, 395 storage,
319 publish_value: Default::default(), 396 publish: false,
320 command_dirty: false, 397 command: false,
321 command_value: Default::default(), 398 command_waker: None,
322 command_wait_waker: None,
323 command_instant: None,
324 }; 399 };
325 self.entities[index].replace(Some(data)); 400 self.entities[index].replace(Some(data));
326 401
@@ -339,7 +414,10 @@ impl<'a> Device<'a> {
339 entity_config.id = id; 414 entity_config.id = id;
340 config.populate(&mut entity_config); 415 config.populate(&mut entity_config);
341 416
342 let entity = self.create_entity(entity_config); 417 let entity = self.create_entity(
418 entity_config,
419 EntityStorage::NumericSensor(Default::default()),
420 );
343 TemperatureSensor::new(entity) 421 TemperatureSensor::new(entity)
344 } 422 }
345 423
@@ -348,7 +426,7 @@ impl<'a> Device<'a> {
348 entity_config.id = id; 426 entity_config.id = id;
349 config.populate(&mut entity_config); 427 config.populate(&mut entity_config);
350 428
351 let entity = self.create_entity(entity_config); 429 let entity = self.create_entity(entity_config, EntityStorage::Button(Default::default()));
352 Button::new(entity) 430 Button::new(entity)
353 } 431 }
354 432
@@ -357,7 +435,7 @@ impl<'a> Device<'a> {
357 entity_config.id = id; 435 entity_config.id = id;
358 config.populate(&mut entity_config); 436 config.populate(&mut entity_config);
359 437
360 let entity = self.create_entity(entity_config); 438 let entity = self.create_entity(entity_config, EntityStorage::Number(Default::default()));
361 Number::new(entity) 439 Number::new(entity)
362 } 440 }
363 441
@@ -366,7 +444,7 @@ impl<'a> Device<'a> {
366 entity_config.id = id; 444 entity_config.id = id;
367 config.populate(&mut entity_config); 445 config.populate(&mut entity_config);
368 446
369 let entity = self.create_entity(entity_config); 447 let entity = self.create_entity(entity_config, EntityStorage::Switch(Default::default()));
370 Switch::new(entity) 448 Switch::new(entity)
371 } 449 }
372 450
@@ -379,18 +457,21 @@ impl<'a> Device<'a> {
379 entity_config.id = id; 457 entity_config.id = id;
380 config.populate(&mut entity_config); 458 config.populate(&mut entity_config);
381 459
382 let entity = self.create_entity(entity_config); 460 let entity = self.create_entity(
461 entity_config,
462 EntityStorage::BinarySensor(Default::default()),
463 );
383 BinarySensor::new(entity) 464 BinarySensor::new(entity)
384 } 465 }
385 466
386 pub async fn run<T: Transport>(&mut self, transport: &mut T) -> ! { 467 pub async fn run<T: Transport>(&mut self, transport: &mut T) -> ! {
387 loop { 468 loop {
388 self.run_iteration(&mut *transport).await; 469 self.run_iteration(transport).await;
389 Timer::after_millis(5000).await; 470 Timer::after_millis(5000).await;
390 } 471 }
391 } 472 }
392 473
393 async fn run_iteration<T: Transport>(&mut self, transport: T) { 474 async fn run_iteration<T: Transport>(&mut self, transport: &mut T) {
394 let mut client = embedded_mqtt::Client::new(self.mqtt_resources, transport); 475 let mut client = embedded_mqtt::Client::new(self.mqtt_resources, transport);
395 client.connect(self.config.device_id).await.unwrap(); 476 client.connect(self.config.device_id).await.unwrap();
396 477
@@ -491,7 +572,7 @@ impl<'a> Device<'a> {
491 client.subscribe(&self.command_topic_buffer).await.unwrap(); 572 client.subscribe(&self.command_topic_buffer).await.unwrap();
492 } 573 }
493 574
494 loop { 575 'outer_loop: loop {
495 use core::fmt::Write; 576 use core::fmt::Write;
496 577
497 for entity in self.entities { 578 for entity in self.entities {
@@ -502,11 +583,37 @@ impl<'a> Device<'a> {
502 None => break, 583 None => break,
503 }; 584 };
504 585
505 if !entity.publish_dirty { 586 if !entity.publish {
506 continue; 587 continue;
507 } 588 }
508 589
509 entity.publish_dirty = false; 590 entity.publish = false;
591 self.publish_buffer.clear();
592
593 match &entity.storage {
594 EntityStorage::Switch(SwitchStorage {
595 state: Some(SwitchState { value, .. }),
596 ..
597 }) => self
598 .publish_buffer
599 .extend_from_slice(value.as_str().as_bytes())
600 .unwrap(),
601 EntityStorage::BinarySensor(BinarySensorStorage {
602 state: Some(BinarySensorState { value, .. }),
603 }) => self
604 .publish_buffer
605 .extend_from_slice(value.as_str().as_bytes())
606 .unwrap(),
607 EntityStorage::NumericSensor(NumericSensorStorage {
608 state: Some(NumericSensorState { value, .. }),
609 ..
610 }) => write!(self.publish_buffer, "{}", value).unwrap(),
611 EntityStorage::Number(NumberStorage {
612 state: Some(NumberState { value, .. }),
613 ..
614 }) => write!(self.publish_buffer, "{}", value).unwrap(),
615 _ => continue, // TODO: print warning
616 }
510 617
511 self.state_topic_buffer.clear(); 618 self.state_topic_buffer.clear();
512 write!( 619 write!(
@@ -518,11 +625,6 @@ impl<'a> Device<'a> {
518 } 625 }
519 ) 626 )
520 .unwrap(); 627 .unwrap();
521
522 self.publish_buffer.clear();
523 self.publish_buffer
524 .extend_from_slice(entity.publish_value.as_slice())
525 .unwrap();
526 } 628 }
527 629
528 client 630 client
@@ -533,33 +635,78 @@ impl<'a> Device<'a> {
533 635
534 let receive = client.receive(); 636 let receive = client.receive();
535 let waker = wait_on_atomic_waker(self.waker); 637 let waker = wait_on_atomic_waker(self.waker);
536 match embassy_futures::select::select(receive, waker).await { 638 let publish = match embassy_futures::select::select(receive, waker).await {
537 embassy_futures::select::Either::First(packet) => { 639 embassy_futures::select::Either::First(packet) => match packet.unwrap() {
538 let packet = packet.unwrap(); 640 embedded_mqtt::Packet::Publish(publish) => publish,
539 let mut read_buffer = [0u8; 128]; 641 _ => continue,
540 if let embedded_mqtt::Packet::Publish(publish) = packet { 642 },
541 if publish.data_len > 128 { 643 embassy_futures::select::Either::Second(_) => continue,
542 defmt::warn!("mqtt publish payload too large, ignoring message"); 644 };
543 } else { 645
544 let b = &mut read_buffer[..publish.data_len]; 646 let entity = 'entity_search_block: {
545 client.receive_data(b).await.unwrap(); 647 for entity in self.entities {
546 defmt::info!("receive value {}", str::from_utf8(b).unwrap()); 648 let mut data = entity.borrow_mut();
547 for entity in self.entities { 649 let data = match data.as_mut() {
548 let mut entity = entity.borrow_mut(); 650 Some(data) => data,
549 if let Some(entity) = entity.as_mut() { 651 None => break,
550 entity.command_dirty = true; 652 };
551 entity.command_value.clear(); 653
552 entity.command_value.extend_from_slice(b).unwrap(); 654 self.command_topic_buffer.clear();
553 entity.command_instant = Some(embassy_time::Instant::now()); 655 write!(
554 if let Some(ref waker) = entity.command_wait_waker { 656 self.command_topic_buffer,
555 waker.wake_by_ref(); 657 "{}",
556 } 658 CommandTopicDisplay {
557 } 659 device_id: self.config.device_id,
558 } 660 entity_id: data.config.id
559 } 661 }
662 )
663 .unwrap();
664
665 if self.command_topic_buffer.as_bytes() == publish.topic.as_bytes() {
666 break 'entity_search_block entity;
560 } 667 }
561 } 668 }
562 embassy_futures::select::Either::Second(_) => {} 669 continue 'outer_loop;
670 };
671
672 let mut read_buffer = [0u8; 128];
673 if publish.data_len > read_buffer.len() {
674 defmt::warn!("mqtt publish payload too large, ignoring message");
675 continue;
676 }
677 let b = &mut read_buffer[..publish.data_len];
678 client.receive_data(b).await.unwrap();
679 let command = str::from_utf8(b).unwrap();
680
681 let mut entity = entity.borrow_mut();
682 let data = entity.as_mut().unwrap();
683
684 match &mut data.storage {
685 EntityStorage::Button(button_storage) => {
686 assert_eq!(command, constants::HA_BUTTON_PAYLOAD_PRESS);
687 button_storage.consumed = false;
688 button_storage.timestamp = Some(embassy_time::Instant::now());
689 }
690 EntityStorage::Switch(switch_storage) => {
691 let command = command.parse::<BinaryState>().unwrap();
692 switch_storage.command = Some(SwitchCommand {
693 value: command,
694 timestamp: embassy_time::Instant::now(),
695 });
696 }
697 EntityStorage::Number(number_storage) => {
698 let command = command.parse::<f32>().unwrap();
699 number_storage.command = Some(NumberCommand {
700 value: command,
701 timestamp: embassy_time::Instant::now(),
702 });
703 }
704 _ => continue 'outer_loop,
705 }
706
707 data.command = true;
708 if let Some(waker) = data.command_waker.take() {
709 waker.wake();
563 } 710 }
564 } 711 }
565 } 712 }