Use helper types to process config input into the right type
This commit is contained in:
parent
92b7a2830a
commit
4273a25acd
|
@ -3,6 +3,7 @@ use std::time::Duration;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use automation_macro::{LuaDevice, LuaDeviceConfig};
|
use automation_macro::{LuaDevice, LuaDeviceConfig};
|
||||||
use google_home::traits::OnOff;
|
use google_home::traits::OnOff;
|
||||||
|
use mlua::FromLua;
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
use tracing::{debug, error, trace, warn};
|
use tracing::{debug, error, trace, warn};
|
||||||
|
|
||||||
|
@ -26,10 +27,25 @@ pub struct PresenceDeviceConfig {
|
||||||
pub timeout: Duration,
|
pub timeout: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct TriggerDevicesHelper(Vec<WrappedDevice>);
|
||||||
|
|
||||||
|
impl<'lua> FromLua<'lua> for TriggerDevicesHelper {
|
||||||
|
fn from_lua(value: mlua::Value<'lua>, lua: &'lua mlua::Lua) -> mlua::Result<Self> {
|
||||||
|
Ok(TriggerDevicesHelper(mlua::FromLua::from_lua(value, lua)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TriggerDevicesHelper> for Vec<(WrappedDevice, bool)> {
|
||||||
|
fn from(value: TriggerDevicesHelper) -> Self {
|
||||||
|
value.0.into_iter().map(|device| (device, false)).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, LuaDeviceConfig)]
|
#[derive(Debug, Clone, LuaDeviceConfig)]
|
||||||
pub struct TriggerConfig {
|
pub struct TriggerConfig {
|
||||||
#[device_config(user_data)]
|
#[device_config(user_data, with = "TriggerDevicesHelper")]
|
||||||
devices: Vec<WrappedDevice>,
|
devices: Vec<(WrappedDevice, bool)>,
|
||||||
#[device_config(with = "Option<DurationSeconds>")]
|
#[device_config(with = "Option<DurationSeconds>")]
|
||||||
pub timeout: Option<Duration>,
|
pub timeout: Option<Duration>,
|
||||||
}
|
}
|
||||||
|
@ -51,9 +67,9 @@ impl DeviceConfig for ContactSensorConfig {
|
||||||
async fn create(&self, identifier: &str) -> Result<Box<dyn Device>, DeviceConfigError> {
|
async fn create(&self, identifier: &str) -> Result<Box<dyn Device>, DeviceConfigError> {
|
||||||
trace!(id = identifier, "Setting up ContactSensor");
|
trace!(id = identifier, "Setting up ContactSensor");
|
||||||
|
|
||||||
let trigger = if let Some(trigger_config) = &self.trigger {
|
// Make sure the devices implement the required traits
|
||||||
let mut devices = Vec::new();
|
if let Some(trigger) = &self.trigger {
|
||||||
for device in &trigger_config.devices {
|
for (device, _) in &trigger.devices {
|
||||||
{
|
{
|
||||||
let device = device.read().await;
|
let device = device.read().await;
|
||||||
let id = device.get_id().to_owned();
|
let id = device.get_id().to_owned();
|
||||||
|
@ -61,23 +77,14 @@ impl DeviceConfig for ContactSensorConfig {
|
||||||
return Err(DeviceConfigError::MissingTrait(id, "OnOff".into()));
|
return Err(DeviceConfigError::MissingTrait(id, "OnOff".into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if trigger_config.timeout.is_none()
|
if trigger.timeout.is_none()
|
||||||
&& (device.as_ref().cast() as Option<&dyn Timeout>).is_none()
|
&& (device.as_ref().cast() as Option<&dyn Timeout>).is_none()
|
||||||
{
|
{
|
||||||
return Err(DeviceConfigError::MissingTrait(id, "Timeout".into()));
|
return Err(DeviceConfigError::MissingTrait(id, "Timeout".into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
devices.push((device.clone(), false));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Some(Trigger {
|
|
||||||
devices,
|
|
||||||
timeout: trigger_config.timeout,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let device = ContactSensor {
|
let device = ContactSensor {
|
||||||
identifier: identifier.into(),
|
identifier: identifier.into(),
|
||||||
|
@ -85,19 +92,12 @@ impl DeviceConfig for ContactSensorConfig {
|
||||||
overall_presence: DEFAULT_PRESENCE,
|
overall_presence: DEFAULT_PRESENCE,
|
||||||
is_closed: true,
|
is_closed: true,
|
||||||
handle: None,
|
handle: None,
|
||||||
trigger,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Box::new(device))
|
Ok(Box::new(device))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Trigger {
|
|
||||||
devices: Vec<(WrappedDevice, bool)>,
|
|
||||||
timeout: Option<Duration>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, LuaDevice)]
|
#[derive(Debug, LuaDevice)]
|
||||||
pub struct ContactSensor {
|
pub struct ContactSensor {
|
||||||
identifier: String,
|
identifier: String,
|
||||||
|
@ -107,8 +107,6 @@ pub struct ContactSensor {
|
||||||
overall_presence: bool,
|
overall_presence: bool,
|
||||||
is_closed: bool,
|
is_closed: bool,
|
||||||
handle: Option<JoinHandle<()>>,
|
handle: Option<JoinHandle<()>>,
|
||||||
|
|
||||||
trigger: Option<Trigger>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device for ContactSensor {
|
impl Device for ContactSensor {
|
||||||
|
@ -146,7 +144,7 @@ impl OnMqtt for ContactSensor {
|
||||||
debug!(id = self.identifier, "Updating state to {is_closed}");
|
debug!(id = self.identifier, "Updating state to {is_closed}");
|
||||||
self.is_closed = 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 {
|
if !self.is_closed {
|
||||||
for (light, previous) in &mut trigger.devices {
|
for (light, previous) in &mut trigger.devices {
|
||||||
let mut light = light.write().await;
|
let mut light = light.write().await;
|
||||||
|
|
|
@ -7,7 +7,8 @@ use crate::config::MqttDeviceConfig;
|
||||||
use crate::device_manager::DeviceConfig;
|
use crate::device_manager::DeviceConfig;
|
||||||
use crate::devices::Device;
|
use crate::devices::Device;
|
||||||
use crate::error::DeviceConfigError;
|
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;
|
use crate::messages::BrightnessMessage;
|
||||||
|
|
||||||
#[derive(Debug, Clone, LuaDeviceConfig)]
|
#[derive(Debug, Clone, LuaDeviceConfig)]
|
||||||
|
@ -16,8 +17,8 @@ pub struct LightSensorConfig {
|
||||||
pub mqtt: MqttDeviceConfig,
|
pub mqtt: MqttDeviceConfig,
|
||||||
pub min: isize,
|
pub min: isize,
|
||||||
pub max: isize,
|
pub max: isize,
|
||||||
#[device_config(user_data)]
|
#[device_config(rename = "event_channel", user_data, with = "TxHelper")]
|
||||||
pub event_channel: EventChannel,
|
pub tx: event::Sender,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const DEFAULT: bool = false;
|
pub const DEFAULT: bool = false;
|
||||||
|
@ -30,7 +31,6 @@ impl DeviceConfig for LightSensorConfig {
|
||||||
let device = LightSensor {
|
let device = LightSensor {
|
||||||
identifier: identifier.into(),
|
identifier: identifier.into(),
|
||||||
// Add helper type that does this conversion for us
|
// Add helper type that does this conversion for us
|
||||||
tx: self.event_channel.get_tx(),
|
|
||||||
config: self.clone(),
|
config: self.clone(),
|
||||||
is_dark: DEFAULT,
|
is_dark: DEFAULT,
|
||||||
};
|
};
|
||||||
|
@ -45,7 +45,6 @@ pub struct LightSensor {
|
||||||
#[config]
|
#[config]
|
||||||
config: LightSensorConfig,
|
config: LightSensorConfig,
|
||||||
|
|
||||||
tx: event::Sender,
|
|
||||||
is_dark: bool,
|
is_dark: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +90,7 @@ impl OnMqtt for LightSensor {
|
||||||
debug!("Dark state has changed: {is_dark}");
|
debug!("Dark state has changed: {is_dark}");
|
||||||
self.is_dark = 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");
|
warn!("There are no receivers on the event channel");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ use super::{Device, Notification};
|
||||||
use crate::config::MqttDeviceConfig;
|
use crate::config::MqttDeviceConfig;
|
||||||
use crate::device_manager::DeviceConfig;
|
use crate::device_manager::DeviceConfig;
|
||||||
use crate::error::DeviceConfigError;
|
use crate::error::DeviceConfigError;
|
||||||
use crate::event::{Event, EventChannel, OnMqtt};
|
use crate::event::{self, Event, OnMqtt};
|
||||||
|
use crate::helper::TxHelper;
|
||||||
use crate::messages::PowerMessage;
|
use crate::messages::PowerMessage;
|
||||||
|
|
||||||
#[derive(Debug, Clone, LuaDeviceConfig)]
|
#[derive(Debug, Clone, LuaDeviceConfig)]
|
||||||
|
@ -17,8 +18,8 @@ pub struct WasherConfig {
|
||||||
mqtt: MqttDeviceConfig,
|
mqtt: MqttDeviceConfig,
|
||||||
// Power in Watt
|
// Power in Watt
|
||||||
threshold: f32,
|
threshold: f32,
|
||||||
#[device_config(user_data)]
|
#[device_config(rename = "event_channel", user_data, with = "TxHelper")]
|
||||||
event_channel: EventChannel,
|
pub tx: event::Sender,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -91,8 +92,7 @@ impl OnMqtt for Washer {
|
||||||
|
|
||||||
if self
|
if self
|
||||||
.config
|
.config
|
||||||
.event_channel
|
.tx
|
||||||
.get_tx()
|
|
||||||
.send(Event::Ntfy(notification))
|
.send(Event::Ntfy(notification))
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err()
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
use std::net::{Ipv4Addr, SocketAddr};
|
use std::net::{Ipv4Addr, SocketAddr};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use mlua::FromLua;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::event::{self, EventChannel};
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct DurationSeconds(u64);
|
pub struct DurationSeconds(u64);
|
||||||
|
|
||||||
|
@ -20,3 +23,18 @@ impl<const PORT: u16> From<Ipv4SocketAddr<PORT>> for SocketAddr {
|
||||||
Self::from((ip.0, PORT))
|
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<Self> {
|
||||||
|
Ok(TxHelper(mlua::FromLua::from_lua(value, lua)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TxHelper> for event::Sender {
|
||||||
|
fn from(value: TxHelper) -> Self {
|
||||||
|
value.0.get_tx()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user