aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/binary_sensor.rs44
-rw-r--r--src/constants.rs3
-rw-r--r--src/lib.rs110
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 @@
1mod common;
2
3use common::AsyncTcp;
4use embassy_executor::{Executor, Spawner};
5use embassy_time::Timer;
6use static_cell::StaticCell;
7
8static RESOURCES: StaticCell<embassy_ha::DeviceResources> = StaticCell::new();
9
10#[embassy_executor::task]
11async 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]
36async 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
44example_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
130pub const HA_SWITCH_STATE_ON: &str = "ON"; 130pub const HA_SWITCH_STATE_ON: &str = "ON";
131pub const HA_SWITCH_STATE_OFF: &str = "OFF"; 131pub const HA_SWITCH_STATE_OFF: &str = "OFF";
132
133pub const HA_BINARY_SENSOR_STATE_ON: &str = "ON";
134pub const HA_BINARY_SENSOR_STATE_OFF: &str = "OFF";
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 {
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
218impl core::fmt::Display for SwitchState { 225impl 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
282pub struct InvalidBinarySensorState;
283
284#[derive(Debug, Clone, Copy, PartialEq, Eq)]
285pub enum BinarySensorState {
286 On,
287 Off,
288}
289
290impl 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
306impl 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
312impl 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
326impl 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
335pub struct BinarySensor<'a>(Entity<'a>);
336
337impl<'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)]
286pub struct EntityConfig { 356pub 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;