Replaced impl_cast with a new and improved trait
With this trait the impl_cast macros are no longer needed, simplifying everything. This commit also improved how the actual casting itself is handled.
This commit is contained in:
@@ -12,7 +12,7 @@ use tokio_cron_scheduler::{Job, JobScheduler};
|
||||
use tracing::{debug, error, instrument, trace};
|
||||
|
||||
use crate::devices::{
|
||||
AirFilterConfig, As, AudioSetupConfig, ContactSensorConfig, DebugBridgeConfig, Device,
|
||||
AirFilterConfig, AudioSetupConfig, ContactSensorConfig, DebugBridgeConfig, Device,
|
||||
HueBridgeConfig, HueGroupConfig, IkeaOutletConfig, KasaOutletConfig, LightSensorConfig,
|
||||
WakeOnLANConfig, WasherConfig,
|
||||
};
|
||||
@@ -106,22 +106,22 @@ impl DeviceManager {
|
||||
let device = manager.get(&target).await.unwrap();
|
||||
match action {
|
||||
Action::On => {
|
||||
As::<dyn OnOff>::cast_mut(
|
||||
device.write().await.as_mut(),
|
||||
)
|
||||
.unwrap()
|
||||
.set_on(true)
|
||||
.await
|
||||
.unwrap();
|
||||
let mut device = device.write().await;
|
||||
let device: Option<&mut dyn OnOff> =
|
||||
device.as_mut().cast_mut();
|
||||
|
||||
if let Some(device) = device {
|
||||
device.set_on(true).await.unwrap();
|
||||
}
|
||||
}
|
||||
Action::Off => {
|
||||
As::<dyn OnOff>::cast_mut(
|
||||
device.write().await.as_mut(),
|
||||
)
|
||||
.unwrap()
|
||||
.set_on(false)
|
||||
.await
|
||||
.unwrap();
|
||||
let mut device = device.write().await;
|
||||
let device: Option<&mut dyn OnOff> =
|
||||
device.as_mut().cast_mut();
|
||||
|
||||
if let Some(device) = device {
|
||||
device.set_on(false).await.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,14 +142,17 @@ impl DeviceManager {
|
||||
|
||||
debug!(id, "Adding device");
|
||||
|
||||
// If the device listens to mqtt, subscribe to the topics
|
||||
if let Some(device) = As::<dyn OnMqtt>::cast(device.as_ref()) {
|
||||
for topic in device.topics() {
|
||||
trace!(id, topic, "Subscribing to topic");
|
||||
if let Err(err) = self.client.subscribe(topic, QoS::AtLeastOnce).await {
|
||||
// NOTE: Pretty sure that this can only happen if the mqtt client if no longer
|
||||
// running
|
||||
error!(id, topic, "Failed to subscribe to topic: {err}");
|
||||
{
|
||||
// If the device listens to mqtt, subscribe to the topics
|
||||
let device: Option<&dyn OnMqtt> = device.as_ref().cast();
|
||||
if let Some(device) = device {
|
||||
for topic in device.topics() {
|
||||
trace!(id, topic, "Subscribing to topic");
|
||||
if let Err(err) = self.client.subscribe(topic, QoS::AtLeastOnce).await {
|
||||
// NOTE: Pretty sure that this can only happen if the mqtt client if no longer
|
||||
// running
|
||||
error!(id, topic, "Failed to subscribe to topic: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,8 +202,8 @@ impl DeviceManager {
|
||||
let message = message.clone();
|
||||
async move {
|
||||
let mut device = device.write().await;
|
||||
let device = device.as_mut();
|
||||
if let Some(device) = As::<dyn OnMqtt>::cast_mut(device) {
|
||||
let device: Option<&mut dyn OnMqtt> = device.as_mut().cast_mut();
|
||||
if let Some(device) = device {
|
||||
let subscribed = device
|
||||
.topics()
|
||||
.iter()
|
||||
@@ -220,8 +223,8 @@ impl DeviceManager {
|
||||
let devices = self.devices.read().await;
|
||||
let iter = devices.iter().map(|(id, device)| async move {
|
||||
let mut device = device.write().await;
|
||||
let device = device.as_mut();
|
||||
if let Some(device) = As::<dyn OnDarkness>::cast_mut(device) {
|
||||
let device: Option<&mut dyn OnDarkness> = device.as_mut().cast_mut();
|
||||
if let Some(device) = device {
|
||||
trace!(id, "Handling");
|
||||
device.on_darkness(dark).await;
|
||||
}
|
||||
@@ -233,8 +236,8 @@ impl DeviceManager {
|
||||
let devices = self.devices.read().await;
|
||||
let iter = devices.iter().map(|(id, device)| async move {
|
||||
let mut device = device.write().await;
|
||||
let device = device.as_mut();
|
||||
if let Some(device) = As::<dyn OnPresence>::cast_mut(device) {
|
||||
let device: Option<&mut dyn OnPresence> = device.as_mut().cast_mut();
|
||||
if let Some(device) = device {
|
||||
trace!(id, "Handling");
|
||||
device.on_presence(presence).await;
|
||||
}
|
||||
@@ -248,8 +251,8 @@ impl DeviceManager {
|
||||
let notification = notification.clone();
|
||||
async move {
|
||||
let mut device = device.write().await;
|
||||
let device = device.as_mut();
|
||||
if let Some(device) = As::<dyn OnNotification>::cast_mut(device) {
|
||||
let device: Option<&mut dyn OnNotification> = device.as_mut().cast_mut();
|
||||
if let Some(device) = device {
|
||||
trace!(id, "Handling");
|
||||
device.on_notification(notification).await;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ use tracing::{debug, error, trace, warn};
|
||||
use super::Device;
|
||||
use crate::config::MqttDeviceConfig;
|
||||
use crate::device_manager::{ConfigExternal, DeviceConfig, WrappedDevice};
|
||||
use crate::devices::As;
|
||||
use crate::error::DeviceConfigError;
|
||||
use crate::event::{OnMqtt, OnPresence};
|
||||
use crate::messages::{RemoteAction, RemoteMessage};
|
||||
@@ -39,8 +38,11 @@ impl DeviceConfig for AudioSetupConfig {
|
||||
self.mixer.clone(),
|
||||
))?;
|
||||
|
||||
if !As::<dyn OnOff>::is(mixer.read().await.as_ref()) {
|
||||
return Err(DeviceConfigError::MissingTrait(self.mixer, "OnOff".into()));
|
||||
{
|
||||
let mixer = mixer.read().await;
|
||||
if (mixer.as_ref().cast() as Option<&dyn OnOff>).is_none() {
|
||||
return Err(DeviceConfigError::MissingTrait(self.mixer, "OnOff".into()));
|
||||
}
|
||||
}
|
||||
|
||||
let speakers =
|
||||
@@ -52,11 +54,11 @@ impl DeviceConfig for AudioSetupConfig {
|
||||
self.speakers.clone(),
|
||||
))?;
|
||||
|
||||
if !As::<dyn OnOff>::is(speakers.read().await.as_ref()) {
|
||||
return Err(DeviceConfigError::MissingTrait(
|
||||
self.speakers,
|
||||
"OnOff".into(),
|
||||
));
|
||||
{
|
||||
let speakers = speakers.read().await;
|
||||
if (speakers.as_ref().cast() as Option<&dyn OnOff>).is_none() {
|
||||
return Err(DeviceConfigError::MissingTrait(self.mixer, "OnOff".into()));
|
||||
}
|
||||
}
|
||||
|
||||
let device = AudioSetup {
|
||||
@@ -103,8 +105,8 @@ impl OnMqtt for AudioSetup {
|
||||
let mut mixer = self.mixer.write().await;
|
||||
let mut speakers = self.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()),
|
||||
mixer.as_mut().cast_mut() as Option<&mut dyn OnOff>,
|
||||
speakers.as_mut().cast_mut() as Option<&mut dyn OnOff>,
|
||||
) {
|
||||
match action {
|
||||
RemoteAction::On => {
|
||||
@@ -137,10 +139,9 @@ 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;
|
||||
|
||||
if let (Some(mixer), Some(speakers)) = (
|
||||
As::<dyn OnOff>::cast_mut(mixer.as_mut()),
|
||||
As::<dyn OnOff>::cast_mut(speakers.as_mut()),
|
||||
mixer.as_mut().cast_mut() as Option<&mut dyn OnOff>,
|
||||
speakers.as_mut().cast_mut() as Option<&mut dyn OnOff>,
|
||||
) {
|
||||
// Turn off the audio setup when we leave the house
|
||||
if !presence {
|
||||
|
||||
@@ -11,7 +11,7 @@ use tracing::{debug, error, trace, warn};
|
||||
use super::Device;
|
||||
use crate::config::MqttDeviceConfig;
|
||||
use crate::device_manager::{ConfigExternal, DeviceConfig, WrappedDevice};
|
||||
use crate::devices::{As, DEFAULT_PRESENCE};
|
||||
use crate::devices::DEFAULT_PRESENCE;
|
||||
use crate::error::DeviceConfigError;
|
||||
use crate::event::{OnMqtt, OnPresence};
|
||||
use crate::messages::{ContactMessage, PresenceMessage};
|
||||
@@ -60,20 +60,23 @@ impl DeviceConfig for ContactSensorConfig {
|
||||
DeviceConfigError::MissingChild(device_name.into(), "OnOff".into()),
|
||||
)?;
|
||||
|
||||
if !As::<dyn OnOff>::is(device.read().await.as_ref()) {
|
||||
return Err(DeviceConfigError::MissingTrait(
|
||||
device_name.into(),
|
||||
"OnOff".into(),
|
||||
));
|
||||
}
|
||||
|
||||
if !trigger_config.timeout.is_zero()
|
||||
&& !As::<dyn Timeout>::is(device.read().await.as_ref())
|
||||
{
|
||||
return Err(DeviceConfigError::MissingTrait(
|
||||
device_name.into(),
|
||||
"Timeout".into(),
|
||||
));
|
||||
let device = device.read().await;
|
||||
if (device.as_ref().cast() as Option<&dyn OnOff>).is_none() {
|
||||
return Err(DeviceConfigError::MissingTrait(
|
||||
device_name.into(),
|
||||
"OnOff".into(),
|
||||
));
|
||||
}
|
||||
|
||||
if trigger_config.timeout.is_zero()
|
||||
&& (device.as_ref().cast() as Option<&dyn Timeout>).is_none()
|
||||
{
|
||||
return Err(DeviceConfigError::MissingTrait(
|
||||
device_name.into(),
|
||||
"Timeout".into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
devices.push((device, false));
|
||||
@@ -161,7 +164,7 @@ impl OnMqtt for ContactSensor {
|
||||
if !self.is_closed {
|
||||
for (light, previous) in &mut trigger.devices {
|
||||
let mut light = light.write().await;
|
||||
if let Some(light) = As::<dyn OnOff>::cast_mut(light.as_mut()) {
|
||||
if let Some(light) = light.as_mut().cast_mut() as Option<&mut dyn OnOff> {
|
||||
*previous = light.is_on().await.unwrap();
|
||||
light.set_on(true).await.ok();
|
||||
}
|
||||
@@ -172,10 +175,12 @@ impl OnMqtt for ContactSensor {
|
||||
if !previous {
|
||||
// If the timeout is zero just turn the light off directly
|
||||
if trigger.timeout.is_zero()
|
||||
&& let Some(light) = As::<dyn OnOff>::cast_mut(light.as_mut())
|
||||
&& let Some(light) = light.as_mut().cast_mut() as Option<&mut dyn OnOff>
|
||||
{
|
||||
light.set_on(false).await.ok();
|
||||
} else if let Some(light) = As::<dyn Timeout>::cast_mut(light.as_mut()) {
|
||||
} else if let Some(light) =
|
||||
light.as_mut().cast_mut() as Option<&mut dyn Timeout>
|
||||
{
|
||||
light.start_timeout(trigger.timeout).await.unwrap();
|
||||
}
|
||||
// TODO: Put a warning/error on creation if either of this has to option to fail
|
||||
|
||||
@@ -12,8 +12,11 @@ mod presence;
|
||||
mod wake_on_lan;
|
||||
mod washer;
|
||||
|
||||
use google_home::device::AsGoogleHomeDevice;
|
||||
use std::fmt::Debug;
|
||||
|
||||
use automation_cast::Cast;
|
||||
use google_home::traits::OnOff;
|
||||
use google_home::GoogleHomeDevice;
|
||||
|
||||
pub use self::air_filter::AirFilterConfig;
|
||||
pub use self::audio_setup::AudioSetupConfig;
|
||||
@@ -31,7 +34,18 @@ pub use self::washer::WasherConfig;
|
||||
use crate::event::{OnDarkness, OnMqtt, OnNotification, OnPresence};
|
||||
use crate::traits::Timeout;
|
||||
|
||||
#[impl_cast::device(As: OnMqtt + OnPresence + OnDarkness + OnNotification + OnOff + Timeout)]
|
||||
pub trait Device: AsGoogleHomeDevice + std::fmt::Debug + Sync + Send {
|
||||
pub trait Device:
|
||||
Debug
|
||||
+ Sync
|
||||
+ Send
|
||||
+ Cast<dyn GoogleHomeDevice>
|
||||
+ Cast<dyn OnMqtt>
|
||||
+ Cast<dyn OnMqtt>
|
||||
+ Cast<dyn OnPresence>
|
||||
+ Cast<dyn OnDarkness>
|
||||
+ Cast<dyn OnNotification>
|
||||
+ Cast<dyn OnOff>
|
||||
+ Cast<dyn Timeout>
|
||||
{
|
||||
fn get_id(&self) -> &str;
|
||||
}
|
||||
|
||||
13
src/event.rs
13
src/event.rs
@@ -1,5 +1,4 @@
|
||||
use async_trait::async_trait;
|
||||
use impl_cast::device_trait;
|
||||
use rumqttc::Publish;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
@@ -32,26 +31,22 @@ impl EventChannel {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
#[device_trait]
|
||||
pub trait OnMqtt {
|
||||
pub trait OnMqtt: Sync + Send {
|
||||
fn topics(&self) -> Vec<&str>;
|
||||
async fn on_mqtt(&mut self, message: Publish);
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
#[device_trait]
|
||||
pub trait OnPresence {
|
||||
pub trait OnPresence: Sync + Send {
|
||||
async fn on_presence(&mut self, presence: bool);
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
#[device_trait]
|
||||
pub trait OnDarkness {
|
||||
pub trait OnDarkness: Sync + Send {
|
||||
async fn on_darkness(&mut self, dark: bool);
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
#[device_trait]
|
||||
pub trait OnNotification {
|
||||
pub trait OnNotification: Sync + Send {
|
||||
async fn on_notification(&mut self, notification: Notification);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,9 @@ use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use impl_cast::device_trait;
|
||||
|
||||
#[async_trait]
|
||||
#[device_trait]
|
||||
pub trait Timeout {
|
||||
pub trait Timeout: Sync + Send {
|
||||
async fn start_timeout(&mut self, _timeout: Duration) -> Result<()>;
|
||||
async fn stop_timeout(&mut self) -> Result<()>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user