AudioSetup now takes the name of two already created devices and stores a reference to the devices instead of creating and owning the devices directly
This commit is contained in:
parent
76b75b0cfb
commit
e38c5eed31
|
@ -2,12 +2,12 @@
|
||||||
base_url = "https://login.huizinga.dev/api/oidc"
|
base_url = "https://login.huizinga.dev/api/oidc"
|
||||||
|
|
||||||
[mqtt]
|
[mqtt]
|
||||||
host="olympus.vpn.huizinga.dev"
|
host = "olympus.vpn.huizinga.dev"
|
||||||
port=8883
|
port = 8883
|
||||||
client_name="automation-ares"
|
client_name = "automation-ares"
|
||||||
username="mqtt"
|
username = "mqtt"
|
||||||
password="${MQTT_PASSWORD}"
|
password = "${MQTT_PASSWORD}"
|
||||||
tls=true
|
tls = true
|
||||||
|
|
||||||
[ntfy]
|
[ntfy]
|
||||||
topic = "${NTFY_TOPIC}"
|
topic = "${NTFY_TOPIC}"
|
||||||
|
|
|
@ -65,15 +65,19 @@ topic = "automation/appliance/living_room/zeus"
|
||||||
mac_address = "30:9c:23:60:9c:13"
|
mac_address = "30:9c:23:60:9c:13"
|
||||||
broadcast_ip = "10.0.0.255"
|
broadcast_ip = "10.0.0.255"
|
||||||
|
|
||||||
|
[devices.living_mixer]
|
||||||
|
type = "KasaOutlet"
|
||||||
|
ip = "10.0.0.49"
|
||||||
|
|
||||||
|
[devices.living_speakers]
|
||||||
|
type = "KasaOutlet"
|
||||||
|
ip = "10.0.0.182"
|
||||||
|
|
||||||
[devices.living_audio]
|
[devices.living_audio]
|
||||||
type = "AudioSetup"
|
type = "AudioSetup"
|
||||||
topic = "zigbee2mqtt/living/remote"
|
topic = "zigbee2mqtt/living/remote"
|
||||||
[devices.living_audio.mixer]
|
mixer = "living_mixer"
|
||||||
type = "KasaOutlet"
|
speakers = "living_speakers"
|
||||||
ip = "10.0.0.49"
|
|
||||||
[devices.living_audio.speakers]
|
|
||||||
type = "KasaOutlet"
|
|
||||||
ip = "10.0.0.182"
|
|
||||||
|
|
||||||
[devices.hallway_frontdoor]
|
[devices.hallway_frontdoor]
|
||||||
type = "ContactSensor"
|
type = "ContactSensor"
|
||||||
|
|
|
@ -65,15 +65,19 @@ room = "Living Room"
|
||||||
topic = "automation/appliance/living_room/zeus"
|
topic = "automation/appliance/living_room/zeus"
|
||||||
mac_address = "30:9c:23:60:9c:13"
|
mac_address = "30:9c:23:60:9c:13"
|
||||||
|
|
||||||
|
[devices.living_mixer]
|
||||||
|
type = "KasaOutlet"
|
||||||
|
ip = "10.0.0.49"
|
||||||
|
|
||||||
|
[devices.living_speakers]
|
||||||
|
type = "KasaOutlet"
|
||||||
|
ip = "10.0.0.182"
|
||||||
|
|
||||||
[devices.living_audio]
|
[devices.living_audio]
|
||||||
type = "AudioSetup"
|
type = "AudioSetup"
|
||||||
topic = "zigbee2mqtt/living/remote"
|
topic = "zigbee2mqtt/living/remote"
|
||||||
[devices.living_audio.mixer]
|
mixer = "light_sensor"
|
||||||
type = "KasaOutlet"
|
speakers = "living_speakers"
|
||||||
ip = "10.0.0.49"
|
|
||||||
[devices.living_audio.speakers]
|
|
||||||
type = "KasaOutlet"
|
|
||||||
ip = "10.0.0.182"
|
|
||||||
|
|
||||||
[devices.hallway_frontdoor]
|
[devices.hallway_frontdoor]
|
||||||
type = "ContactSensor"
|
type = "ContactSensor"
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::{
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
use regex::{Captures, Regex};
|
use regex::{Captures, Regex};
|
||||||
use rumqttc::{AsyncClient, MqttOptions, Transport};
|
use rumqttc::{AsyncClient, MqttOptions, Transport};
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
|
@ -11,6 +12,7 @@ use tracing::debug;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
auth::OpenIDConfig,
|
auth::OpenIDConfig,
|
||||||
|
device_manager::DeviceManager,
|
||||||
devices::{
|
devices::{
|
||||||
AudioSetup, ContactSensor, DebugBridgeConfig, Device, HueBridgeConfig, IkeaOutlet,
|
AudioSetup, ContactSensor, DebugBridgeConfig, Device, HueBridgeConfig, IkeaOutlet,
|
||||||
KasaOutlet, LightSensorConfig, PresenceConfig, WakeOnLAN,
|
KasaOutlet, LightSensorConfig, PresenceConfig, WakeOnLAN,
|
||||||
|
@ -158,39 +160,42 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
pub trait CreateDevice {
|
pub trait CreateDevice {
|
||||||
type Config;
|
type Config;
|
||||||
|
|
||||||
fn create(
|
async fn create(
|
||||||
identifier: &str,
|
identifier: &str,
|
||||||
config: Self::Config,
|
config: Self::Config,
|
||||||
event_channel: &EventChannel,
|
event_channel: &EventChannel,
|
||||||
client: &AsyncClient,
|
client: &AsyncClient,
|
||||||
// TODO: Not a big fan of passing in the global config
|
// TODO: Not a big fan of passing in the global config
|
||||||
presence_topic: &str,
|
presence_topic: &str,
|
||||||
|
devices: &DeviceManager,
|
||||||
) -> Result<Self, CreateDeviceError>
|
) -> Result<Self, CreateDeviceError>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! create {
|
macro_rules! create {
|
||||||
(($self:ident, $id:ident, $event_channel:ident, $client:ident, $presence_topic:ident), [ $( $Variant:ident ),* ]) => {
|
(($self:ident, $id:ident, $event_channel:ident, $client:ident, $presence_topic:ident, $device_manager:ident), [ $( $Variant:ident ),* ]) => {
|
||||||
match $self {
|
match $self {
|
||||||
$(DeviceConfig::$Variant(c) => Box::new($Variant::create($id, c, $event_channel, $client, $presence_topic)?),)*
|
$(DeviceConfig::$Variant(c) => Box::new($Variant::create($id, c, $event_channel, $client, $presence_topic, $device_manager).await?),)*
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeviceConfig {
|
impl DeviceConfig {
|
||||||
pub fn create(
|
pub async fn create(
|
||||||
self,
|
self,
|
||||||
id: &str,
|
id: &str,
|
||||||
event_channel: &EventChannel,
|
event_channel: &EventChannel,
|
||||||
client: &AsyncClient,
|
client: &AsyncClient,
|
||||||
presence_topic: &str,
|
presence_topic: &str,
|
||||||
|
device_manager: &DeviceManager,
|
||||||
) -> Result<Box<dyn Device>, CreateDeviceError> {
|
) -> Result<Box<dyn Device>, CreateDeviceError> {
|
||||||
Ok(create! {
|
Ok(create! {
|
||||||
(self, id, event_channel, client, presence_topic), [
|
(self, id, event_channel, client, presence_topic, device_manager), [
|
||||||
AudioSetup,
|
AudioSetup,
|
||||||
ContactSensor,
|
ContactSensor,
|
||||||
IkeaOutlet,
|
IkeaOutlet,
|
||||||
|
|
|
@ -14,7 +14,8 @@ use crate::{
|
||||||
event::{Event, EventChannel, OnMqtt},
|
event::{Event, EventChannel, OnMqtt},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type DeviceMap = HashMap<String, Arc<RwLock<Box<dyn Device>>>>;
|
pub type WrappedDevice = Arc<RwLock<Box<dyn Device>>>;
|
||||||
|
pub type DeviceMap = HashMap<String, WrappedDevice>;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DeviceManager {
|
pub struct DeviceManager {
|
||||||
|
@ -70,6 +71,10 @@ impl DeviceManager {
|
||||||
self.devices.write().await.insert(id, device);
|
self.devices.write().await.insert(id, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get(&self, name: &str) -> Option<WrappedDevice> {
|
||||||
|
self.devices.read().await.get(name).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn devices(&self) -> RwLockReadGuard<DeviceMap> {
|
pub async fn devices(&self) -> RwLockReadGuard<DeviceMap> {
|
||||||
self.devices.read().await
|
self.devices.read().await
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use google_home::traits;
|
use google_home::traits::OnOff;
|
||||||
use rumqttc::AsyncClient;
|
use rumqttc::AsyncClient;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tracing::{debug, error, trace, warn};
|
use tracing::{debug, error, trace, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{self, CreateDevice, MqttDeviceConfig},
|
config::{CreateDevice, MqttDeviceConfig},
|
||||||
|
device_manager::{DeviceManager, WrappedDevice},
|
||||||
|
devices::As,
|
||||||
error::CreateDeviceError,
|
error::CreateDeviceError,
|
||||||
event::EventChannel,
|
event::EventChannel,
|
||||||
event::OnMqtt,
|
event::OnMqtt,
|
||||||
|
@ -13,14 +15,14 @@ use crate::{
|
||||||
messages::{RemoteAction, RemoteMessage},
|
messages::{RemoteAction, RemoteMessage},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{As, Device};
|
use super::Device;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
pub struct AudioSetupConfig {
|
pub struct AudioSetupConfig {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
mqtt: MqttDeviceConfig,
|
mqtt: MqttDeviceConfig,
|
||||||
mixer: Box<config::DeviceConfig>,
|
mixer: String,
|
||||||
speakers: Box<config::DeviceConfig>,
|
speakers: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We need a better way to store the children devices
|
// TODO: We need a better way to store the children devices
|
||||||
|
@ -28,32 +30,48 @@ pub struct AudioSetupConfig {
|
||||||
pub struct AudioSetup {
|
pub struct AudioSetup {
|
||||||
identifier: String,
|
identifier: String,
|
||||||
mqtt: MqttDeviceConfig,
|
mqtt: MqttDeviceConfig,
|
||||||
mixer: Box<dyn traits::OnOff>,
|
mixer: WrappedDevice,
|
||||||
speakers: Box<dyn traits::OnOff>,
|
speakers: WrappedDevice,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
impl CreateDevice for AudioSetup {
|
impl CreateDevice for AudioSetup {
|
||||||
type Config = AudioSetupConfig;
|
type Config = AudioSetupConfig;
|
||||||
|
|
||||||
fn create(
|
async fn create(
|
||||||
identifier: &str,
|
identifier: &str,
|
||||||
config: Self::Config,
|
config: Self::Config,
|
||||||
event_channel: &EventChannel,
|
_event_channel: &EventChannel,
|
||||||
client: &AsyncClient,
|
_client: &AsyncClient,
|
||||||
presence_topic: &str,
|
_presence_topic: &str,
|
||||||
|
device_manager: &DeviceManager,
|
||||||
) -> Result<Self, CreateDeviceError> {
|
) -> Result<Self, CreateDeviceError> {
|
||||||
trace!(id = identifier, "Setting up AudioSetup");
|
trace!(id = identifier, "Setting up AudioSetup");
|
||||||
|
|
||||||
// Create the child devices
|
// TODO: Make sure they implement OnOff?
|
||||||
let mixer_id = format!("{}.mixer", identifier);
|
let mixer = device_manager
|
||||||
let mixer = (*config.mixer).create(&mixer_id, event_channel, client, presence_topic)?;
|
.get(&config.mixer)
|
||||||
let mixer = As::consume(mixer).ok_or(CreateDeviceError::OnOffExpected(mixer_id))?;
|
.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(CreateDeviceError::DeviceDoesNotExist(config.mixer.clone()))?;
|
||||||
|
|
||||||
let speakers_id = format!("{}.speakers", identifier);
|
{
|
||||||
let speakers =
|
let mixer = mixer.read().await;
|
||||||
(*config.speakers).create(&speakers_id, event_channel, client, presence_topic)?;
|
if As::<dyn OnOff>::cast(mixer.as_ref()).is_none() {
|
||||||
let speakers =
|
return Err(CreateDeviceError::OnOffExpected(config.mixer));
|
||||||
As::consume(speakers).ok_or(CreateDeviceError::OnOffExpected(speakers_id))?;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let speakers = device_manager.get(&config.speakers).await.ok_or(
|
||||||
|
CreateDeviceError::DeviceDoesNotExist(config.speakers.clone()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let speakers = speakers.read().await;
|
||||||
|
if As::<dyn OnOff>::cast(speakers.as_ref()).is_none() {
|
||||||
|
return Err(CreateDeviceError::OnOffExpected(config.speakers));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
identifier: identifier.to_owned(),
|
identifier: identifier.to_owned(),
|
||||||
|
@ -85,27 +103,34 @@ impl OnMqtt for AudioSetup {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match action {
|
let mut mixer = self.mixer.write().await;
|
||||||
RemoteAction::On => {
|
let mut speakers = self.speakers.write().await;
|
||||||
if self.mixer.is_on().await.unwrap() {
|
if let (Some(mixer), Some(speakers)) = (
|
||||||
self.speakers.set_on(false).await.unwrap();
|
As::<dyn OnOff>::cast_mut(mixer.as_mut()),
|
||||||
self.mixer.set_on(false).await.unwrap();
|
As::<dyn OnOff>::cast_mut(speakers.as_mut()),
|
||||||
} else {
|
) {
|
||||||
self.speakers.set_on(true).await.unwrap();
|
match action {
|
||||||
self.mixer.set_on(true).await.unwrap();
|
RemoteAction::On => {
|
||||||
}
|
if mixer.is_on().await.unwrap() {
|
||||||
},
|
speakers.set_on(false).await.unwrap();
|
||||||
RemoteAction::BrightnessMoveUp => {
|
mixer.set_on(false).await.unwrap();
|
||||||
if !self.mixer.is_on().await.unwrap() {
|
} else {
|
||||||
self.mixer.set_on(true).await.unwrap();
|
speakers.set_on(true).await.unwrap();
|
||||||
} else if self.speakers.is_on().await.unwrap() {
|
mixer.set_on(true).await.unwrap();
|
||||||
self.speakers.set_on(false).await.unwrap();
|
}
|
||||||
} else {
|
},
|
||||||
self.speakers.set_on(true).await.unwrap();
|
RemoteAction::BrightnessMoveUp => {
|
||||||
}
|
if !mixer.is_on().await.unwrap() {
|
||||||
},
|
mixer.set_on(true).await.unwrap();
|
||||||
RemoteAction::BrightnessStop => { /* Ignore this action */ },
|
} else if speakers.is_on().await.unwrap() {
|
||||||
_ => warn!("Expected ikea shortcut button which only supports 'on' and 'brightness_move_up', got: {action:?}")
|
speakers.set_on(false).await.unwrap();
|
||||||
|
} else {
|
||||||
|
speakers.set_on(true).await.unwrap();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
RemoteAction::BrightnessStop => { /* Ignore this action */ },
|
||||||
|
_ => warn!("Expected ikea shortcut button which only supports 'on' and 'brightness_move_up', got: {action:?}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,11 +138,19 @@ impl OnMqtt for AudioSetup {
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl OnPresence for AudioSetup {
|
impl OnPresence for AudioSetup {
|
||||||
async fn on_presence(&mut self, presence: bool) {
|
async fn on_presence(&mut self, presence: bool) {
|
||||||
// Turn off the audio setup when we leave the house
|
let mut mixer = self.mixer.write().await;
|
||||||
if !presence {
|
let mut speakers = self.speakers.write().await;
|
||||||
debug!(id = self.identifier, "Turning devices off");
|
|
||||||
self.speakers.set_on(false).await.unwrap();
|
if let (Some(mixer), Some(speakers)) = (
|
||||||
self.mixer.set_on(false).await.unwrap();
|
As::<dyn OnOff>::cast_mut(mixer.as_mut()),
|
||||||
|
As::<dyn OnOff>::cast_mut(speakers.as_mut()),
|
||||||
|
) {
|
||||||
|
// Turn off the audio setup when we leave the house
|
||||||
|
if !presence {
|
||||||
|
debug!(id = self.identifier, "Turning devices off");
|
||||||
|
speakers.set_on(false).await.unwrap();
|
||||||
|
mixer.set_on(false).await.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use tracing::{debug, error, trace, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{CreateDevice, MqttDeviceConfig},
|
config::{CreateDevice, MqttDeviceConfig},
|
||||||
|
device_manager::DeviceManager,
|
||||||
devices::DEFAULT_PRESENCE,
|
devices::DEFAULT_PRESENCE,
|
||||||
error::{CreateDeviceError, MissingWildcard},
|
error::{CreateDeviceError, MissingWildcard},
|
||||||
event::EventChannel,
|
event::EventChannel,
|
||||||
|
@ -72,15 +73,17 @@ pub struct ContactSensor {
|
||||||
handle: Option<JoinHandle<()>>,
|
handle: Option<JoinHandle<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
impl CreateDevice for ContactSensor {
|
impl CreateDevice for ContactSensor {
|
||||||
type Config = ContactSensorConfig;
|
type Config = ContactSensorConfig;
|
||||||
|
|
||||||
fn create(
|
async fn create(
|
||||||
identifier: &str,
|
identifier: &str,
|
||||||
config: Self::Config,
|
config: Self::Config,
|
||||||
_event_channel: &EventChannel,
|
_event_channel: &EventChannel,
|
||||||
client: &AsyncClient,
|
client: &AsyncClient,
|
||||||
presence_topic: &str,
|
presence_topic: &str,
|
||||||
|
_device_manager: &DeviceManager,
|
||||||
) -> Result<Self, CreateDeviceError> {
|
) -> Result<Self, CreateDeviceError> {
|
||||||
trace!(id = identifier, "Setting up ContactSensor");
|
trace!(id = identifier, "Setting up ContactSensor");
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ use tokio::task::JoinHandle;
|
||||||
use tracing::{debug, error, trace, warn};
|
use tracing::{debug, error, trace, warn};
|
||||||
|
|
||||||
use crate::config::{CreateDevice, InfoConfig, MqttDeviceConfig};
|
use crate::config::{CreateDevice, InfoConfig, MqttDeviceConfig};
|
||||||
|
use crate::device_manager::DeviceManager;
|
||||||
use crate::devices::Device;
|
use crate::devices::Device;
|
||||||
use crate::error::CreateDeviceError;
|
use crate::error::CreateDeviceError;
|
||||||
use crate::event::EventChannel;
|
use crate::event::EventChannel;
|
||||||
|
@ -56,15 +57,17 @@ pub struct IkeaOutlet {
|
||||||
handle: Option<JoinHandle<()>>,
|
handle: Option<JoinHandle<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
impl CreateDevice for IkeaOutlet {
|
impl CreateDevice for IkeaOutlet {
|
||||||
type Config = IkeaOutletConfig;
|
type Config = IkeaOutletConfig;
|
||||||
|
|
||||||
fn create(
|
async fn create(
|
||||||
identifier: &str,
|
identifier: &str,
|
||||||
config: Self::Config,
|
config: Self::Config,
|
||||||
_event_channel: &EventChannel,
|
_event_channel: &EventChannel,
|
||||||
client: &AsyncClient,
|
client: &AsyncClient,
|
||||||
_presence_topic: &str,
|
_presence_topic: &str,
|
||||||
|
_device_manager: &DeviceManager,
|
||||||
) -> Result<Self, CreateDeviceError> {
|
) -> Result<Self, CreateDeviceError> {
|
||||||
trace!(
|
trace!(
|
||||||
id = identifier,
|
id = identifier,
|
||||||
|
|
|
@ -18,7 +18,10 @@ use tokio::{
|
||||||
};
|
};
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
use crate::{config::CreateDevice, error::CreateDeviceError, event::EventChannel};
|
use crate::{
|
||||||
|
config::CreateDevice, device_manager::DeviceManager, error::CreateDeviceError,
|
||||||
|
event::EventChannel,
|
||||||
|
};
|
||||||
|
|
||||||
use super::Device;
|
use super::Device;
|
||||||
|
|
||||||
|
@ -33,15 +36,17 @@ pub struct KasaOutlet {
|
||||||
addr: SocketAddr,
|
addr: SocketAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
impl CreateDevice for KasaOutlet {
|
impl CreateDevice for KasaOutlet {
|
||||||
type Config = KasaOutletConfig;
|
type Config = KasaOutletConfig;
|
||||||
|
|
||||||
fn create(
|
async fn create(
|
||||||
identifier: &str,
|
identifier: &str,
|
||||||
config: Self::Config,
|
config: Self::Config,
|
||||||
_event_channel: &EventChannel,
|
_event_channel: &EventChannel,
|
||||||
_client: &AsyncClient,
|
_client: &AsyncClient,
|
||||||
_presence_topic: &str,
|
_presence_topic: &str,
|
||||||
|
_device_manager: &DeviceManager,
|
||||||
) -> Result<Self, CreateDeviceError> {
|
) -> Result<Self, CreateDeviceError> {
|
||||||
trace!(id = identifier, "Setting up KasaOutlet");
|
trace!(id = identifier, "Setting up KasaOutlet");
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ use tracing::{debug, error, trace};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{CreateDevice, InfoConfig, MqttDeviceConfig},
|
config::{CreateDevice, InfoConfig, MqttDeviceConfig},
|
||||||
|
device_manager::DeviceManager,
|
||||||
error::CreateDeviceError,
|
error::CreateDeviceError,
|
||||||
event::EventChannel,
|
event::EventChannel,
|
||||||
event::OnMqtt,
|
event::OnMqtt,
|
||||||
|
@ -47,15 +48,17 @@ pub struct WakeOnLAN {
|
||||||
broadcast_ip: Ipv4Addr,
|
broadcast_ip: Ipv4Addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
impl CreateDevice for WakeOnLAN {
|
impl CreateDevice for WakeOnLAN {
|
||||||
type Config = WakeOnLANConfig;
|
type Config = WakeOnLANConfig;
|
||||||
|
|
||||||
fn create(
|
async fn create(
|
||||||
identifier: &str,
|
identifier: &str,
|
||||||
config: Self::Config,
|
config: Self::Config,
|
||||||
_event_channel: &EventChannel,
|
_event_channel: &EventChannel,
|
||||||
_client: &AsyncClient,
|
_client: &AsyncClient,
|
||||||
_presence_topic: &str,
|
_presence_topic: &str,
|
||||||
|
_device_manager: &DeviceManager,
|
||||||
) -> Result<Self, CreateDeviceError> {
|
) -> Result<Self, CreateDeviceError> {
|
||||||
trace!(
|
trace!(
|
||||||
id = identifier,
|
id = identifier,
|
||||||
|
|
|
@ -91,6 +91,8 @@ impl MissingWildcard {
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum CreateDeviceError {
|
pub enum CreateDeviceError {
|
||||||
|
#[error("Child device '{0}' does not exist (yet?)")]
|
||||||
|
DeviceDoesNotExist(String),
|
||||||
#[error("Expected device '{0}' to implement OnOff trait")]
|
#[error("Expected device '{0}' to implement OnOff trait")]
|
||||||
OnOffExpected(String),
|
OnOffExpected(String),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -62,8 +62,15 @@ async fn app() -> anyhow::Result<()> {
|
||||||
|
|
||||||
// Create all the devices specified in the config
|
// Create all the devices specified in the config
|
||||||
for (id, device_config) in config.devices {
|
for (id, device_config) in config.devices {
|
||||||
let device =
|
let device = device_config
|
||||||
device_config.create(&id, &event_channel, &client, &config.presence.mqtt.topic)?;
|
.create(
|
||||||
|
&id,
|
||||||
|
&event_channel,
|
||||||
|
&client,
|
||||||
|
&config.presence.mqtt.topic,
|
||||||
|
&device_manager,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
device_manager.add(device).await;
|
device_manager.add(device).await;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user