diff options
| author | diogo464 <[email protected]> | 2025-12-04 23:59:21 +0000 |
|---|---|---|
| committer | diogo464 <[email protected]> | 2025-12-04 23:59:21 +0000 |
| commit | 40a16d099c2bf2b3e5bf537aa14d37fdf9e52668 (patch) | |
| tree | fae2ec76ca797e1e55d678cabea743c91d30de5c | |
| parent | abdcb51d7e9d6ebfacdf17b32e5296464e0aa2d4 (diff) | |
added basic binary sensor example
| -rw-r--r-- | examples/binary_sensor.rs | 44 | ||||
| -rw-r--r-- | src/constants.rs | 3 | ||||
| -rw-r--r-- | src/lib.rs | 110 |
3 files changed, 145 insertions, 12 deletions
diff --git a/examples/binary_sensor.rs b/examples/binary_sensor.rs new file mode 100644 index 0000000..2809255 --- /dev/null +++ b/examples/binary_sensor.rs | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | mod common; | ||
| 2 | |||
| 3 | use common::AsyncTcp; | ||
| 4 | use embassy_executor::{Executor, Spawner}; | ||
| 5 | use embassy_time::Timer; | ||
| 6 | use static_cell::StaticCell; | ||
| 7 | |||
| 8 | static RESOURCES: StaticCell<embassy_ha::DeviceResources> = StaticCell::new(); | ||
| 9 | |||
| 10 | #[embassy_executor::task] | ||
| 11 | async fn main_task(spawner: Spawner) { | ||
| 12 | let mut stream = AsyncTcp::connect(std::env!("MQTT_ADDRESS")); | ||
| 13 | |||
| 14 | let mut device = embassy_ha::Device::new( | ||
| 15 | RESOURCES.init(Default::default()), | ||
| 16 | embassy_ha::DeviceConfig { | ||
| 17 | device_id: "example-device-id", | ||
| 18 | device_name: "Example Device Name", | ||
| 19 | manufacturer: "Example Device Manufacturer", | ||
| 20 | model: "Example Device Model", | ||
| 21 | }, | ||
| 22 | ); | ||
| 23 | |||
| 24 | let sensor = device.create_binary_sensor( | ||
| 25 | "binary-sensor-id", | ||
| 26 | "Binary Sensor", | ||
| 27 | embassy_ha::constants::HA_DEVICE_CLASS_BINARY_SENSOR_SMOKE, | ||
| 28 | ); | ||
| 29 | |||
| 30 | spawner.must_spawn(binary_sensor_class(sensor)); | ||
| 31 | |||
| 32 | device.run(&mut stream).await; | ||
| 33 | } | ||
| 34 | |||
| 35 | #[embassy_executor::task] | ||
| 36 | async fn binary_sensor_class(mut switch: embassy_ha::BinarySensor<'static>) { | ||
| 37 | loop { | ||
| 38 | let state = switch.toggle(); | ||
| 39 | println!("state = {}", state); | ||
| 40 | Timer::after_secs(2).await; | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | example_main!(); | ||
diff --git a/src/constants.rs b/src/constants.rs index 6159e3d..b05d94c 100644 --- a/src/constants.rs +++ b/src/constants.rs | |||
| @@ -129,3 +129,6 @@ pub const HA_ENTITY_CATEGORY_DIAGNOSTIC: &str = "diagnostic"; | |||
| 129 | 129 | ||
| 130 | pub const HA_SWITCH_STATE_ON: &str = "ON"; | 130 | pub const HA_SWITCH_STATE_ON: &str = "ON"; |
| 131 | pub const HA_SWITCH_STATE_OFF: &str = "OFF"; | 131 | pub const HA_SWITCH_STATE_OFF: &str = "OFF"; |
| 132 | |||
| 133 | pub const HA_BINARY_SENSOR_STATE_ON: &str = "ON"; | ||
| 134 | pub const HA_BINARY_SENSOR_STATE_OFF: &str = "OFF"; | ||
| @@ -213,6 +213,13 @@ impl SwitchState { | |||
| 213 | Self::Off => constants::HA_SWITCH_STATE_OFF, | 213 | Self::Off => constants::HA_SWITCH_STATE_OFF, |
| 214 | } | 214 | } |
| 215 | } | 215 | } |
| 216 | |||
| 217 | pub fn flip(self) -> Self { | ||
| 218 | match self { | ||
| 219 | Self::On => Self::Off, | ||
| 220 | Self::Off => Self::On, | ||
| 221 | } | ||
| 222 | } | ||
| 216 | } | 223 | } |
| 217 | 224 | ||
| 218 | impl core::fmt::Display for SwitchState { | 225 | impl core::fmt::Display for SwitchState { |
| @@ -253,23 +260,13 @@ impl<'a> Switch<'a> { | |||
| 253 | } | 260 | } |
| 254 | 261 | ||
| 255 | pub fn toggle(&mut self) -> SwitchState { | 262 | pub fn toggle(&mut self) -> SwitchState { |
| 256 | let curr_state = self.state().unwrap_or(SwitchState::Off); | 263 | let new_state = self.state().unwrap_or(SwitchState::Off).flip(); |
| 257 | let new_state = match curr_state { | ||
| 258 | SwitchState::On => SwitchState::Off, | ||
| 259 | SwitchState::Off => SwitchState::On, | ||
| 260 | }; | ||
| 261 | self.set(new_state); | 264 | self.set(new_state); |
| 262 | new_state | 265 | new_state |
| 263 | } | 266 | } |
| 264 | 267 | ||
| 265 | pub fn set(&mut self, state: SwitchState) { | 268 | pub fn set(&mut self, state: SwitchState) { |
| 266 | self.0.publish( | 269 | self.0.publish(state.as_str().as_bytes()); |
| 267 | match state { | ||
| 268 | SwitchState::On => constants::HA_SWITCH_STATE_ON, | ||
| 269 | SwitchState::Off => constants::HA_SWITCH_STATE_OFF, | ||
| 270 | } | ||
| 271 | .as_bytes(), | ||
| 272 | ); | ||
| 273 | } | 270 | } |
| 274 | 271 | ||
| 275 | pub async fn wait(&mut self) -> SwitchState { | 272 | pub async fn wait(&mut self) -> SwitchState { |
| @@ -282,6 +279,79 @@ impl<'a> Switch<'a> { | |||
| 282 | } | 279 | } |
| 283 | } | 280 | } |
| 284 | 281 | ||
| 282 | pub struct InvalidBinarySensorState; | ||
| 283 | |||
| 284 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 285 | pub enum BinarySensorState { | ||
| 286 | On, | ||
| 287 | Off, | ||
| 288 | } | ||
| 289 | |||
| 290 | impl BinarySensorState { | ||
| 291 | pub fn as_str(&self) -> &'static str { | ||
| 292 | match self { | ||
| 293 | Self::On => constants::HA_BINARY_SENSOR_STATE_ON, | ||
| 294 | Self::Off => constants::HA_BINARY_SENSOR_STATE_OFF, | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | pub fn flip(self) -> Self { | ||
| 299 | match self { | ||
| 300 | Self::On => Self::Off, | ||
| 301 | Self::Off => Self::On, | ||
| 302 | } | ||
| 303 | } | ||
| 304 | } | ||
| 305 | |||
| 306 | impl core::fmt::Display for BinarySensorState { | ||
| 307 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
| 308 | f.write_str(self.as_str()) | ||
| 309 | } | ||
| 310 | } | ||
| 311 | |||
| 312 | impl FromStr for BinarySensorState { | ||
| 313 | type Err = InvalidBinarySensorState; | ||
| 314 | |||
| 315 | fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
| 316 | if s.eq_ignore_ascii_case(constants::HA_BINARY_SENSOR_STATE_ON) { | ||
| 317 | return Ok(Self::On); | ||
| 318 | } | ||
| 319 | if s.eq_ignore_ascii_case(constants::HA_BINARY_SENSOR_STATE_OFF) { | ||
| 320 | return Ok(Self::Off); | ||
| 321 | } | ||
| 322 | Err(InvalidBinarySensorState) | ||
| 323 | } | ||
| 324 | } | ||
| 325 | |||
| 326 | impl TryFrom<&[u8]> for BinarySensorState { | ||
| 327 | type Error = InvalidBinarySensorState; | ||
| 328 | |||
| 329 | fn try_from(value: &[u8]) -> Result<Self, Self::Error> { | ||
| 330 | let string = str::from_utf8(value).map_err(|_| InvalidBinarySensorState)?; | ||
| 331 | string.parse() | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | pub struct BinarySensor<'a>(Entity<'a>); | ||
| 336 | |||
| 337 | impl<'a> BinarySensor<'a> { | ||
| 338 | pub fn set(&mut self, state: BinarySensorState) { | ||
| 339 | self.0.publish(state.as_str().as_bytes()); | ||
| 340 | } | ||
| 341 | |||
| 342 | pub fn value(&self) -> Option<BinarySensorState> { | ||
| 343 | self.0 | ||
| 344 | .with_data(|data| BinarySensorState::try_from(data.publish_value.as_slice())) | ||
| 345 | .ok() | ||
| 346 | } | ||
| 347 | |||
| 348 | pub fn toggle(&mut self) -> BinarySensorState { | ||
| 349 | let new_state = self.value().unwrap_or(BinarySensorState::Off).flip(); | ||
| 350 | self.set(new_state); | ||
| 351 | new_state | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 285 | #[derive(Default)] | 355 | #[derive(Default)] |
| 286 | pub struct EntityConfig { | 356 | pub struct EntityConfig { |
| 287 | pub id: &'static str, | 357 | pub id: &'static str, |
| @@ -487,6 +557,22 @@ impl<'a> Device<'a> { | |||
| 487 | Switch(entity) | 557 | Switch(entity) |
| 488 | } | 558 | } |
| 489 | 559 | ||
| 560 | pub fn create_binary_sensor( | ||
| 561 | &self, | ||
| 562 | id: &'static str, | ||
| 563 | name: &'static str, | ||
| 564 | class: &'static str, | ||
| 565 | ) -> BinarySensor<'a> { | ||
| 566 | let entity = self.create_entity(EntityConfig { | ||
| 567 | id, | ||
| 568 | name, | ||
| 569 | domain: constants::HA_DOMAIN_BINARY_SENSOR, | ||
| 570 | device_class: Some(class), | ||
| 571 | ..Default::default() | ||
| 572 | }); | ||
| 573 | BinarySensor(entity) | ||
| 574 | } | ||
| 575 | |||
| 490 | pub async fn run<T: Transport>(&mut self, transport: &mut T) -> ! { | 576 | pub async fn run<T: Transport>(&mut self, transport: &mut T) -> ! { |
| 491 | loop { | 577 | loop { |
| 492 | self.run_iteration(&mut *transport).await; | 578 | self.run_iteration(&mut *transport).await; |
