diff --git a/src/devices/ikea_remote.rs b/src/devices/ikea_remote.rs new file mode 100644 index 0000000..0f8d236 --- /dev/null +++ b/src/devices/ikea_remote.rs @@ -0,0 +1,94 @@ +use automation_macro::LuaDeviceConfig; +use axum::async_trait; +use rumqttc::{matches, Publish}; +use tracing::{debug, error, trace}; + +use super::LuaDeviceCreate; +use crate::action_callback::ActionCallback; +use crate::config::{InfoConfig, MqttDeviceConfig}; +use crate::devices::Device; +use crate::event::OnMqtt; +use crate::messages::RemoteMessage; +use crate::mqtt::WrappedAsyncClient; + +#[derive(Debug, Clone, LuaDeviceConfig)] +pub struct Config { + #[device_config(flatten)] + pub info: InfoConfig, + + #[device_config(default)] + pub single_button: bool, + + #[device_config(flatten)] + pub mqtt: MqttDeviceConfig, + + #[device_config(from_lua)] + pub client: WrappedAsyncClient, + + #[device_config(from_lua)] + pub callback: ActionCallback, +} + +#[derive(Debug, Clone)] +pub struct IkeaRemote { + config: Config, +} + +impl Device for IkeaRemote { + fn get_id(&self) -> String { + self.config.info.identifier() + } +} + +#[async_trait] +impl LuaDeviceCreate for IkeaRemote { + type Config = Config; + type Error = rumqttc::ClientError; + + async fn create(config: Self::Config) -> Result { + trace!(id = config.info.identifier(), "Setting up IkeaRemote"); + + config + .client + .subscribe(&config.mqtt.topic, rumqttc::QoS::AtLeastOnce) + .await?; + + Ok(Self { config }) + } +} + +#[async_trait] +impl OnMqtt for IkeaRemote { + async fn on_mqtt(&self, message: Publish) { + // Check if the message is from the deviec itself or from a remote + debug!(id = Device::get_id(self), "Mqtt message received"); + if matches(&message.topic, &self.config.mqtt.topic) { + let action = match RemoteMessage::try_from(message) { + Ok(message) => message.action(), + Err(err) => { + error!(id = Device::get_id(self), "Failed to parse message: {err}"); + return; + } + }; + debug!(id = Device::get_id(self), "Remote action = {:?}", action); + + let on = if self.config.single_button { + match action { + crate::messages::RemoteAction::On => Some(true), + crate::messages::RemoteAction::BrightnessMoveUp => Some(false), + _ => None, + } + } else { + match action { + crate::messages::RemoteAction::On => Some(true), + crate::messages::RemoteAction::Off => Some(false), + _ => None, + } + }; + + if let Some(on) = on { + self.config.callback.call(on).await; + } + } + } +} diff --git a/src/devices/mod.rs b/src/devices/mod.rs index 6281992..597e52b 100644 --- a/src/devices/mod.rs +++ b/src/devices/mod.rs @@ -5,6 +5,7 @@ mod debug_bridge; mod hue_bridge; mod hue_group; mod ikea_outlet; +mod ikea_remote; mod kasa_outlet; mod light_sensor; mod ntfy; @@ -28,6 +29,7 @@ pub use self::debug_bridge::DebugBridge; pub use self::hue_bridge::HueBridge; pub use self::hue_group::HueGroup; pub use self::ikea_outlet::IkeaOutlet; +pub use self::ikea_remote::IkeaRemote; pub use self::kasa_outlet::KasaOutlet; pub use self::light_sensor::LightSensor; pub use self::ntfy::{Notification, Ntfy}; @@ -104,6 +106,7 @@ impl_device!(DebugBridge); impl_device!(HueBridge); impl_device!(HueGroup); impl_device!(IkeaOutlet); +impl_device!(IkeaRemote); impl_device!(KasaOutlet); impl_device!(LightSensor); impl_device!(Ntfy); @@ -119,6 +122,7 @@ pub fn register_with_lua(lua: &mlua::Lua) -> mlua::Result<()> { register_device!(lua, HueBridge); register_device!(lua, HueGroup); register_device!(lua, IkeaOutlet); + register_device!(lua, IkeaRemote); register_device!(lua, KasaOutlet); register_device!(lua, LightSensor); register_device!(lua, Ntfy);