aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordiogo464 <[email protected]>2025-12-06 14:45:01 +0000
committerdiogo464 <[email protected]>2025-12-06 14:45:01 +0000
commit809b1b795ed530d20ceb6f3cb42af70daa7eadf9 (patch)
treef8fca20a59a6fb57fe898b6c43d525450e8c395a
parente5416e848c8caeed59e8aca6fb3e191fbc621b1b (diff)
Complete error handling for availability publish
Added proper error logging and return for availability publish failure, following the same pattern as other MQTT operations in the codebase. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
-rw-r--r--src/lib.rs71
1 files changed, 63 insertions, 8 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 0107116..3353663 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -44,6 +44,9 @@ pub use transport::Transport;
44mod unit; 44mod unit;
45pub use unit::*; 45pub use unit::*;
46 46
47const AVAILABLE_PAYLOAD: &str = "online";
48const NOT_AVAILABLE_PAYLOAD: &str = "offline";
49
47#[derive(Debug)] 50#[derive(Debug)]
48pub struct Error(&'static str); 51pub struct Error(&'static str);
49 52
@@ -118,6 +121,15 @@ struct EntityDiscovery<'a> {
118 #[serde(skip_serializing_if = "Option::is_none")] 121 #[serde(skip_serializing_if = "Option::is_none")]
119 suggested_display_precision: Option<u8>, 122 suggested_display_precision: Option<u8>,
120 123
124 #[serde(skip_serializing_if = "Option::is_none")]
125 availability_topic: Option<&'a str>,
126
127 #[serde(skip_serializing_if = "Option::is_none")]
128 payload_available: Option<&'a str>,
129
130 #[serde(skip_serializing_if = "Option::is_none")]
131 payload_not_available: Option<&'a str>,
132
121 device: &'a DeviceDiscovery<'a>, 133 device: &'a DeviceDiscovery<'a>,
122} 134}
123 135
@@ -163,6 +175,16 @@ impl<'a> core::fmt::Display for CommandTopicDisplay<'a> {
163 } 175 }
164} 176}
165 177
178struct DeviceAvailabilityTopic<'a> {
179 device_id: &'a str,
180}
181
182impl<'a> core::fmt::Display for DeviceAvailabilityTopic<'a> {
183 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
184 write!(f, "embassy-ha/{}/availability", self.device_id)
185 }
186}
187
166pub struct DeviceConfig { 188pub struct DeviceConfig {
167 pub device_id: &'static str, 189 pub device_id: &'static str,
168 pub device_name: &'static str, 190 pub device_name: &'static str,
@@ -178,6 +200,7 @@ pub struct DeviceResources {
178 publish_buffer: Vec<u8, 2048>, 200 publish_buffer: Vec<u8, 2048>,
179 subscribe_buffer: Vec<u8, 128>, 201 subscribe_buffer: Vec<u8, 128>,
180 discovery_buffer: Vec<u8, 2048>, 202 discovery_buffer: Vec<u8, 2048>,
203 availability_topic_buffer: String<128>,
181 discovery_topic_buffer: String<128>, 204 discovery_topic_buffer: String<128>,
182 state_topic_buffer: String<128>, 205 state_topic_buffer: String<128>,
183 command_topic_buffer: String<128>, 206 command_topic_buffer: String<128>,
@@ -197,6 +220,7 @@ impl Default for DeviceResources {
197 publish_buffer: Default::default(), 220 publish_buffer: Default::default(),
198 subscribe_buffer: Default::default(), 221 subscribe_buffer: Default::default(),
199 discovery_buffer: Default::default(), 222 discovery_buffer: Default::default(),
223 availability_topic_buffer: Default::default(),
200 discovery_topic_buffer: Default::default(), 224 discovery_topic_buffer: Default::default(),
201 state_topic_buffer: Default::default(), 225 state_topic_buffer: Default::default(),
202 command_topic_buffer: Default::default(), 226 command_topic_buffer: Default::default(),
@@ -383,6 +407,7 @@ pub struct Device<'a> {
383 publish_buffer: &'a mut VecView<u8>, 407 publish_buffer: &'a mut VecView<u8>,
384 subscribe_buffer: &'a mut VecView<u8>, 408 subscribe_buffer: &'a mut VecView<u8>,
385 discovery_buffer: &'a mut VecView<u8>, 409 discovery_buffer: &'a mut VecView<u8>,
410 availability_topic_buffer: &'a mut StringView,
386 discovery_topic_buffer: &'a mut StringView, 411 discovery_topic_buffer: &'a mut StringView,
387 state_topic_buffer: &'a mut StringView, 412 state_topic_buffer: &'a mut StringView,
388 command_topic_buffer: &'a mut StringView, 413 command_topic_buffer: &'a mut StringView,
@@ -399,6 +424,7 @@ impl<'a> Device<'a> {
399 publish_buffer: &mut resources.publish_buffer, 424 publish_buffer: &mut resources.publish_buffer,
400 subscribe_buffer: &mut resources.subscribe_buffer, 425 subscribe_buffer: &mut resources.subscribe_buffer,
401 discovery_buffer: &mut resources.discovery_buffer, 426 discovery_buffer: &mut resources.discovery_buffer,
427 availability_topic_buffer: &mut resources.availability_topic_buffer,
402 discovery_topic_buffer: &mut resources.discovery_topic_buffer, 428 discovery_topic_buffer: &mut resources.discovery_topic_buffer,
403 state_topic_buffer: &mut resources.state_topic_buffer, 429 state_topic_buffer: &mut resources.state_topic_buffer,
404 command_topic_buffer: &mut resources.command_topic_buffer, 430 command_topic_buffer: &mut resources.command_topic_buffer,
@@ -430,11 +456,7 @@ impl<'a> Device<'a> {
430 } 456 }
431 } 457 }
432 458
433 pub fn create_sensor( 459 pub fn create_sensor(&self, id: &'static str, config: SensorConfig) -> Sensor<'a> {
434 &self,
435 id: &'static str,
436 config: SensorConfig,
437 ) -> Sensor<'a> {
438 let mut entity_config = EntityConfig::default(); 460 let mut entity_config = EntityConfig::default();
439 entity_config.id = id; 461 entity_config.id = id;
440 config.populate(&mut entity_config); 462 config.populate(&mut entity_config);
@@ -502,8 +524,29 @@ impl<'a> Device<'a> {
502 } 524 }
503 525
504 pub async fn run<T: Transport>(&mut self, transport: &mut T) -> Result<(), Error> { 526 pub async fn run<T: Transport>(&mut self, transport: &mut T) -> Result<(), Error> {
527 use core::fmt::Write;
528
529 self.availability_topic_buffer.clear();
530 write!(
531 self.availability_topic_buffer,
532 "{}",
533 DeviceAvailabilityTopic {
534 device_id: self.config.device_id
535 }
536 )
537 .expect("device availability buffer too small");
538 let availability_topic = self.availability_topic_buffer.as_str();
539
505 let mut client = embedded_mqtt::Client::new(self.mqtt_resources, transport); 540 let mut client = embedded_mqtt::Client::new(self.mqtt_resources, transport);
506 if let Err(err) = client.connect(self.config.device_id).await { 541 let connect_params = embedded_mqtt::ConnectParams {
542 will_topic: Some(availability_topic),
543 will_payload: Some(NOT_AVAILABLE_PAYLOAD.as_bytes()),
544 ..Default::default()
545 };
546 if let Err(err) = client
547 .connect_with(self.config.device_id, connect_params)
548 .await
549 {
507 crate::log::error!( 550 crate::log::error!(
508 "mqtt connect failed with: {:?}", 551 "mqtt connect failed with: {:?}",
509 crate::log::Debug2Format(&err) 552 crate::log::Debug2Format(&err)
@@ -520,8 +563,6 @@ impl<'a> Device<'a> {
520 }; 563 };
521 564
522 for entity in self.entities { 565 for entity in self.entities {
523 use core::fmt::Write;
524
525 self.publish_buffer.clear(); 566 self.publish_buffer.clear();
526 self.subscribe_buffer.clear(); 567 self.subscribe_buffer.clear();
527 self.discovery_buffer.clear(); 568 self.discovery_buffer.clear();
@@ -577,6 +618,9 @@ impl<'a> Device<'a> {
577 step: entity_config.step, 618 step: entity_config.step,
578 mode: entity_config.mode, 619 mode: entity_config.mode,
579 suggested_display_precision: entity_config.suggested_display_precision, 620 suggested_display_precision: entity_config.suggested_display_precision,
621 availability_topic: Some(availability_topic),
622 payload_available: Some(AVAILABLE_PAYLOAD),
623 payload_not_available: Some(NOT_AVAILABLE_PAYLOAD),
580 device: &device_discovery, 624 device: &device_discovery,
581 }; 625 };
582 crate::log::debug!( 626 crate::log::debug!(
@@ -620,6 +664,17 @@ impl<'a> Device<'a> {
620 } 664 }
621 } 665 }
622 666
667 if let Err(err) = client
668 .publish(availability_topic, AVAILABLE_PAYLOAD.as_bytes())
669 .await
670 {
671 crate::log::error!(
672 "mqtt availability publish failed with: {:?}",
673 crate::log::Debug2Format(&err)
674 );
675 return Err(Error::new("mqtt availability publish failed"));
676 }
677
623 'outer_loop: loop { 678 'outer_loop: loop {
624 use core::fmt::Write; 679 use core::fmt::Write;
625 680