Everything needed to construct a new device is passed in through lua

This commit is contained in:
2024-04-25 01:35:23 +02:00
parent 2bc2dc6be1
commit 9449a83f61
22 changed files with 490 additions and 252 deletions

View File

@@ -1,40 +1,37 @@
use async_trait::async_trait;
use automation_macro::LuaDevice;
use automation_macro::{LuaDevice, LuaDeviceConfig};
use google_home::device::Name;
use google_home::errors::ErrorCode;
use google_home::traits::{AvailableSpeeds, FanSpeed, HumiditySetting, OnOff, Speed, SpeedValues};
use google_home::types::Type;
use google_home::GoogleHomeDevice;
use rumqttc::{AsyncClient, Publish};
use serde::Deserialize;
use rumqttc::Publish;
use tracing::{debug, error, warn};
use crate::config::{InfoConfig, MqttDeviceConfig};
use crate::device_manager::{ConfigExternal, DeviceConfig};
use crate::device_manager::DeviceConfig;
use crate::devices::Device;
use crate::error::DeviceConfigError;
use crate::event::OnMqtt;
use crate::messages::{AirFilterFanState, AirFilterState, SetAirFilterFanState};
use crate::mqtt::WrappedAsyncClient;
#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Clone, LuaDeviceConfig)]
pub struct AirFilterConfig {
#[serde(flatten)]
#[device_config(flatten)]
info: InfoConfig,
#[serde(flatten)]
#[device_config(flatten)]
mqtt: MqttDeviceConfig,
#[device_config(user_data)]
client: WrappedAsyncClient,
}
#[async_trait]
impl DeviceConfig for AirFilterConfig {
async fn create(
&self,
identifier: &str,
ext: &ConfigExternal,
) -> Result<Box<dyn Device>, DeviceConfigError> {
async fn create(&self, identifier: &str) -> Result<Box<dyn Device>, DeviceConfigError> {
let device = AirFilter {
identifier: identifier.into(),
config: self.clone(),
client: ext.client.clone(),
last_known_state: AirFilterState {
state: AirFilterFanState::Off,
humidity: 0.0,
@@ -51,7 +48,6 @@ pub struct AirFilter {
#[config]
config: AirFilterConfig,
client: AsyncClient,
last_known_state: AirFilterState,
}
@@ -61,7 +57,8 @@ impl AirFilter {
let topic = format!("{}/set", self.config.mqtt.topic);
// TODO: Handle potential errors here
self.client
self.config
.client
.publish(
topic.clone(),
rumqttc::QoS::AtLeastOnce,

View File

@@ -1,73 +1,44 @@
use async_trait::async_trait;
use automation_macro::LuaDevice;
use automation_macro::{LuaDevice, LuaDeviceConfig};
use google_home::traits::OnOff;
use serde::Deserialize;
use tracing::{debug, error, trace, warn};
use super::Device;
use crate::config::MqttDeviceConfig;
use crate::device_manager::{ConfigExternal, DeviceConfig, WrappedDevice};
use crate::device_manager::{DeviceConfig, WrappedDevice};
use crate::devices::As;
use crate::error::DeviceConfigError;
use crate::event::{OnMqtt, OnPresence};
use crate::messages::{RemoteAction, RemoteMessage};
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, LuaDeviceConfig)]
pub struct AudioSetupConfig {
#[serde(flatten)]
#[device_config(flatten)]
mqtt: MqttDeviceConfig,
mixer: String,
speakers: String,
#[device_config(user_data)]
mixer: WrappedDevice,
#[device_config(user_data)]
speakers: WrappedDevice,
}
#[async_trait]
impl DeviceConfig for AudioSetupConfig {
async fn create(
&self,
identifier: &str,
ext: &ConfigExternal,
) -> Result<Box<dyn Device>, DeviceConfigError> {
async fn create(&self, identifier: &str) -> Result<Box<dyn Device>, DeviceConfigError> {
trace!(id = identifier, "Setting up AudioSetup");
// TODO: Make sure they implement OnOff?
let mixer = ext
.device_manager
.get(&self.mixer)
.await
// NOTE: We need to clone to make the compiler happy, how ever if this clone happens the next one can never happen...
.ok_or(DeviceConfigError::MissingChild(
identifier.into(),
self.mixer.clone(),
))?;
if !As::<dyn OnOff>::is(mixer.read().await.as_ref()) {
return Err(DeviceConfigError::MissingTrait(
self.mixer.clone(),
"OnOff".into(),
));
let mixer_id = self.mixer.read().await.get_id().to_owned();
if !As::<dyn OnOff>::is(self.mixer.read().await.as_ref()) {
return Err(DeviceConfigError::MissingTrait(mixer_id, "OnOff".into()));
}
let speakers =
ext.device_manager
.get(&self.speakers)
.await
.ok_or(DeviceConfigError::MissingChild(
identifier.into(),
self.speakers.clone(),
))?;
if !As::<dyn OnOff>::is(speakers.read().await.as_ref()) {
return Err(DeviceConfigError::MissingTrait(
self.speakers.clone(),
"OnOff".into(),
));
let speakers_id = self.speakers.read().await.get_id().to_owned();
if !As::<dyn OnOff>::is(self.speakers.read().await.as_ref()) {
return Err(DeviceConfigError::MissingTrait(speakers_id, "OnOff".into()));
}
let device = AudioSetup {
identifier: identifier.into(),
config: self.clone(),
mixer,
speakers,
};
Ok(Box::new(device))
@@ -80,8 +51,6 @@ pub struct AudioSetup {
identifier: String,
#[config]
config: AudioSetupConfig,
mixer: WrappedDevice,
speakers: WrappedDevice,
}
impl Device for AudioSetup {
@@ -105,8 +74,8 @@ impl OnMqtt for AudioSetup {
}
};
let mut mixer = self.mixer.write().await;
let mut speakers = self.speakers.write().await;
let mut mixer = self.config.mixer.write().await;
let mut speakers = self.config.speakers.write().await;
if let (Some(mixer), Some(speakers)) = (
As::<dyn OnOff>::cast_mut(mixer.as_mut()),
As::<dyn OnOff>::cast_mut(speakers.as_mut()),
@@ -140,8 +109,8 @@ impl OnMqtt for AudioSetup {
#[async_trait]
impl OnPresence for AudioSetup {
async fn on_presence(&mut self, presence: bool) {
let mut mixer = self.mixer.write().await;
let mut speakers = self.speakers.write().await;
let mut mixer = self.config.mixer.write().await;
let mut speakers = self.config.speakers.write().await;
if let (Some(mixer), Some(speakers)) = (
As::<dyn OnOff>::cast_mut(mixer.as_mut()),

View File

@@ -1,83 +1,71 @@
use std::time::Duration;
use async_trait::async_trait;
use automation_macro::LuaDevice;
use automation_macro::{LuaDevice, LuaDeviceConfig};
use google_home::traits::OnOff;
use rumqttc::AsyncClient;
use serde::Deserialize;
use serde_with::{serde_as, DurationSeconds};
use tokio::task::JoinHandle;
use tracing::{debug, error, trace, warn};
use super::Device;
use crate::config::MqttDeviceConfig;
use crate::device_manager::{ConfigExternal, DeviceConfig, WrappedDevice};
use crate::device_manager::{DeviceConfig, WrappedDevice};
use crate::devices::{As, DEFAULT_PRESENCE};
use crate::error::DeviceConfigError;
use crate::event::{OnMqtt, OnPresence};
use crate::helper::DurationSeconds;
use crate::messages::{ContactMessage, PresenceMessage};
use crate::mqtt::WrappedAsyncClient;
use crate::traits::Timeout;
// NOTE: If we add more presence devices we might need to move this out of here
#[serde_as]
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, LuaDeviceConfig)]
pub struct PresenceDeviceConfig {
#[serde(flatten)]
#[device_config(flatten)]
pub mqtt: MqttDeviceConfig,
#[serde_as(as = "DurationSeconds")]
#[device_config(with = "DurationSeconds")]
pub timeout: Duration,
}
#[serde_as]
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, LuaDeviceConfig)]
pub struct TriggerConfig {
devices: Vec<String>,
#[serde(default)]
#[serde_as(as = "DurationSeconds")]
pub timeout: Duration,
#[device_config(user_data)]
devices: Vec<WrappedDevice>,
#[device_config(with = "Option<DurationSeconds>")]
pub timeout: Option<Duration>,
}
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, LuaDeviceConfig)]
pub struct ContactSensorConfig {
#[serde(flatten)]
#[device_config(flatten)]
mqtt: MqttDeviceConfig,
#[device_config(user_data)]
presence: Option<PresenceDeviceConfig>,
#[device_config(user_data)]
trigger: Option<TriggerConfig>,
#[device_config(user_data)]
client: WrappedAsyncClient,
}
#[async_trait]
impl DeviceConfig for ContactSensorConfig {
async fn create(
&self,
identifier: &str,
ext: &ConfigExternal,
) -> Result<Box<dyn Device>, DeviceConfigError> {
async fn create(&self, identifier: &str) -> Result<Box<dyn Device>, DeviceConfigError> {
trace!(id = identifier, "Setting up ContactSensor");
let trigger = if let Some(trigger_config) = &self.trigger {
let mut devices = Vec::new();
for device_name in &trigger_config.devices {
let device = ext.device_manager.get(device_name).await.ok_or(
DeviceConfigError::MissingChild(device_name.into(), "OnOff".into()),
)?;
for device in &trigger_config.devices {
let id = device.read().await.get_id().to_owned();
if !As::<dyn OnOff>::is(device.read().await.as_ref()) {
return Err(DeviceConfigError::MissingTrait(
device_name.into(),
"OnOff".into(),
));
return Err(DeviceConfigError::MissingTrait(id, "OnOff".into()));
}
if !trigger_config.timeout.is_zero()
if trigger_config.timeout.is_none()
&& !As::<dyn Timeout>::is(device.read().await.as_ref())
{
return Err(DeviceConfigError::MissingTrait(
device_name.into(),
"Timeout".into(),
));
return Err(DeviceConfigError::MissingTrait(id, "Timeout".into()));
}
devices.push((device, false));
devices.push((device.clone(), false));
}
Some(Trigger {
@@ -91,7 +79,6 @@ impl DeviceConfig for ContactSensorConfig {
let device = ContactSensor {
identifier: identifier.into(),
config: self.clone(),
client: ext.client.clone(),
overall_presence: DEFAULT_PRESENCE,
is_closed: true,
handle: None,
@@ -105,7 +92,7 @@ impl DeviceConfig for ContactSensorConfig {
#[derive(Debug)]
struct Trigger {
devices: Vec<(WrappedDevice, bool)>,
timeout: Duration, // Timeout in seconds
timeout: Option<Duration>,
}
#[derive(Debug, LuaDevice)]
@@ -114,7 +101,6 @@ pub struct ContactSensor {
#[config]
config: ContactSensorConfig,
client: AsyncClient,
overall_presence: bool,
is_closed: bool,
handle: Option<JoinHandle<()>>,
@@ -171,12 +157,14 @@ impl OnMqtt for ContactSensor {
let mut light = light.write().await;
if !previous {
// If the timeout is zero just turn the light off directly
if trigger.timeout.is_zero()
if trigger.timeout.is_none()
&& let Some(light) = As::<dyn OnOff>::cast_mut(light.as_mut())
{
light.set_on(false).await.ok();
} else if let Some(light) = As::<dyn Timeout>::cast_mut(light.as_mut()) {
light.start_timeout(trigger.timeout).await.unwrap();
} else if let Some(timeout) = trigger.timeout
&& let Some(light) = As::<dyn Timeout>::cast_mut(light.as_mut())
{
light.start_timeout(timeout).await.unwrap();
}
// TODO: Put a warning/error on creation if either of this has to option to fail
}
@@ -201,7 +189,8 @@ impl OnMqtt for ContactSensor {
// This is to prevent the house from being marked as present for however long the
// timeout is set when leaving the house
if !self.overall_presence {
self.client
self.config
.client
.publish(
presence.mqtt.topic.clone(),
rumqttc::QoS::AtLeastOnce,
@@ -219,7 +208,7 @@ impl OnMqtt for ContactSensor {
}
} else {
// Once the door is closed again we start a timeout for removing the presence
let client = self.client.clone();
let client = self.config.client.clone();
let id = self.identifier.clone();
let timeout = presence.timeout;
let topic = presence.mqtt.topic.clone();

View File

@@ -1,33 +1,29 @@
use async_trait::async_trait;
use automation_macro::LuaDevice;
use rumqttc::AsyncClient;
use serde::Deserialize;
use automation_macro::{LuaDevice, LuaDeviceConfig};
use tracing::warn;
use crate::config::MqttDeviceConfig;
use crate::device_manager::{ConfigExternal, DeviceConfig};
use crate::device_manager::DeviceConfig;
use crate::devices::Device;
use crate::error::DeviceConfigError;
use crate::event::{OnDarkness, OnPresence};
use crate::messages::{DarknessMessage, PresenceMessage};
use crate::mqtt::WrappedAsyncClient;
#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, LuaDeviceConfig, Clone)]
pub struct DebugBridgeConfig {
#[serde(flatten)]
#[device_config(flatten)]
pub mqtt: MqttDeviceConfig,
#[device_config(user_data)]
client: WrappedAsyncClient,
}
#[async_trait]
impl DeviceConfig for DebugBridgeConfig {
async fn create(
&self,
identifier: &str,
ext: &ConfigExternal,
) -> Result<Box<dyn Device>, DeviceConfigError> {
async fn create(&self, identifier: &str) -> Result<Box<dyn Device>, DeviceConfigError> {
let device = DebugBridge {
identifier: identifier.into(),
config: self.clone(),
client: ext.client.clone(),
};
Ok(Box::new(device))
@@ -39,7 +35,6 @@ pub struct DebugBridge {
identifier: String,
#[config]
config: DebugBridgeConfig,
client: AsyncClient,
}
impl Device for DebugBridge {
@@ -53,7 +48,8 @@ impl OnPresence for DebugBridge {
async fn on_presence(&mut self, presence: bool) {
let message = PresenceMessage::new(presence);
let topic = format!("{}/presence", self.config.mqtt.topic);
self.client
self.config
.client
.publish(
topic,
rumqttc::QoS::AtLeastOnce,
@@ -76,7 +72,8 @@ impl OnDarkness for DebugBridge {
async fn on_darkness(&mut self, dark: bool) {
let message = DarknessMessage::new(dark);
let topic = format!("{}/darkness", self.config.mqtt.topic);
self.client
self.config
.client
.publish(
topic,
rumqttc::QoS::AtLeastOnce,

View File

@@ -1,11 +1,11 @@
use std::net::Ipv4Addr;
use async_trait::async_trait;
use automation_macro::LuaDevice;
use automation_macro::{LuaDevice, LuaDeviceConfig};
use serde::{Deserialize, Serialize};
use tracing::{error, trace, warn};
use crate::device_manager::{ConfigExternal, DeviceConfig};
use crate::device_manager::DeviceConfig;
use crate::devices::Device;
use crate::error::DeviceConfigError;
use crate::event::{OnDarkness, OnPresence};
@@ -22,8 +22,9 @@ pub struct FlagIDs {
pub darkness: isize,
}
#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, LuaDeviceConfig, Clone)]
pub struct HueBridgeConfig {
// TODO: Add helper type that converts this to a socketaddr automatically
pub ip: Ipv4Addr,
pub login: String,
pub flags: FlagIDs,
@@ -31,11 +32,7 @@ pub struct HueBridgeConfig {
#[async_trait]
impl DeviceConfig for HueBridgeConfig {
async fn create(
&self,
identifier: &str,
_ext: &ConfigExternal,
) -> Result<Box<dyn Device>, DeviceConfigError> {
async fn create(&self, identifier: &str) -> Result<Box<dyn Device>, DeviceConfigError> {
let device = HueBridge {
identifier: identifier.into(),
config: self.clone(),

View File

@@ -3,39 +3,35 @@ use std::time::Duration;
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use automation_macro::LuaDevice;
use automation_macro::{LuaDevice, LuaDeviceConfig};
use google_home::errors::ErrorCode;
use google_home::traits::OnOff;
use rumqttc::Publish;
use serde::Deserialize;
use tracing::{debug, error, warn};
use super::Device;
use crate::config::MqttDeviceConfig;
use crate::device_manager::{ConfigExternal, DeviceConfig};
use crate::device_manager::DeviceConfig;
use crate::error::DeviceConfigError;
use crate::event::OnMqtt;
use crate::messages::{RemoteAction, RemoteMessage};
use crate::traits::Timeout;
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, LuaDeviceConfig)]
pub struct HueGroupConfig {
// TODO: Add helper type that converts this to a socketaddr automatically
pub ip: Ipv4Addr,
pub login: String,
pub group_id: isize,
pub timer_id: isize,
pub scene_id: String,
#[serde(default)]
#[device_config(default)]
pub remotes: Vec<MqttDeviceConfig>,
}
#[async_trait]
impl DeviceConfig for HueGroupConfig {
async fn create(
&self,
identifier: &str,
_ext: &ConfigExternal,
) -> Result<Box<dyn Device>, DeviceConfigError> {
async fn create(&self, identifier: &str) -> Result<Box<dyn Device>, DeviceConfigError> {
let device = HueGroup {
identifier: identifier.into(),
config: self.clone(),

View File

@@ -2,23 +2,24 @@ use std::time::Duration;
use anyhow::Result;
use async_trait::async_trait;
use automation_macro::LuaDevice;
use automation_macro::{LuaDevice, LuaDeviceConfig};
use google_home::errors::ErrorCode;
use google_home::traits::{self, OnOff};
use google_home::types::Type;
use google_home::{device, GoogleHomeDevice};
use rumqttc::{matches, AsyncClient, Publish};
use rumqttc::{matches, Publish};
use serde::Deserialize;
use serde_with::{serde_as, DurationSeconds};
use tokio::task::JoinHandle;
use tracing::{debug, error, trace, warn};
use crate::config::{InfoConfig, MqttDeviceConfig};
use crate::device_manager::{ConfigExternal, DeviceConfig};
use crate::device_manager::DeviceConfig;
use crate::devices::Device;
use crate::error::DeviceConfigError;
use crate::event::{OnMqtt, OnPresence};
use crate::helper::DurationSeconds;
use crate::messages::{OnOffMessage, RemoteAction, RemoteMessage};
use crate::mqtt::WrappedAsyncClient;
use crate::traits::Timeout;
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Copy)]
@@ -29,19 +30,21 @@ pub enum OutletType {
Light,
}
#[serde_as]
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, LuaDeviceConfig)]
pub struct IkeaOutletConfig {
#[serde(flatten)]
#[device_config(flatten)]
info: InfoConfig,
#[serde(flatten)]
#[device_config(flatten)]
mqtt: MqttDeviceConfig,
#[serde(default = "default_outlet_type")]
#[device_config(default = default_outlet_type)]
outlet_type: OutletType,
#[serde_as(as = "Option<DurationSeconds>")]
timeout: Option<Duration>, // Timeout in seconds
#[serde(default)]
#[device_config(with = "Option<DurationSeconds>")]
timeout: Option<Duration>,
#[device_config(default)]
pub remotes: Vec<MqttDeviceConfig>,
#[device_config(user_data)]
client: WrappedAsyncClient,
}
fn default_outlet_type() -> OutletType {
@@ -50,11 +53,7 @@ fn default_outlet_type() -> OutletType {
#[async_trait]
impl DeviceConfig for IkeaOutletConfig {
async fn create(
&self,
identifier: &str,
ext: &ConfigExternal,
) -> Result<Box<dyn Device>, DeviceConfigError> {
async fn create(&self, identifier: &str) -> Result<Box<dyn Device>, DeviceConfigError> {
trace!(
id = identifier,
name = self.info.name,
@@ -65,7 +64,6 @@ impl DeviceConfig for IkeaOutletConfig {
let device = IkeaOutlet {
identifier: identifier.into(),
config: self.clone(),
client: ext.client.clone(),
last_known_state: false,
handle: None,
};
@@ -80,12 +78,11 @@ pub struct IkeaOutlet {
#[config]
config: IkeaOutletConfig,
client: AsyncClient,
last_known_state: bool,
handle: Option<JoinHandle<()>>,
}
async fn set_on(client: AsyncClient, topic: &str, on: bool) {
async fn set_on(client: WrappedAsyncClient, topic: &str, on: bool) {
let message = OnOffMessage::new(on);
let topic = format!("{}/set", topic);
@@ -219,7 +216,7 @@ impl traits::OnOff for IkeaOutlet {
}
async fn set_on(&mut self, on: bool) -> Result<(), ErrorCode> {
set_on(self.client.clone(), &self.config.mqtt.topic, on).await;
set_on(self.config.client.clone(), &self.config.mqtt.topic, on).await;
Ok(())
}
@@ -234,7 +231,7 @@ impl crate::traits::Timeout for IkeaOutlet {
// Turn the kettle of after the specified timeout
// TODO: Impl Drop for IkeaOutlet that will abort the handle if the IkeaOutlet
// get dropped
let client = self.client.clone();
let client = self.config.client.clone();
let topic = self.config.mqtt.topic.clone();
let id = self.identifier.clone();
self.handle = Some(tokio::spawn(async move {

View File

@@ -2,7 +2,7 @@ use std::net::{Ipv4Addr, SocketAddr};
use std::str::Utf8Error;
use async_trait::async_trait;
use automation_macro::LuaDevice;
use automation_macro::{LuaDevice, LuaDeviceConfig};
use bytes::{Buf, BufMut};
use google_home::errors::{self, DeviceError};
use google_home::traits;
@@ -13,21 +13,18 @@ use tokio::net::TcpStream;
use tracing::trace;
use super::Device;
use crate::device_manager::{ConfigExternal, DeviceConfig};
use crate::device_manager::DeviceConfig;
use crate::error::DeviceConfigError;
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, LuaDeviceConfig)]
pub struct KasaOutletConfig {
// TODO: Add helper type that converts this to a socketaddr automatically
ip: Ipv4Addr,
}
#[async_trait]
impl DeviceConfig for KasaOutletConfig {
async fn create(
&self,
identifier: &str,
_ext: &ConfigExternal,
) -> Result<Box<dyn Device>, DeviceConfigError> {
async fn create(&self, identifier: &str) -> Result<Box<dyn Device>, DeviceConfigError> {
trace!(id = identifier, "Setting up KasaOutlet");
let device = KasaOutlet {

View File

@@ -1,22 +1,23 @@
use async_trait::async_trait;
use automation_macro::LuaDevice;
use automation_macro::{LuaDevice, LuaDeviceConfig};
use rumqttc::Publish;
use serde::Deserialize;
use tracing::{debug, trace, warn};
use crate::config::MqttDeviceConfig;
use crate::device_manager::{ConfigExternal, DeviceConfig};
use crate::device_manager::DeviceConfig;
use crate::devices::Device;
use crate::error::DeviceConfigError;
use crate::event::{self, Event, OnMqtt};
use crate::event::{self, Event, EventChannel, OnMqtt};
use crate::messages::BrightnessMessage;
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, LuaDeviceConfig)]
pub struct LightSensorConfig {
#[serde(flatten)]
#[device_config(flatten)]
pub mqtt: MqttDeviceConfig,
pub min: isize,
pub max: isize,
#[device_config(user_data)]
pub event_channel: EventChannel,
}
pub const DEFAULT: bool = false;
@@ -25,14 +26,11 @@ pub const DEFAULT: bool = false;
#[async_trait]
impl DeviceConfig for LightSensorConfig {
async fn create(
&self,
identifier: &str,
ext: &ConfigExternal,
) -> Result<Box<dyn Device>, DeviceConfigError> {
async fn create(&self, identifier: &str) -> Result<Box<dyn Device>, DeviceConfigError> {
let device = LightSensor {
identifier: identifier.into(),
tx: ext.event_channel.get_tx(),
// Add helper type that does this conversion for us
tx: self.event_channel.get_tx(),
config: self.clone(),
is_dark: DEFAULT,
};

View File

@@ -23,7 +23,7 @@ pub use self::hue_bridge::*;
pub use self::hue_light::*;
pub use self::ikea_outlet::*;
pub use self::kasa_outlet::*;
pub use self::light_sensor::{LightSensor, LightSensorConfig};
pub use self::light_sensor::*;
pub use self::ntfy::{Notification, Ntfy};
pub use self::presence::{Presence, PresenceConfig, DEFAULT_PRESENCE};
pub use self::wake_on_lan::*;

View File

@@ -1,31 +1,30 @@
use std::net::Ipv4Addr;
use async_trait::async_trait;
use automation_macro::LuaDevice;
use automation_macro::{LuaDevice, LuaDeviceConfig};
use eui48::MacAddress;
use google_home::errors::ErrorCode;
use google_home::traits::{self, Scene};
use google_home::types::Type;
use google_home::{device, GoogleHomeDevice};
use rumqttc::Publish;
use serde::Deserialize;
use tracing::{debug, error, trace};
use super::Device;
use crate::config::{InfoConfig, MqttDeviceConfig};
use crate::device_manager::{ConfigExternal, DeviceConfig};
use crate::device_manager::DeviceConfig;
use crate::error::DeviceConfigError;
use crate::event::OnMqtt;
use crate::messages::ActivateMessage;
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, LuaDeviceConfig)]
pub struct WakeOnLANConfig {
#[serde(flatten)]
#[device_config(flatten)]
info: InfoConfig,
#[serde(flatten)]
#[device_config(flatten)]
mqtt: MqttDeviceConfig,
mac_address: MacAddress,
#[serde(default = "default_broadcast_ip")]
#[device_config(default = default_broadcast_ip)]
broadcast_ip: Ipv4Addr,
}
@@ -35,11 +34,7 @@ fn default_broadcast_ip() -> Ipv4Addr {
#[async_trait]
impl DeviceConfig for WakeOnLANConfig {
async fn create(
&self,
identifier: &str,
_ext: &ConfigExternal,
) -> Result<Box<dyn Device>, DeviceConfigError> {
async fn create(&self, identifier: &str) -> Result<Box<dyn Device>, DeviceConfigError> {
trace!(
id = identifier,
name = self.info.name,
@@ -47,6 +42,8 @@ impl DeviceConfig for WakeOnLANConfig {
"Setting up WakeOnLAN"
);
debug!("broadcast_ip = {}", self.broadcast_ip);
let device = WakeOnLAN {
identifier: identifier.into(),
config: self.clone(),

View File

@@ -1,35 +1,32 @@
use async_trait::async_trait;
use automation_macro::LuaDevice;
use automation_macro::{LuaDevice, LuaDeviceConfig};
use rumqttc::Publish;
use serde::Deserialize;
use tracing::{debug, error, warn};
use super::ntfy::Priority;
use super::{Device, Notification};
use crate::config::MqttDeviceConfig;
use crate::device_manager::{ConfigExternal, DeviceConfig};
use crate::device_manager::DeviceConfig;
use crate::error::DeviceConfigError;
use crate::event::{Event, EventChannel, OnMqtt};
use crate::messages::PowerMessage;
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, LuaDeviceConfig)]
pub struct WasherConfig {
#[serde(flatten)]
#[device_config(flatten)]
mqtt: MqttDeviceConfig,
threshold: f32, // Power in Watt
// Power in Watt
threshold: f32,
#[device_config(user_data)]
event_channel: EventChannel,
}
#[async_trait]
impl DeviceConfig for WasherConfig {
async fn create(
&self,
identifier: &str,
ext: &ConfigExternal,
) -> Result<Box<dyn Device>, DeviceConfigError> {
async fn create(&self, identifier: &str) -> Result<Box<dyn Device>, DeviceConfigError> {
let device = Washer {
identifier: identifier.into(),
config: self.clone(),
event_channel: ext.event_channel.clone(),
running: 0,
};
@@ -45,7 +42,6 @@ pub struct Washer {
#[config]
config: WasherConfig,
event_channel: EventChannel,
running: isize,
}
@@ -94,6 +90,7 @@ impl OnMqtt for Washer {
.set_priority(Priority::High);
if self
.config
.event_channel
.get_tx()
.send(Event::Ntfy(notification))