automation_rs/src/devices/audio_setup.rs
Dreaded_X 522fe27f11
Some checks failed
continuous-integration/drone/push Build is failing
Converted google home traits to be async
2023-08-11 03:46:44 +02:00

124 lines
3.8 KiB
Rust

use async_trait::async_trait;
use google_home::traits;
use rumqttc::AsyncClient;
use serde::Deserialize;
use tracing::{debug, error, trace, warn};
use crate::{
config::{self, CreateDevice, MqttDeviceConfig},
error::CreateDeviceError,
event::EventChannel,
event::OnMqtt,
event::OnPresence,
messages::{RemoteAction, RemoteMessage},
};
use super::{As, Device};
#[derive(Debug, Clone, Deserialize)]
pub struct AudioSetupConfig {
#[serde(flatten)]
mqtt: MqttDeviceConfig,
mixer: Box<config::DeviceConfig>,
speakers: Box<config::DeviceConfig>,
}
// TODO: We need a better way to store the children devices
#[derive(Debug)]
pub struct AudioSetup {
identifier: String,
mqtt: MqttDeviceConfig,
mixer: Box<dyn traits::OnOff>,
speakers: Box<dyn traits::OnOff>,
}
impl CreateDevice for AudioSetup {
type Config = AudioSetupConfig;
fn create(
identifier: &str,
config: Self::Config,
event_channel: &EventChannel,
client: &AsyncClient,
presence_topic: &str,
) -> Result<Self, CreateDeviceError> {
trace!(id = identifier, "Setting up AudioSetup");
// Create the child devices
let mixer_id = format!("{}.mixer", identifier);
let mixer = (*config.mixer).create(&mixer_id, event_channel, client, presence_topic)?;
let mixer = As::consume(mixer).ok_or(CreateDeviceError::OnOffExpected(mixer_id))?;
let speakers_id = format!("{}.speakers", identifier);
let speakers =
(*config.speakers).create(&speakers_id, event_channel, client, presence_topic)?;
let speakers =
As::consume(speakers).ok_or(CreateDeviceError::OnOffExpected(speakers_id))?;
Ok(Self {
identifier: identifier.to_owned(),
mqtt: config.mqtt,
mixer,
speakers,
})
}
}
impl Device for AudioSetup {
fn get_id(&self) -> &str {
&self.identifier
}
}
#[async_trait]
impl OnMqtt for AudioSetup {
fn topics(&self) -> Vec<&str> {
vec![&self.mqtt.topic]
}
async fn on_mqtt(&mut self, message: rumqttc::Publish) {
let action = match RemoteMessage::try_from(message) {
Ok(message) => message.action(),
Err(err) => {
error!(id = self.identifier, "Failed to parse message: {err}");
return;
}
};
match action {
RemoteAction::On => {
if self.mixer.is_on().await.unwrap() {
self.speakers.set_on(false).await.unwrap();
self.mixer.set_on(false).await.unwrap();
} else {
self.speakers.set_on(true).await.unwrap();
self.mixer.set_on(true).await.unwrap();
}
},
RemoteAction::BrightnessMoveUp => {
if !self.mixer.is_on().await.unwrap() {
self.mixer.set_on(true).await.unwrap();
} else if self.speakers.is_on().await.unwrap() {
self.speakers.set_on(false).await.unwrap();
} else {
self.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:?}")
}
}
}
#[async_trait]
impl OnPresence for AudioSetup {
async fn on_presence(&mut self, presence: bool) {
// Turn off the audio setup when we leave the house
if !presence {
debug!(id = self.identifier, "Turning devices off");
self.speakers.set_on(false).await.unwrap();
self.mixer.set_on(false).await.unwrap();
}
}
}