From 72ab48df4283f2b77710c1a5380426c4dc113f30 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Thu, 13 Apr 2023 05:41:32 +0200 Subject: [PATCH] The device create function is now standarized using a trait --- src/config.rs | 54 +++++++++++++++++++---------------- src/devices.rs | 10 +++---- src/devices/audio_setup.rs | 21 +++++++------- src/devices/contact_sensor.rs | 14 +++++---- src/devices/ikea_outlet.rs | 15 ++++++---- src/devices/kasa_outlet.rs | 14 +++++++-- src/devices/wake_on_lan.rs | 17 +++++++---- src/error.rs | 2 +- src/mqtt.rs | 11 ------- 9 files changed, 86 insertions(+), 72 deletions(-) diff --git a/src/config.rs b/src/config.rs index 290d013..f15b1bd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -13,11 +13,8 @@ use tracing::debug; use crate::{ auth::OpenIDConfig, debug_bridge::DebugBridgeConfig, - devices::{ - self, AudioSetup, AudioSetupConfig, ContactSensor, ContactSensorConfig, IkeaOutlet, - IkeaOutletConfig, KasaOutlet, KasaOutletConfig, WakeOnLAN, WakeOnLANConfig, - }, - error::{ConfigParseError, DeviceCreateError, MissingEnv}, + devices::{self, AudioSetup, ContactSensor, IkeaOutlet, KasaOutlet, WakeOnLAN}, + error::{ConfigParseError, CreateDeviceError, MissingEnv}, hue_bridge::HueBridgeConfig, light_sensor::LightSensorConfig, }; @@ -126,11 +123,11 @@ pub struct MqttDeviceConfig { #[derive(Debug, Clone, Deserialize)] #[serde(tag = "type")] pub enum Device { - IkeaOutlet(IkeaOutletConfig), - WakeOnLAN(WakeOnLANConfig), - KasaOutlet(KasaOutletConfig), - AudioSetup(AudioSetupConfig), - ContactSensor(ContactSensorConfig), + IkeaOutlet(::Config), + WakeOnLAN(::Config), + KasaOutlet(::Config), + AudioSetup(::Config), + ContactSensor(::Config), } impl Config { @@ -161,26 +158,33 @@ impl Config { } } +pub trait CreateDevice { + type Config; + + fn create( + identifier: &str, + config: Self::Config, + client: AsyncClient, + presence_topic: &str, // Not a big fan of passing in the global config + ) -> Result + where + Self: Sized; +} + impl Device { pub fn create( self, - identifier: &str, + id: &str, client: AsyncClient, - presence_topic: &str, - ) -> Result, DeviceCreateError> { + presence: &str, + ) -> Result, CreateDeviceError> { let device: Box = match self { - Device::IkeaOutlet(c) => Box::new(IkeaOutlet::create(identifier, c, client)?), - Device::WakeOnLAN(c) => Box::new(WakeOnLAN::create(identifier, c)?), - Device::KasaOutlet(c) => Box::new(KasaOutlet::create(identifier, c)?), - Device::AudioSetup(c) => { - Box::new(AudioSetup::create(identifier, c, client, presence_topic)?) - } - Device::ContactSensor(c) => Box::new(ContactSensor::create( - identifier, - c, - client, - presence_topic, - )?), + // TODO: It would be nice if this would be more automatic, not sure how to do that... + Device::IkeaOutlet(c) => Box::new(IkeaOutlet::create(id, c, client, presence)?), + Device::WakeOnLAN(c) => Box::new(WakeOnLAN::create(id, c, client, presence)?), + Device::KasaOutlet(c) => Box::new(KasaOutlet::create(id, c, client, presence)?), + Device::AudioSetup(c) => Box::new(AudioSetup::create(id, c, client, presence)?), + Device::ContactSensor(c) => Box::new(ContactSensor::create(id, c, client, presence)?), }; Ok(device) diff --git a/src/devices.rs b/src/devices.rs index b366980..311c345 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -4,11 +4,11 @@ mod ikea_outlet; mod kasa_outlet; mod wake_on_lan; -pub use self::audio_setup::{AudioSetup, AudioSetupConfig}; -pub use self::contact_sensor::{ContactSensor, ContactSensorConfig}; -pub use self::ikea_outlet::{IkeaOutlet, IkeaOutletConfig}; -pub use self::kasa_outlet::{KasaOutlet, KasaOutletConfig}; -pub use self::wake_on_lan::{WakeOnLAN, WakeOnLANConfig}; +pub use self::audio_setup::AudioSetup; +pub use self::contact_sensor::ContactSensor; +pub use self::ikea_outlet::IkeaOutlet; +pub use self::kasa_outlet::KasaOutlet; +pub use self::wake_on_lan::WakeOnLAN; use std::collections::HashMap; diff --git a/src/devices/audio_setup.rs b/src/devices/audio_setup.rs index ea097d7..531077b 100644 --- a/src/devices/audio_setup.rs +++ b/src/devices/audio_setup.rs @@ -4,8 +4,8 @@ use rumqttc::AsyncClient; use serde::Deserialize; use tracing::{debug, error, trace, warn}; -use crate::config::{self, MqttDeviceConfig}; -use crate::error::DeviceCreateError; +use crate::config::{self, CreateDevice, MqttDeviceConfig}; +use crate::error::CreateDeviceError; use crate::mqtt::{OnMqtt, RemoteAction, RemoteMessage}; use crate::presence::OnPresence; @@ -28,25 +28,26 @@ pub struct AudioSetup { speakers: Box, } -impl AudioSetup { - pub fn create( +impl CreateDevice for AudioSetup { + type Config = AudioSetupConfig; + + fn create( identifier: &str, - config: AudioSetupConfig, + config: Self::Config, client: AsyncClient, - // We only need to pass this in because constructing children - presence_topic: &str, // Not a big fan of passing in the global config - ) -> Result { + presence_topic: &str, + ) -> Result { trace!(id = identifier, "Setting up AudioSetup"); // Create the child devices let mixer_id = format!("{}.mixer", identifier); let mixer = (*config.mixer).create(&mixer_id, client.clone(), presence_topic)?; - let mixer = As::consume(mixer).ok_or(DeviceCreateError::OnOffExpected(mixer_id))?; + let mixer = As::consume(mixer).ok_or(CreateDeviceError::OnOffExpected(mixer_id))?; let speakers_id = format!("{}.speakers", identifier); let speakers = (*config.speakers).create(&speakers_id, client, presence_topic)?; let speakers = - As::consume(speakers).ok_or(DeviceCreateError::OnOffExpected(speakers_id))?; + As::consume(speakers).ok_or(CreateDeviceError::OnOffExpected(speakers_id))?; Ok(Self { identifier: identifier.to_owned(), diff --git a/src/devices/contact_sensor.rs b/src/devices/contact_sensor.rs index c693643..7545270 100644 --- a/src/devices/contact_sensor.rs +++ b/src/devices/contact_sensor.rs @@ -7,8 +7,8 @@ use tokio::task::JoinHandle; use tracing::{debug, error, trace, warn}; use crate::{ - config::MqttDeviceConfig, - error::{DeviceCreateError, MissingWildcard}, + config::{CreateDevice, MqttDeviceConfig}, + error::{CreateDeviceError, MissingWildcard}, mqtt::{ContactMessage, OnMqtt, PresenceMessage}, presence::OnPresence, }; @@ -69,13 +69,15 @@ pub struct ContactSensor { handle: Option>, } -impl ContactSensor { - pub fn create( +impl CreateDevice for ContactSensor { + type Config = ContactSensorConfig; + + fn create( identifier: &str, - config: ContactSensorConfig, + config: Self::Config, client: AsyncClient, presence_topic: &str, - ) -> Result { + ) -> Result { trace!(id = identifier, "Setting up ContactSensor"); let presence = config diff --git a/src/devices/ikea_outlet.rs b/src/devices/ikea_outlet.rs index a4f39ad..adc069a 100644 --- a/src/devices/ikea_outlet.rs +++ b/src/devices/ikea_outlet.rs @@ -13,9 +13,9 @@ use std::time::Duration; use tokio::task::JoinHandle; use tracing::{debug, error, trace, warn}; -use crate::config::{InfoConfig, MqttDeviceConfig}; +use crate::config::{CreateDevice, InfoConfig, MqttDeviceConfig}; use crate::devices::Device; -use crate::error::DeviceCreateError; +use crate::error::CreateDeviceError; use crate::mqtt::{OnMqtt, OnOffMessage}; use crate::presence::OnPresence; @@ -54,12 +54,15 @@ pub struct IkeaOutlet { handle: Option>, } -impl IkeaOutlet { - pub fn create( +impl CreateDevice for IkeaOutlet { + type Config = IkeaOutletConfig; + + fn create( identifier: &str, - config: IkeaOutletConfig, + config: Self::Config, client: AsyncClient, - ) -> Result { + _presence_topic: &str, // Not a big fan of passing in the global config + ) -> Result { trace!( id = identifier, name = config.info.name, diff --git a/src/devices/kasa_outlet.rs b/src/devices/kasa_outlet.rs index ee8dd26..2bb4bf4 100644 --- a/src/devices/kasa_outlet.rs +++ b/src/devices/kasa_outlet.rs @@ -9,11 +9,12 @@ use google_home::{ errors::{self, DeviceError}, traits, }; +use rumqttc::AsyncClient; use serde::{Deserialize, Serialize}; use thiserror::Error; use tracing::trace; -use crate::error::DeviceCreateError; +use crate::{config::CreateDevice, error::CreateDeviceError}; use super::Device; @@ -28,8 +29,15 @@ pub struct KasaOutlet { addr: SocketAddr, } -impl KasaOutlet { - pub fn create(identifier: &str, config: KasaOutletConfig) -> Result { +impl CreateDevice for KasaOutlet { + type Config = KasaOutletConfig; + + fn create( + identifier: &str, + config: Self::Config, + _client: AsyncClient, + _presence_topic: &str, + ) -> Result { trace!(id = identifier, "Setting up KasaOutlet"); Ok(Self { diff --git a/src/devices/wake_on_lan.rs b/src/devices/wake_on_lan.rs index 5987aca..90ddda9 100644 --- a/src/devices/wake_on_lan.rs +++ b/src/devices/wake_on_lan.rs @@ -9,13 +9,13 @@ use google_home::{ types::Type, GoogleHomeDevice, }; -use rumqttc::Publish; +use rumqttc::{AsyncClient, Publish}; use serde::Deserialize; use tracing::{debug, error, trace}; use crate::{ - config::{InfoConfig, MqttDeviceConfig}, - error::DeviceCreateError, + config::{CreateDevice, InfoConfig, MqttDeviceConfig}, + error::CreateDeviceError, mqtt::{ActivateMessage, OnMqtt}, }; @@ -45,8 +45,15 @@ pub struct WakeOnLAN { broadcast_ip: Ipv4Addr, } -impl WakeOnLAN { - pub fn create(identifier: &str, config: WakeOnLANConfig) -> Result { +impl CreateDevice for WakeOnLAN { + type Config = WakeOnLANConfig; + + fn create( + identifier: &str, + config: Self::Config, + _client: AsyncClient, + _presence_topic: &str, + ) -> Result { trace!( id = identifier, name = config.info.name, diff --git a/src/error.rs b/src/error.rs index 8f85ee1..19d7d73 100644 --- a/src/error.rs +++ b/src/error.rs @@ -83,7 +83,7 @@ impl MissingWildcard { } #[derive(Debug, Error)] -pub enum DeviceCreateError { +pub enum CreateDeviceError { #[error("Expected device '{0}' to implement OnOff trait")] OnOffExpected(String), #[error(transparent)] diff --git a/src/mqtt.rs b/src/mqtt.rs index 0db1d86..d9f50b0 100644 --- a/src/mqtt.rs +++ b/src/mqtt.rs @@ -19,17 +19,6 @@ pub trait OnMqtt { pub type Receiver = broadcast::Receiver; type Sender = broadcast::Sender; -#[derive(Debug, Clone, Deserialize)] -pub struct MqttConfig { - pub host: String, - pub port: u16, - pub client_name: String, - pub username: String, - pub password: String, - #[serde(default)] - pub tls: bool, -} - pub struct Mqtt { tx: Sender, eventloop: EventLoop,