Everything needed to construct a new device is passed in through lua
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user