From abdcb51d7e9d6ebfacdf17b32e5296464e0aa2d4 Mon Sep 17 00:00:00 2001 From: diogo464 Date: Thu, 4 Dec 2025 21:14:27 +0000 Subject: added switch example --- src/constants.rs | 3 ++ src/lib.rs | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/constants.rs b/src/constants.rs index 44ba09e..6159e3d 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -126,3 +126,6 @@ pub const HA_UNIT_DISTANCE_KILOMETER: &str = "km"; pub const HA_ENTITY_CATEGORY_CONFIG: &str = "config"; pub const HA_ENTITY_CATEGORY_DIAGNOSTIC: &str = "diagnostic"; + +pub const HA_SWITCH_STATE_ON: &str = "ON"; +pub const HA_SWITCH_STATE_OFF: &str = "OFF"; diff --git a/src/lib.rs b/src/lib.rs index 1f9d2d5..d954883 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -use core::{cell::RefCell, task::Waker}; +use core::{cell::RefCell, str::FromStr, task::Waker}; use defmt::Format; use embassy_sync::waitqueue::AtomicWaker; @@ -198,6 +198,90 @@ impl<'a> Number<'a> { } } +pub struct InvalidSwitchState; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SwitchState { + On, + Off, +} + +impl SwitchState { + pub fn as_str(&self) -> &'static str { + match self { + Self::On => constants::HA_SWITCH_STATE_ON, + Self::Off => constants::HA_SWITCH_STATE_OFF, + } + } +} + +impl core::fmt::Display for SwitchState { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(self.as_str()) + } +} + +impl FromStr for SwitchState { + type Err = InvalidSwitchState; + + fn from_str(s: &str) -> Result { + if s.eq_ignore_ascii_case(constants::HA_SWITCH_STATE_ON) { + return Ok(Self::On); + } + if s.eq_ignore_ascii_case(constants::HA_SWITCH_STATE_OFF) { + return Ok(Self::Off); + } + Err(InvalidSwitchState) + } +} + +impl TryFrom<&[u8]> for SwitchState { + type Error = InvalidSwitchState; + + fn try_from(value: &[u8]) -> Result { + let string = str::from_utf8(value).map_err(|_| InvalidSwitchState)?; + string.parse() + } +} + +pub struct Switch<'a>(Entity<'a>); + +impl<'a> Switch<'a> { + pub fn state(&self) -> Option { + self.0 + .with_data(|data| SwitchState::try_from(data.command_value.as_slice()).ok()) + } + + pub fn toggle(&mut self) -> SwitchState { + let curr_state = self.state().unwrap_or(SwitchState::Off); + let new_state = match curr_state { + SwitchState::On => SwitchState::Off, + SwitchState::Off => SwitchState::On, + }; + self.set(new_state); + new_state + } + + pub fn set(&mut self, state: SwitchState) { + self.0.publish( + match state { + SwitchState::On => constants::HA_SWITCH_STATE_ON, + SwitchState::Off => constants::HA_SWITCH_STATE_OFF, + } + .as_bytes(), + ); + } + + pub async fn wait(&mut self) -> SwitchState { + loop { + self.0.wait_command().await; + if let Some(state) = self.state() { + return state; + } + } + } +} + #[derive(Default)] pub struct EntityConfig { pub id: &'static str, @@ -393,6 +477,16 @@ impl<'a> Device<'a> { Number(entity) } + pub fn create_switch(&self, id: &'static str, name: &'static str) -> Switch<'a> { + let entity = self.create_entity(EntityConfig { + id, + name, + domain: constants::HA_DOMAIN_SWITCH, + ..Default::default() + }); + Switch(entity) + } + pub async fn run(&mut self, transport: &mut T) -> ! { loop { self.run_iteration(&mut *transport).await; -- cgit