diff options
| author | diogo464 <[email protected]> | 2025-12-08 20:49:23 +0000 |
|---|---|---|
| committer | diogo464 <[email protected]> | 2025-12-08 20:49:23 +0000 |
| commit | 8ac9ddd2cbc9cf454eae066e5e60d05ee714a83e (patch) | |
| tree | e4797159d8fdae7e8521295fd8178cadc8c2974a | |
| parent | 28d9961141a38ebde8bd6144636c3021eb2755a5 (diff) | |
formatting and improved timeout handling
| -rw-r--r-- | examples/button.rs | 6 | ||||
| -rw-r--r-- | src/entity_category.rs | 1 | ||||
| -rw-r--r-- | src/entity_sensor.rs | 28 | ||||
| -rw-r--r-- | src/entity_switch.rs | 4 | ||||
| -rw-r--r-- | src/lib.rs | 230 | ||||
| -rw-r--r-- | src/log.rs | 2 | ||||
| -rw-r--r-- | src/unit.rs | 56 |
7 files changed, 238 insertions, 89 deletions
diff --git a/examples/button.rs b/examples/button.rs index 4a2a228..ea8c4a9 100644 --- a/examples/button.rs +++ b/examples/button.rs | |||
| @@ -20,7 +20,11 @@ async fn main_task(spawner: Spawner) { | |||
| 20 | }, | 20 | }, |
| 21 | ); | 21 | ); |
| 22 | 22 | ||
| 23 | let button = embassy_ha::create_button(&device, "button-sensor-id", embassy_ha::ButtonConfig::default()); | 23 | let button = embassy_ha::create_button( |
| 24 | &device, | ||
| 25 | "button-sensor-id", | ||
| 26 | embassy_ha::ButtonConfig::default(), | ||
| 27 | ); | ||
| 24 | 28 | ||
| 25 | spawner.must_spawn(button_task(button)); | 29 | spawner.must_spawn(button_task(button)); |
| 26 | 30 | ||
diff --git a/src/entity_category.rs b/src/entity_category.rs index 741e7dd..2560fd4 100644 --- a/src/entity_category.rs +++ b/src/entity_category.rs | |||
| @@ -14,4 +14,3 @@ impl EntityCategory { | |||
| 14 | } | 14 | } |
| 15 | } | 15 | } |
| 16 | } | 16 | } |
| 17 | |||
diff --git a/src/entity_sensor.rs b/src/entity_sensor.rs index 1a99754..1168c37 100644 --- a/src/entity_sensor.rs +++ b/src/entity_sensor.rs | |||
| @@ -1,6 +1,4 @@ | |||
| 1 | use crate::{ | 1 | use crate::{Entity, EntityCommonConfig, EntityConfig, NumericSensorState, constants}; |
| 2 | Entity, EntityCommonConfig, EntityConfig, NumericSensorState, constants, | ||
| 3 | }; | ||
| 4 | 2 | ||
| 5 | #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] | 3 | #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] |
| 6 | pub enum StateClass { | 4 | pub enum StateClass { |
| @@ -90,7 +88,9 @@ impl SensorClass { | |||
| 90 | SensorClass::Other(s) => Some(s), | 88 | SensorClass::Other(s) => Some(s), |
| 91 | SensorClass::ApparentPower => Some(constants::HA_DEVICE_CLASS_SENSOR_APPARENT_POWER), | 89 | SensorClass::ApparentPower => Some(constants::HA_DEVICE_CLASS_SENSOR_APPARENT_POWER), |
| 92 | SensorClass::Aqi => Some(constants::HA_DEVICE_CLASS_SENSOR_AQI), | 90 | SensorClass::Aqi => Some(constants::HA_DEVICE_CLASS_SENSOR_AQI), |
| 93 | SensorClass::AtmosphericPressure => Some(constants::HA_DEVICE_CLASS_SENSOR_ATMOSPHERIC_PRESSURE), | 91 | SensorClass::AtmosphericPressure => { |
| 92 | Some(constants::HA_DEVICE_CLASS_SENSOR_ATMOSPHERIC_PRESSURE) | ||
| 93 | } | ||
| 94 | SensorClass::Battery => Some(constants::HA_DEVICE_CLASS_SENSOR_BATTERY), | 94 | SensorClass::Battery => Some(constants::HA_DEVICE_CLASS_SENSOR_BATTERY), |
| 95 | SensorClass::CarbonDioxide => Some(constants::HA_DEVICE_CLASS_SENSOR_CARBON_DIOXIDE), | 95 | SensorClass::CarbonDioxide => Some(constants::HA_DEVICE_CLASS_SENSOR_CARBON_DIOXIDE), |
| 96 | SensorClass::CarbonMonoxide => Some(constants::HA_DEVICE_CLASS_SENSOR_CARBON_MONOXIDE), | 96 | SensorClass::CarbonMonoxide => Some(constants::HA_DEVICE_CLASS_SENSOR_CARBON_MONOXIDE), |
| @@ -110,8 +110,12 @@ impl SensorClass { | |||
| 110 | SensorClass::Irradiance => Some(constants::HA_DEVICE_CLASS_SENSOR_IRRADIANCE), | 110 | SensorClass::Irradiance => Some(constants::HA_DEVICE_CLASS_SENSOR_IRRADIANCE), |
| 111 | SensorClass::Moisture => Some(constants::HA_DEVICE_CLASS_SENSOR_MOISTURE), | 111 | SensorClass::Moisture => Some(constants::HA_DEVICE_CLASS_SENSOR_MOISTURE), |
| 112 | SensorClass::Monetary => Some(constants::HA_DEVICE_CLASS_SENSOR_MONETARY), | 112 | SensorClass::Monetary => Some(constants::HA_DEVICE_CLASS_SENSOR_MONETARY), |
| 113 | SensorClass::NitrogenDioxide => Some(constants::HA_DEVICE_CLASS_SENSOR_NITROGEN_DIOXIDE), | 113 | SensorClass::NitrogenDioxide => { |
| 114 | SensorClass::NitrogenMonoxide => Some(constants::HA_DEVICE_CLASS_SENSOR_NITROGEN_MONOXIDE), | 114 | Some(constants::HA_DEVICE_CLASS_SENSOR_NITROGEN_DIOXIDE) |
| 115 | } | ||
| 116 | SensorClass::NitrogenMonoxide => { | ||
| 117 | Some(constants::HA_DEVICE_CLASS_SENSOR_NITROGEN_MONOXIDE) | ||
| 118 | } | ||
| 115 | SensorClass::NitrousOxide => Some(constants::HA_DEVICE_CLASS_SENSOR_NITROUS_OXIDE), | 119 | SensorClass::NitrousOxide => Some(constants::HA_DEVICE_CLASS_SENSOR_NITROUS_OXIDE), |
| 116 | SensorClass::Ozone => Some(constants::HA_DEVICE_CLASS_SENSOR_OZONE), | 120 | SensorClass::Ozone => Some(constants::HA_DEVICE_CLASS_SENSOR_OZONE), |
| 117 | SensorClass::Ph => Some(constants::HA_DEVICE_CLASS_SENSOR_PH), | 121 | SensorClass::Ph => Some(constants::HA_DEVICE_CLASS_SENSOR_PH), |
| @@ -121,7 +125,9 @@ impl SensorClass { | |||
| 121 | SensorClass::PowerFactor => Some(constants::HA_DEVICE_CLASS_SENSOR_POWER_FACTOR), | 125 | SensorClass::PowerFactor => Some(constants::HA_DEVICE_CLASS_SENSOR_POWER_FACTOR), |
| 122 | SensorClass::Power => Some(constants::HA_DEVICE_CLASS_SENSOR_POWER), | 126 | SensorClass::Power => Some(constants::HA_DEVICE_CLASS_SENSOR_POWER), |
| 123 | SensorClass::Precipitation => Some(constants::HA_DEVICE_CLASS_SENSOR_PRECIPITATION), | 127 | SensorClass::Precipitation => Some(constants::HA_DEVICE_CLASS_SENSOR_PRECIPITATION), |
| 124 | SensorClass::PrecipitationIntensity => Some(constants::HA_DEVICE_CLASS_SENSOR_PRECIPITATION_INTENSITY), | 128 | SensorClass::PrecipitationIntensity => { |
| 129 | Some(constants::HA_DEVICE_CLASS_SENSOR_PRECIPITATION_INTENSITY) | ||
| 130 | } | ||
| 125 | SensorClass::Pressure => Some(constants::HA_DEVICE_CLASS_SENSOR_PRESSURE), | 131 | SensorClass::Pressure => Some(constants::HA_DEVICE_CLASS_SENSOR_PRESSURE), |
| 126 | SensorClass::ReactivePower => Some(constants::HA_DEVICE_CLASS_SENSOR_REACTIVE_POWER), | 132 | SensorClass::ReactivePower => Some(constants::HA_DEVICE_CLASS_SENSOR_REACTIVE_POWER), |
| 127 | SensorClass::SignalStrength => Some(constants::HA_DEVICE_CLASS_SENSOR_SIGNAL_STRENGTH), | 133 | SensorClass::SignalStrength => Some(constants::HA_DEVICE_CLASS_SENSOR_SIGNAL_STRENGTH), |
| @@ -130,8 +136,12 @@ impl SensorClass { | |||
| 130 | SensorClass::SulphurDioxide => Some(constants::HA_DEVICE_CLASS_SENSOR_SULPHUR_DIOXIDE), | 136 | SensorClass::SulphurDioxide => Some(constants::HA_DEVICE_CLASS_SENSOR_SULPHUR_DIOXIDE), |
| 131 | SensorClass::Temperature => Some(constants::HA_DEVICE_CLASS_SENSOR_TEMPERATURE), | 137 | SensorClass::Temperature => Some(constants::HA_DEVICE_CLASS_SENSOR_TEMPERATURE), |
| 132 | SensorClass::Timestamp => Some(constants::HA_DEVICE_CLASS_SENSOR_TIMESTAMP), | 138 | SensorClass::Timestamp => Some(constants::HA_DEVICE_CLASS_SENSOR_TIMESTAMP), |
| 133 | SensorClass::VolatileOrganicCompounds => Some(constants::HA_DEVICE_CLASS_SENSOR_VOLATILE_ORGANIC_COMPOUNDS), | 139 | SensorClass::VolatileOrganicCompounds => { |
| 134 | SensorClass::VolatileOrganicCompoundsParts => Some(constants::HA_DEVICE_CLASS_SENSOR_VOLATILE_ORGANIC_COMPOUNDS_PARTS), | 140 | Some(constants::HA_DEVICE_CLASS_SENSOR_VOLATILE_ORGANIC_COMPOUNDS) |
| 141 | } | ||
| 142 | SensorClass::VolatileOrganicCompoundsParts => { | ||
| 143 | Some(constants::HA_DEVICE_CLASS_SENSOR_VOLATILE_ORGANIC_COMPOUNDS_PARTS) | ||
| 144 | } | ||
| 135 | SensorClass::Voltage => Some(constants::HA_DEVICE_CLASS_SENSOR_VOLTAGE), | 145 | SensorClass::Voltage => Some(constants::HA_DEVICE_CLASS_SENSOR_VOLTAGE), |
| 136 | SensorClass::Volume => Some(constants::HA_DEVICE_CLASS_SENSOR_VOLUME), | 146 | SensorClass::Volume => Some(constants::HA_DEVICE_CLASS_SENSOR_VOLUME), |
| 137 | SensorClass::VolumeFlowRate => Some(constants::HA_DEVICE_CLASS_SENSOR_VOLUME_FLOW_RATE), | 147 | SensorClass::VolumeFlowRate => Some(constants::HA_DEVICE_CLASS_SENSOR_VOLUME_FLOW_RATE), |
diff --git a/src/entity_switch.rs b/src/entity_switch.rs index 1cb3647..299d299 100644 --- a/src/entity_switch.rs +++ b/src/entity_switch.rs | |||
| @@ -1,4 +1,6 @@ | |||
| 1 | use crate::{BinaryState, Entity, EntityCommonConfig, EntityConfig, SwitchCommand, SwitchState, constants}; | 1 | use crate::{ |
| 2 | BinaryState, Entity, EntityCommonConfig, EntityConfig, SwitchCommand, SwitchState, constants, | ||
| 3 | }; | ||
| 2 | 4 | ||
| 3 | #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] | 5 | #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] |
| 4 | pub enum SwitchClass { | 6 | pub enum SwitchClass { |
| @@ -1,10 +1,14 @@ | |||
| 1 | #![no_std] | 1 | #![no_std] |
| 2 | 2 | ||
| 3 | use core::{cell::RefCell, net::{Ipv4Addr, SocketAddrV4}, task::Waker}; | 3 | use core::{ |
| 4 | cell::RefCell, | ||
| 5 | net::{Ipv4Addr, SocketAddrV4}, | ||
| 6 | task::Waker, | ||
| 7 | }; | ||
| 4 | 8 | ||
| 5 | use embassy_net::tcp::TcpSocket; | 9 | use embassy_net::tcp::TcpSocket; |
| 6 | use embassy_sync::waitqueue::AtomicWaker; | 10 | use embassy_sync::waitqueue::AtomicWaker; |
| 7 | use embassy_time::Timer; | 11 | use embassy_time::{Duration, Timer}; |
| 8 | use heapless::{ | 12 | use heapless::{ |
| 9 | Vec, VecView, | 13 | Vec, VecView, |
| 10 | string::{String, StringView}, | 14 | string::{String, StringView}, |
| @@ -432,7 +436,11 @@ pub fn new<'a>(resources: &'a mut DeviceResources, config: DeviceConfig) -> Devi | |||
| 432 | } | 436 | } |
| 433 | } | 437 | } |
| 434 | 438 | ||
| 435 | fn create_entity<'a>(device: &Device<'a>, config: EntityConfig, storage: EntityStorage) -> Entity<'a> { | 439 | fn create_entity<'a>( |
| 440 | device: &Device<'a>, | ||
| 441 | config: EntityConfig, | ||
| 442 | storage: EntityStorage, | ||
| 443 | ) -> Entity<'a> { | ||
| 436 | let index = 'outer: { | 444 | let index = 'outer: { |
| 437 | for idx in 0..device.entities.len() { | 445 | for idx in 0..device.entities.len() { |
| 438 | if device.entities[idx].borrow().is_none() { | 446 | if device.entities[idx].borrow().is_none() { |
| @@ -457,7 +465,11 @@ fn create_entity<'a>(device: &Device<'a>, config: EntityConfig, storage: EntityS | |||
| 457 | } | 465 | } |
| 458 | } | 466 | } |
| 459 | 467 | ||
| 460 | pub fn create_sensor<'a>(device: &Device<'a>, id: &'static str, config: SensorConfig) -> Sensor<'a> { | 468 | pub fn create_sensor<'a>( |
| 469 | device: &Device<'a>, | ||
| 470 | id: &'static str, | ||
| 471 | config: SensorConfig, | ||
| 472 | ) -> Sensor<'a> { | ||
| 461 | let mut entity_config = EntityConfig::default(); | 473 | let mut entity_config = EntityConfig::default(); |
| 462 | entity_config.id = id; | 474 | entity_config.id = id; |
| 463 | config.populate(&mut entity_config); | 475 | config.populate(&mut entity_config); |
| @@ -470,16 +482,28 @@ pub fn create_sensor<'a>(device: &Device<'a>, id: &'static str, config: SensorCo | |||
| 470 | Sensor::new(entity) | 482 | Sensor::new(entity) |
| 471 | } | 483 | } |
| 472 | 484 | ||
| 473 | pub fn create_button<'a>(device: &Device<'a>, id: &'static str, config: ButtonConfig) -> Button<'a> { | 485 | pub fn create_button<'a>( |
| 486 | device: &Device<'a>, | ||
| 487 | id: &'static str, | ||
| 488 | config: ButtonConfig, | ||
| 489 | ) -> Button<'a> { | ||
| 474 | let mut entity_config = EntityConfig::default(); | 490 | let mut entity_config = EntityConfig::default(); |
| 475 | entity_config.id = id; | 491 | entity_config.id = id; |
| 476 | config.populate(&mut entity_config); | 492 | config.populate(&mut entity_config); |
| 477 | 493 | ||
| 478 | let entity = create_entity(device, entity_config, EntityStorage::Button(Default::default())); | 494 | let entity = create_entity( |
| 495 | device, | ||
| 496 | entity_config, | ||
| 497 | EntityStorage::Button(Default::default()), | ||
| 498 | ); | ||
| 479 | Button::new(entity) | 499 | Button::new(entity) |
| 480 | } | 500 | } |
| 481 | 501 | ||
| 482 | pub fn create_number<'a>(device: &Device<'a>, id: &'static str, config: NumberConfig) -> Number<'a> { | 502 | pub fn create_number<'a>( |
| 503 | device: &Device<'a>, | ||
| 504 | id: &'static str, | ||
| 505 | config: NumberConfig, | ||
| 506 | ) -> Number<'a> { | ||
| 483 | let mut entity_config = EntityConfig::default(); | 507 | let mut entity_config = EntityConfig::default(); |
| 484 | entity_config.id = id; | 508 | entity_config.id = id; |
| 485 | config.populate(&mut entity_config); | 509 | config.populate(&mut entity_config); |
| @@ -495,7 +519,11 @@ pub fn create_number<'a>(device: &Device<'a>, id: &'static str, config: NumberCo | |||
| 495 | Number::new(entity) | 519 | Number::new(entity) |
| 496 | } | 520 | } |
| 497 | 521 | ||
| 498 | pub fn create_switch<'a>(device: &Device<'a>, id: &'static str, config: SwitchConfig) -> Switch<'a> { | 522 | pub fn create_switch<'a>( |
| 523 | device: &Device<'a>, | ||
| 524 | id: &'static str, | ||
| 525 | config: SwitchConfig, | ||
| 526 | ) -> Switch<'a> { | ||
| 499 | let mut entity_config = EntityConfig::default(); | 527 | let mut entity_config = EntityConfig::default(); |
| 500 | entity_config.id = id; | 528 | entity_config.id = id; |
| 501 | config.populate(&mut entity_config); | 529 | config.populate(&mut entity_config); |
| @@ -531,6 +559,8 @@ pub fn create_binary_sensor<'a>( | |||
| 531 | pub async fn run<T: Transport>(device: &mut Device<'_>, transport: &mut T) -> Result<(), Error> { | 559 | pub async fn run<T: Transport>(device: &mut Device<'_>, transport: &mut T) -> Result<(), Error> { |
| 532 | use core::fmt::Write; | 560 | use core::fmt::Write; |
| 533 | 561 | ||
| 562 | const MQTT_TIMEOUT: Duration = Duration::from_secs(30); | ||
| 563 | |||
| 534 | device.availability_topic_buffer.clear(); | 564 | device.availability_topic_buffer.clear(); |
| 535 | write!( | 565 | write!( |
| 536 | device.availability_topic_buffer, | 566 | device.availability_topic_buffer, |
| @@ -549,15 +579,24 @@ pub async fn run<T: Transport>(device: &mut Device<'_>, transport: &mut T) -> Re | |||
| 549 | will_retain: true, | 579 | will_retain: true, |
| 550 | ..Default::default() | 580 | ..Default::default() |
| 551 | }; | 581 | }; |
| 552 | if let Err(err) = client | 582 | match embassy_time::with_timeout( |
| 553 | .connect_with(device.config.device_id, connect_params) | 583 | MQTT_TIMEOUT, |
| 554 | .await | 584 | client.connect_with(device.config.device_id, connect_params), |
| 585 | ) | ||
| 586 | .await | ||
| 555 | { | 587 | { |
| 556 | crate::log::error!( | 588 | Ok(Ok(())) => {} |
| 557 | "mqtt connect failed with: {:?}", | 589 | Ok(Err(err)) => { |
| 558 | crate::log::Debug2Format(&err) | 590 | crate::log::error!( |
| 559 | ); | 591 | "mqtt connect failed with: {:?}", |
| 560 | return Err(Error::new("mqtt connection failed")); | 592 | crate::log::Debug2Format(&err) |
| 593 | ); | ||
| 594 | return Err(Error::new("mqtt connection failed")); | ||
| 595 | } | ||
| 596 | Err(_) => { | ||
| 597 | crate::log::error!("mqtt connect timed out"); | ||
| 598 | return Err(Error::new("mqtt connect timed out")); | ||
| 599 | } | ||
| 561 | } | 600 | } |
| 562 | 601 | ||
| 563 | crate::log::debug!("sending discover messages"); | 602 | crate::log::debug!("sending discover messages"); |
| @@ -635,7 +674,8 @@ pub async fn run<T: Transport>(device: &mut Device<'_>, transport: &mut T) -> Re | |||
| 635 | discovery | 674 | discovery |
| 636 | ); | 675 | ); |
| 637 | 676 | ||
| 638 | device.discovery_buffer | 677 | device |
| 678 | .discovery_buffer | ||
| 639 | .resize(device.discovery_buffer.capacity(), 0) | 679 | .resize(device.discovery_buffer.capacity(), 0) |
| 640 | .unwrap(); | 680 | .unwrap(); |
| 641 | let n = serde_json_core::to_slice(&discovery, &mut device.discovery_buffer) | 681 | let n = serde_json_core::to_slice(&discovery, &mut device.discovery_buffer) |
| @@ -645,48 +685,73 @@ pub async fn run<T: Transport>(device: &mut Device<'_>, transport: &mut T) -> Re | |||
| 645 | 685 | ||
| 646 | let discovery_topic = device.discovery_topic_buffer.as_str(); | 686 | let discovery_topic = device.discovery_topic_buffer.as_str(); |
| 647 | crate::log::debug!("sending discovery to topic '{}'", discovery_topic); | 687 | crate::log::debug!("sending discovery to topic '{}'", discovery_topic); |
| 648 | if let Err(err) = client | 688 | match embassy_time::with_timeout( |
| 649 | .publish(discovery_topic, &device.discovery_buffer) | 689 | MQTT_TIMEOUT, |
| 650 | .await | 690 | client.publish(discovery_topic, &device.discovery_buffer), |
| 691 | ) | ||
| 692 | .await | ||
| 651 | { | 693 | { |
| 652 | crate::log::error!( | 694 | Ok(Ok(_)) => {} |
| 653 | "mqtt discovery publish failed with: {:?}", | 695 | Ok(Err(err)) => { |
| 654 | crate::log::Debug2Format(&err) | 696 | crate::log::error!( |
| 655 | ); | 697 | "mqtt discovery publish failed with: {:?}", |
| 656 | return Err(Error::new("mqtt discovery publish failed")); | 698 | crate::log::Debug2Format(&err) |
| 699 | ); | ||
| 700 | return Err(Error::new("mqtt discovery publish failed")); | ||
| 701 | } | ||
| 702 | Err(_) => { | ||
| 703 | crate::log::error!("mqtt discovery publish timed out"); | ||
| 704 | return Err(Error::new("mqtt discovery publish timed out")); | ||
| 705 | } | ||
| 657 | } | 706 | } |
| 658 | 707 | ||
| 659 | let command_topic = device.command_topic_buffer.as_str(); | 708 | let command_topic = device.command_topic_buffer.as_str(); |
| 660 | crate::log::debug!("subscribing to command topic '{}'", command_topic); | 709 | crate::log::debug!("subscribing to command topic '{}'", command_topic); |
| 661 | if let Err(err) = client.subscribe(command_topic).await { | 710 | match embassy_time::with_timeout(MQTT_TIMEOUT, client.subscribe(command_topic)).await { |
| 662 | crate::log::error!( | 711 | Ok(Ok(_)) => {} |
| 663 | "mqtt subscribe to '{}' failed with: {:?}", | 712 | Ok(Err(err)) => { |
| 664 | command_topic, | 713 | crate::log::error!( |
| 665 | crate::log::Debug2Format(&err) | 714 | "mqtt subscribe to '{}' failed with: {:?}", |
| 666 | ); | 715 | command_topic, |
| 667 | return Err(Error::new( | 716 | crate::log::Debug2Format(&err) |
| 668 | "mqtt subscription to entity command topic failed", | 717 | ); |
| 669 | )); | 718 | return Err(Error::new( |
| 719 | "mqtt subscription to entity command topic failed", | ||
| 720 | )); | ||
| 721 | } | ||
| 722 | Err(_) => { | ||
| 723 | crate::log::error!("mqtt subscribe to '{}' timed out", command_topic); | ||
| 724 | return Err(Error::new("mqtt subscribe timed out")); | ||
| 725 | } | ||
| 670 | } | 726 | } |
| 671 | } | 727 | } |
| 672 | 728 | ||
| 673 | if let Err(err) = client | 729 | match embassy_time::with_timeout( |
| 674 | .publish_with( | 730 | MQTT_TIMEOUT, |
| 675 | availability_topic, | 731 | client.publish_with( |
| 676 | AVAILABLE_PAYLOAD.as_bytes(), | 732 | availability_topic, |
| 677 | embedded_mqtt::PublishParams { | 733 | AVAILABLE_PAYLOAD.as_bytes(), |
| 678 | retain: true, | 734 | embedded_mqtt::PublishParams { |
| 679 | ..Default::default() | 735 | retain: true, |
| 680 | }, | 736 | ..Default::default() |
| 681 | ) | 737 | }, |
| 682 | .await | 738 | ), |
| 683 | { | 739 | ) |
| 740 | .await | ||
| 741 | { | ||
| 742 | Ok(Ok(_)) => {} | ||
| 743 | Ok(Err(err)) => { | ||
| 684 | crate::log::error!( | 744 | crate::log::error!( |
| 685 | "mqtt availability publish failed with: {:?}", | 745 | "mqtt availability publish failed with: {:?}", |
| 686 | crate::log::Debug2Format(&err) | 746 | crate::log::Debug2Format(&err) |
| 687 | ); | 747 | ); |
| 688 | return Err(Error::new("mqtt availability publish failed")); | 748 | return Err(Error::new("mqtt availability publish failed")); |
| 689 | } | 749 | } |
| 750 | Err(_) => { | ||
| 751 | crate::log::error!("mqtt availability publish timed out"); | ||
| 752 | return Err(Error::new("mqtt availability publish timed out")); | ||
| 753 | } | ||
| 754 | } | ||
| 690 | 755 | ||
| 691 | 'outer_loop: loop { | 756 | 'outer_loop: loop { |
| 692 | use core::fmt::Write; | 757 | use core::fmt::Write; |
| @@ -749,7 +814,14 @@ pub async fn run<T: Transport>(device: &mut Device<'_>, transport: &mut T) -> Re | |||
| 749 | } | 814 | } |
| 750 | 815 | ||
| 751 | let state_topic = device.state_topic_buffer.as_str(); | 816 | let state_topic = device.state_topic_buffer.as_str(); |
| 752 | if let Err(err) = client.publish(state_topic, device.publish_buffer).await { | 817 | match embassy_time::with_timeout( |
| 818 | MQTT_TIMEOUT, | ||
| 819 | client.publish(state_topic, device.publish_buffer), | ||
| 820 | ) | ||
| 821 | .await | ||
| 822 | { | ||
| 823 | Ok(Ok(_)) => {} | ||
| 824 | Ok(Err(err)) => { | ||
| 753 | crate::log::error!( | 825 | crate::log::error!( |
| 754 | "mqtt state publish on topic '{}' failed with: {:?}", | 826 | "mqtt state publish on topic '{}' failed with: {:?}", |
| 755 | state_topic, | 827 | state_topic, |
| @@ -757,12 +829,22 @@ pub async fn run<T: Transport>(device: &mut Device<'_>, transport: &mut T) -> Re | |||
| 757 | ); | 829 | ); |
| 758 | return Err(Error::new("mqtt publish failed")); | 830 | return Err(Error::new("mqtt publish failed")); |
| 759 | } | 831 | } |
| 832 | Err(_) => { | ||
| 833 | crate::log::error!("mqtt state publish on topic '{}' timed out", state_topic); | ||
| 834 | return Err(Error::new("mqtt publish timed out")); | ||
| 835 | } | ||
| 760 | } | 836 | } |
| 837 | } | ||
| 761 | 838 | ||
| 762 | let receive = client.receive(); | 839 | let receive = client.receive(); |
| 763 | let waker = wait_on_atomic_waker(device.waker); | 840 | let waker = wait_on_atomic_waker(device.waker); |
| 764 | let publish = match embassy_futures::select::select(receive, waker).await { | 841 | let publish = match embassy_time::with_timeout( |
| 765 | embassy_futures::select::Either::First(packet) => match packet { | 842 | MQTT_TIMEOUT, |
| 843 | embassy_futures::select::select(receive, waker), | ||
| 844 | ) | ||
| 845 | .await | ||
| 846 | { | ||
| 847 | Ok(embassy_futures::select::Either::First(packet)) => match packet { | ||
| 766 | Ok(embedded_mqtt::Packet::Publish(publish)) => publish, | 848 | Ok(embedded_mqtt::Packet::Publish(publish)) => publish, |
| 767 | Err(err) => { | 849 | Err(err) => { |
| 768 | crate::log::error!( | 850 | crate::log::error!( |
| @@ -773,7 +855,11 @@ pub async fn run<T: Transport>(device: &mut Device<'_>, transport: &mut T) -> Re | |||
| 773 | } | 855 | } |
| 774 | _ => continue, | 856 | _ => continue, |
| 775 | }, | 857 | }, |
| 776 | embassy_futures::select::Either::Second(_) => continue, | 858 | Ok(embassy_futures::select::Either::Second(_)) => continue, |
| 859 | Err(_) => { | ||
| 860 | crate::log::error!("mqtt receive timed out"); | ||
| 861 | return Err(Error::new("mqtt receive timed out")); | ||
| 862 | } | ||
| 777 | }; | 863 | }; |
| 778 | 864 | ||
| 779 | let entity = 'entity_search_block: { | 865 | let entity = 'entity_search_block: { |
| @@ -816,12 +902,24 @@ pub async fn run<T: Transport>(device: &mut Device<'_>, transport: &mut T) -> Re | |||
| 816 | ); | 902 | ); |
| 817 | 903 | ||
| 818 | let data_len = publish.data_len; | 904 | let data_len = publish.data_len; |
| 819 | if let Err(err) = client.receive_data(&mut read_buffer[..data_len]).await { | 905 | match embassy_time::with_timeout( |
| 820 | crate::log::error!( | 906 | MQTT_TIMEOUT, |
| 821 | "mqtt receive data failed with: {:?}", | 907 | client.receive_data(&mut read_buffer[..data_len]), |
| 822 | crate::log::Debug2Format(&err) | 908 | ) |
| 823 | ); | 909 | .await |
| 824 | return Err(Error::new("mqtt receive data failed")); | 910 | { |
| 911 | Ok(Ok(())) => {} | ||
| 912 | Ok(Err(err)) => { | ||
| 913 | crate::log::error!( | ||
| 914 | "mqtt receive data failed with: {:?}", | ||
| 915 | crate::log::Debug2Format(&err) | ||
| 916 | ); | ||
| 917 | return Err(Error::new("mqtt receive data failed")); | ||
| 918 | } | ||
| 919 | Err(_) => { | ||
| 920 | crate::log::error!("mqtt receive data timed out"); | ||
| 921 | return Err(Error::new("mqtt receive data timed out")); | ||
| 922 | } | ||
| 825 | } | 923 | } |
| 826 | 924 | ||
| 827 | let command = match str::from_utf8(&read_buffer[..data_len]) { | 925 | let command = match str::from_utf8(&read_buffer[..data_len]) { |
| @@ -990,13 +1088,21 @@ pub async fn connect_and_run( | |||
| 990 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); | 1088 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); |
| 991 | socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); | 1089 | socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); |
| 992 | 1090 | ||
| 993 | if let Err(err) = socket.connect(addr).await { | 1091 | let connect_fut = embassy_time::with_timeout(Duration::from_secs(10), socket.connect(addr)); |
| 994 | crate::log::error!( | 1092 | match connect_fut.await { |
| 995 | "TCP connect to {} failed with: {:?}", | 1093 | Ok(Err(err)) => { |
| 996 | addr, | 1094 | crate::log::error!( |
| 997 | crate::log::Debug2Format(&err) | 1095 | "TCP connect to {} failed with: {:?}", |
| 998 | ); | 1096 | addr, |
| 999 | continue; | 1097 | crate::log::Debug2Format(&err) |
| 1098 | ); | ||
| 1099 | continue; | ||
| 1100 | } | ||
| 1101 | Err(_) => { | ||
| 1102 | crate::log::error!("TCP connect to {} timed out", addr); | ||
| 1103 | continue; | ||
| 1104 | } | ||
| 1105 | _ => {} | ||
| 1000 | } | 1106 | } |
| 1001 | 1107 | ||
| 1002 | socket.set_timeout(None); | 1108 | socket.set_timeout(None); |
| @@ -112,4 +112,4 @@ macro_rules! error { | |||
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | // Re-export the macros at the module level for easier use | 114 | // Re-export the macros at the module level for easier use |
| 115 | pub use crate::{trace, debug, info, warn, error}; | 115 | pub use crate::{debug, error, info, trace, warn}; |
diff --git a/src/unit.rs b/src/unit.rs index e61c867..90eecb4 100644 --- a/src/unit.rs +++ b/src/unit.rs | |||
| @@ -365,7 +365,9 @@ impl NumberUnit { | |||
| 365 | NumberUnit::MeterPerSecond => crate::constants::HA_UNIT_SPEED_METER_PER_SECOND, | 365 | NumberUnit::MeterPerSecond => crate::constants::HA_UNIT_SPEED_METER_PER_SECOND, |
| 366 | NumberUnit::MilePerHour => crate::constants::HA_UNIT_SPEED_MILE_PER_HOUR, | 366 | NumberUnit::MilePerHour => crate::constants::HA_UNIT_SPEED_MILE_PER_HOUR, |
| 367 | NumberUnit::MillimeterPerDay => crate::constants::HA_UNIT_SPEED_MILLIMETER_PER_DAY, | 367 | NumberUnit::MillimeterPerDay => crate::constants::HA_UNIT_SPEED_MILLIMETER_PER_DAY, |
| 368 | NumberUnit::MillimeterPerSecond => crate::constants::HA_UNIT_SPEED_MILLIMETER_PER_SECOND, | 368 | NumberUnit::MillimeterPerSecond => { |
| 369 | crate::constants::HA_UNIT_SPEED_MILLIMETER_PER_SECOND | ||
| 370 | } | ||
| 369 | // Distance | 371 | // Distance |
| 370 | NumberUnit::Kilometer => crate::constants::HA_UNIT_DISTANCE_KILOMETER, | 372 | NumberUnit::Kilometer => crate::constants::HA_UNIT_DISTANCE_KILOMETER, |
| 371 | NumberUnit::Meter => crate::constants::HA_UNIT_DISTANCE_METER, | 373 | NumberUnit::Meter => crate::constants::HA_UNIT_DISTANCE_METER, |
| @@ -397,12 +399,24 @@ impl NumberUnit { | |||
| 397 | NumberUnit::MegaBitPerSecond => crate::constants::HA_UNIT_DATA_RATE_MEGABIT_PER_SECOND, | 399 | NumberUnit::MegaBitPerSecond => crate::constants::HA_UNIT_DATA_RATE_MEGABIT_PER_SECOND, |
| 398 | NumberUnit::GigaBitPerSecond => crate::constants::HA_UNIT_DATA_RATE_GIGABIT_PER_SECOND, | 400 | NumberUnit::GigaBitPerSecond => crate::constants::HA_UNIT_DATA_RATE_GIGABIT_PER_SECOND, |
| 399 | NumberUnit::BytePerSecond => crate::constants::HA_UNIT_DATA_RATE_BYTE_PER_SECOND, | 401 | NumberUnit::BytePerSecond => crate::constants::HA_UNIT_DATA_RATE_BYTE_PER_SECOND, |
| 400 | NumberUnit::KiloBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_KILOBYTE_PER_SECOND, | 402 | NumberUnit::KiloBytePerSecond => { |
| 401 | NumberUnit::MegaBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_MEGABYTE_PER_SECOND, | 403 | crate::constants::HA_UNIT_DATA_RATE_KILOBYTE_PER_SECOND |
| 402 | NumberUnit::GigaBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_GIGABYTE_PER_SECOND, | 404 | } |
| 403 | NumberUnit::KibiBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_KIBIBYTE_PER_SECOND, | 405 | NumberUnit::MegaBytePerSecond => { |
| 404 | NumberUnit::MebiBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_MEBIBYTE_PER_SECOND, | 406 | crate::constants::HA_UNIT_DATA_RATE_MEGABYTE_PER_SECOND |
| 405 | NumberUnit::GibiBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_GIBIBYTE_PER_SECOND, | 407 | } |
| 408 | NumberUnit::GigaBytePerSecond => { | ||
| 409 | crate::constants::HA_UNIT_DATA_RATE_GIGABYTE_PER_SECOND | ||
| 410 | } | ||
| 411 | NumberUnit::KibiBytePerSecond => { | ||
| 412 | crate::constants::HA_UNIT_DATA_RATE_KIBIBYTE_PER_SECOND | ||
| 413 | } | ||
| 414 | NumberUnit::MebiBytePerSecond => { | ||
| 415 | crate::constants::HA_UNIT_DATA_RATE_MEBIBYTE_PER_SECOND | ||
| 416 | } | ||
| 417 | NumberUnit::GibiBytePerSecond => { | ||
| 418 | crate::constants::HA_UNIT_DATA_RATE_GIBIBYTE_PER_SECOND | ||
| 419 | } | ||
| 406 | // Weight | 420 | // Weight |
| 407 | NumberUnit::Kilogram => crate::constants::HA_UNIT_WEIGHT_KILOGRAM, | 421 | NumberUnit::Kilogram => crate::constants::HA_UNIT_WEIGHT_KILOGRAM, |
| 408 | NumberUnit::Gram => crate::constants::HA_UNIT_WEIGHT_GRAM, | 422 | NumberUnit::Gram => crate::constants::HA_UNIT_WEIGHT_GRAM, |
| @@ -631,7 +645,9 @@ impl Unit { | |||
| 631 | Unit::NumberMeterPerSecond => crate::constants::HA_UNIT_SPEED_METER_PER_SECOND, | 645 | Unit::NumberMeterPerSecond => crate::constants::HA_UNIT_SPEED_METER_PER_SECOND, |
| 632 | Unit::NumberMilePerHour => crate::constants::HA_UNIT_SPEED_MILE_PER_HOUR, | 646 | Unit::NumberMilePerHour => crate::constants::HA_UNIT_SPEED_MILE_PER_HOUR, |
| 633 | Unit::NumberMillimeterPerDay => crate::constants::HA_UNIT_SPEED_MILLIMETER_PER_DAY, | 647 | Unit::NumberMillimeterPerDay => crate::constants::HA_UNIT_SPEED_MILLIMETER_PER_DAY, |
| 634 | Unit::NumberMillimeterPerSecond => crate::constants::HA_UNIT_SPEED_MILLIMETER_PER_SECOND, | 648 | Unit::NumberMillimeterPerSecond => { |
| 649 | crate::constants::HA_UNIT_SPEED_MILLIMETER_PER_SECOND | ||
| 650 | } | ||
| 635 | Unit::NumberKilometer => crate::constants::HA_UNIT_DISTANCE_KILOMETER, | 651 | Unit::NumberKilometer => crate::constants::HA_UNIT_DISTANCE_KILOMETER, |
| 636 | Unit::NumberMeter => crate::constants::HA_UNIT_DISTANCE_METER, | 652 | Unit::NumberMeter => crate::constants::HA_UNIT_DISTANCE_METER, |
| 637 | Unit::NumberCentimeter => crate::constants::HA_UNIT_DISTANCE_CENTIMETER, | 653 | Unit::NumberCentimeter => crate::constants::HA_UNIT_DISTANCE_CENTIMETER, |
| @@ -658,12 +674,24 @@ impl Unit { | |||
| 658 | Unit::NumberMegaBitPerSecond => crate::constants::HA_UNIT_DATA_RATE_MEGABIT_PER_SECOND, | 674 | Unit::NumberMegaBitPerSecond => crate::constants::HA_UNIT_DATA_RATE_MEGABIT_PER_SECOND, |
| 659 | Unit::NumberGigaBitPerSecond => crate::constants::HA_UNIT_DATA_RATE_GIGABIT_PER_SECOND, | 675 | Unit::NumberGigaBitPerSecond => crate::constants::HA_UNIT_DATA_RATE_GIGABIT_PER_SECOND, |
| 660 | Unit::NumberBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_BYTE_PER_SECOND, | 676 | Unit::NumberBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_BYTE_PER_SECOND, |
| 661 | Unit::NumberKiloBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_KILOBYTE_PER_SECOND, | 677 | Unit::NumberKiloBytePerSecond => { |
| 662 | Unit::NumberMegaBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_MEGABYTE_PER_SECOND, | 678 | crate::constants::HA_UNIT_DATA_RATE_KILOBYTE_PER_SECOND |
| 663 | Unit::NumberGigaBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_GIGABYTE_PER_SECOND, | 679 | } |
| 664 | Unit::NumberKibiBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_KIBIBYTE_PER_SECOND, | 680 | Unit::NumberMegaBytePerSecond => { |
| 665 | Unit::NumberMebiBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_MEBIBYTE_PER_SECOND, | 681 | crate::constants::HA_UNIT_DATA_RATE_MEGABYTE_PER_SECOND |
| 666 | Unit::NumberGibiBytePerSecond => crate::constants::HA_UNIT_DATA_RATE_GIBIBYTE_PER_SECOND, | 682 | } |
| 683 | Unit::NumberGigaBytePerSecond => { | ||
| 684 | crate::constants::HA_UNIT_DATA_RATE_GIGABYTE_PER_SECOND | ||
| 685 | } | ||
| 686 | Unit::NumberKibiBytePerSecond => { | ||
| 687 | crate::constants::HA_UNIT_DATA_RATE_KIBIBYTE_PER_SECOND | ||
| 688 | } | ||
| 689 | Unit::NumberMebiBytePerSecond => { | ||
| 690 | crate::constants::HA_UNIT_DATA_RATE_MEBIBYTE_PER_SECOND | ||
| 691 | } | ||
| 692 | Unit::NumberGibiBytePerSecond => { | ||
| 693 | crate::constants::HA_UNIT_DATA_RATE_GIBIBYTE_PER_SECOND | ||
| 694 | } | ||
| 667 | Unit::NumberKilogram => crate::constants::HA_UNIT_WEIGHT_KILOGRAM, | 695 | Unit::NumberKilogram => crate::constants::HA_UNIT_WEIGHT_KILOGRAM, |
| 668 | Unit::NumberGram => crate::constants::HA_UNIT_WEIGHT_GRAM, | 696 | Unit::NumberGram => crate::constants::HA_UNIT_WEIGHT_GRAM, |
| 669 | Unit::NumberMilligram => crate::constants::HA_UNIT_WEIGHT_MILLIGRAM, | 697 | Unit::NumberMilligram => crate::constants::HA_UNIT_WEIGHT_MILLIGRAM, |
