From 849c579d16c21f5cafd9867ae751944eae078800 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Thu, 25 Apr 2024 05:38:21 +0200 Subject: [PATCH] Use helper types to process config input into the right type --- src/devices/contact_sensor.rs | 51 +++++++++++++++++------------------ src/devices/light_sensor.rs | 11 ++++---- src/devices/washer.rs | 10 +++---- src/helper.rs | 18 +++++++++++++ 4 files changed, 52 insertions(+), 38 deletions(-) diff --git a/src/devices/contact_sensor.rs b/src/devices/contact_sensor.rs index 3fc0e99..0566dae 100644 --- a/src/devices/contact_sensor.rs +++ b/src/devices/contact_sensor.rs @@ -3,6 +3,7 @@ use std::time::Duration; use async_trait::async_trait; use automation_macro::{LuaDevice, LuaDeviceConfig}; use google_home::traits::OnOff; +use mlua::FromLua; use tokio::task::JoinHandle; use tracing::{debug, error, trace, warn}; @@ -26,10 +27,25 @@ pub struct PresenceDeviceConfig { pub timeout: Duration, } +#[derive(Debug, Clone)] +struct TriggerDevicesHelper(Vec); + +impl<'lua> FromLua<'lua> for TriggerDevicesHelper { + fn from_lua(value: mlua::Value<'lua>, lua: &'lua mlua::Lua) -> mlua::Result { + Ok(TriggerDevicesHelper(mlua::FromLua::from_lua(value, lua)?)) + } +} + +impl From for Vec<(WrappedDevice, bool)> { + fn from(value: TriggerDevicesHelper) -> Self { + value.0.into_iter().map(|device| (device, false)).collect() + } +} + #[derive(Debug, Clone, LuaDeviceConfig)] pub struct TriggerConfig { - #[device_config(user_data)] - devices: Vec, + #[device_config(user_data, with = "TriggerDevicesHelper")] + devices: Vec<(WrappedDevice, bool)>, #[device_config(with = "Option")] pub timeout: Option, } @@ -51,30 +67,20 @@ impl DeviceConfig for ContactSensorConfig { async fn create(&self, identifier: &str) -> Result, DeviceConfigError> { trace!(id = identifier, "Setting up ContactSensor"); - let trigger = if let Some(trigger_config) = &self.trigger { - let mut devices = Vec::new(); - for device in &trigger_config.devices { + // Make sure the devices implement the required traits + if let Some(trigger) = &self.trigger { + for (device, _) in &trigger.devices { let id = device.read().await.get_id().to_owned(); if !As::::is(device.read().await.as_ref()) { return Err(DeviceConfigError::MissingTrait(id, "OnOff".into())); } - if trigger_config.timeout.is_none() - && !As::::is(device.read().await.as_ref()) + if trigger.timeout.is_none() && !As::::is(device.read().await.as_ref()) { return Err(DeviceConfigError::MissingTrait(id, "Timeout".into())); } - - devices.push((device.clone(), false)); } - - Some(Trigger { - devices, - timeout: trigger_config.timeout, - }) - } else { - None - }; + } let device = ContactSensor { identifier: identifier.into(), @@ -82,19 +88,12 @@ impl DeviceConfig for ContactSensorConfig { overall_presence: DEFAULT_PRESENCE, is_closed: true, handle: None, - trigger, }; Ok(Box::new(device)) } } -#[derive(Debug)] -struct Trigger { - devices: Vec<(WrappedDevice, bool)>, - timeout: Option, -} - #[derive(Debug, LuaDevice)] pub struct ContactSensor { identifier: String, @@ -104,8 +103,6 @@ pub struct ContactSensor { overall_presence: bool, is_closed: bool, handle: Option>, - - trigger: Option, } impl Device for ContactSensor { @@ -143,7 +140,7 @@ impl OnMqtt for ContactSensor { debug!(id = self.identifier, "Updating state to {is_closed}"); self.is_closed = is_closed; - if let Some(trigger) = &mut self.trigger { + if let Some(trigger) = &mut self.config.trigger { if !self.is_closed { for (light, _) in &mut trigger.devices { let mut light = light.write().await; diff --git a/src/devices/light_sensor.rs b/src/devices/light_sensor.rs index 6f060ce..23ce9a1 100644 --- a/src/devices/light_sensor.rs +++ b/src/devices/light_sensor.rs @@ -7,7 +7,8 @@ use crate::config::MqttDeviceConfig; use crate::device_manager::DeviceConfig; use crate::devices::Device; use crate::error::DeviceConfigError; -use crate::event::{self, Event, EventChannel, OnMqtt}; +use crate::event::{self, Event, OnMqtt}; +use crate::helper::TxHelper; use crate::messages::BrightnessMessage; #[derive(Debug, Clone, LuaDeviceConfig)] @@ -16,8 +17,8 @@ pub struct LightSensorConfig { pub mqtt: MqttDeviceConfig, pub min: isize, pub max: isize, - #[device_config(user_data)] - pub event_channel: EventChannel, + #[device_config(rename = "event_channel", user_data, with = "TxHelper")] + pub tx: event::Sender, } pub const DEFAULT: bool = false; @@ -30,7 +31,6 @@ impl DeviceConfig for LightSensorConfig { let device = LightSensor { identifier: identifier.into(), // Add helper type that does this conversion for us - tx: self.event_channel.get_tx(), config: self.clone(), is_dark: DEFAULT, }; @@ -45,7 +45,6 @@ pub struct LightSensor { #[config] config: LightSensorConfig, - tx: event::Sender, is_dark: bool, } @@ -91,7 +90,7 @@ impl OnMqtt for LightSensor { debug!("Dark state has changed: {is_dark}"); self.is_dark = is_dark; - if self.tx.send(Event::Darkness(is_dark)).await.is_err() { + if self.config.tx.send(Event::Darkness(is_dark)).await.is_err() { warn!("There are no receivers on the event channel"); } } diff --git a/src/devices/washer.rs b/src/devices/washer.rs index fdff148..67fae95 100644 --- a/src/devices/washer.rs +++ b/src/devices/washer.rs @@ -8,7 +8,8 @@ use super::{Device, Notification}; use crate::config::MqttDeviceConfig; use crate::device_manager::DeviceConfig; use crate::error::DeviceConfigError; -use crate::event::{Event, EventChannel, OnMqtt}; +use crate::event::{self, Event, OnMqtt}; +use crate::helper::TxHelper; use crate::messages::PowerMessage; #[derive(Debug, Clone, LuaDeviceConfig)] @@ -17,8 +18,8 @@ pub struct WasherConfig { mqtt: MqttDeviceConfig, // Power in Watt threshold: f32, - #[device_config(user_data)] - event_channel: EventChannel, + #[device_config(rename = "event_channel", user_data, with = "TxHelper")] + pub tx: event::Sender, } #[async_trait] @@ -91,8 +92,7 @@ impl OnMqtt for Washer { if self .config - .event_channel - .get_tx() + .tx .send(Event::Ntfy(notification)) .await .is_err() diff --git a/src/helper.rs b/src/helper.rs index 6879739..0c8537c 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -1,8 +1,11 @@ use std::net::{Ipv4Addr, SocketAddr}; use std::time::Duration; +use mlua::FromLua; use serde::Deserialize; +use crate::event::{self, EventChannel}; + #[derive(Debug, Deserialize)] pub struct DurationSeconds(u64); @@ -20,3 +23,18 @@ impl From> for SocketAddr { Self::from((ip.0, PORT)) } } + +#[derive(Debug, Clone)] +pub struct TxHelper(EventChannel); + +impl<'lua> FromLua<'lua> for TxHelper { + fn from_lua(value: mlua::Value<'lua>, lua: &'lua mlua::Lua) -> mlua::Result { + Ok(TxHelper(mlua::FromLua::from_lua(value, lua)?)) + } +} + +impl From for event::Sender { + fn from(value: TxHelper) -> Self { + value.0.get_tx() + } +}