From 40a16d099c2bf2b3e5bf537aa14d37fdf9e52668 Mon Sep 17 00:00:00 2001 From: diogo464 Date: Thu, 4 Dec 2025 23:59:21 +0000 Subject: added basic binary sensor example --- src/lib.rs | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 98 insertions(+), 12 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index d954883..408dbb9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -213,6 +213,13 @@ impl SwitchState { Self::Off => constants::HA_SWITCH_STATE_OFF, } } + + pub fn flip(self) -> Self { + match self { + Self::On => Self::Off, + Self::Off => Self::On, + } + } } impl core::fmt::Display for SwitchState { @@ -253,23 +260,13 @@ impl<'a> Switch<'a> { } 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, - }; + let new_state = self.state().unwrap_or(SwitchState::Off).flip(); 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(), - ); + self.0.publish(state.as_str().as_bytes()); } pub async fn wait(&mut self) -> SwitchState { @@ -282,6 +279,79 @@ impl<'a> Switch<'a> { } } +pub struct InvalidBinarySensorState; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum BinarySensorState { + On, + Off, +} + +impl BinarySensorState { + pub fn as_str(&self) -> &'static str { + match self { + Self::On => constants::HA_BINARY_SENSOR_STATE_ON, + Self::Off => constants::HA_BINARY_SENSOR_STATE_OFF, + } + } + + pub fn flip(self) -> Self { + match self { + Self::On => Self::Off, + Self::Off => Self::On, + } + } +} + +impl core::fmt::Display for BinarySensorState { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(self.as_str()) + } +} + +impl FromStr for BinarySensorState { + type Err = InvalidBinarySensorState; + + fn from_str(s: &str) -> Result { + if s.eq_ignore_ascii_case(constants::HA_BINARY_SENSOR_STATE_ON) { + return Ok(Self::On); + } + if s.eq_ignore_ascii_case(constants::HA_BINARY_SENSOR_STATE_OFF) { + return Ok(Self::Off); + } + Err(InvalidBinarySensorState) + } +} + +impl TryFrom<&[u8]> for BinarySensorState { + type Error = InvalidBinarySensorState; + + fn try_from(value: &[u8]) -> Result { + let string = str::from_utf8(value).map_err(|_| InvalidBinarySensorState)?; + string.parse() + } +} + +pub struct BinarySensor<'a>(Entity<'a>); + +impl<'a> BinarySensor<'a> { + pub fn set(&mut self, state: BinarySensorState) { + self.0.publish(state.as_str().as_bytes()); + } + + pub fn value(&self) -> Option { + self.0 + .with_data(|data| BinarySensorState::try_from(data.publish_value.as_slice())) + .ok() + } + + pub fn toggle(&mut self) -> BinarySensorState { + let new_state = self.value().unwrap_or(BinarySensorState::Off).flip(); + self.set(new_state); + new_state + } +} + #[derive(Default)] pub struct EntityConfig { pub id: &'static str, @@ -487,6 +557,22 @@ impl<'a> Device<'a> { Switch(entity) } + pub fn create_binary_sensor( + &self, + id: &'static str, + name: &'static str, + class: &'static str, + ) -> BinarySensor<'a> { + let entity = self.create_entity(EntityConfig { + id, + name, + domain: constants::HA_DOMAIN_BINARY_SENSOR, + device_class: Some(class), + ..Default::default() + }); + BinarySensor(entity) + } + pub async fn run(&mut self, transport: &mut T) -> ! { loop { self.run_iteration(&mut *transport).await; -- cgit