Files
automation_rs/automation_devices/src/ikea_remote.rs
Dreaded_X 1532958a86 feat: Added Typed impl for all automation devices
To accomplish this a basic implementation was also provided for some
types in automation_lib
2025-10-15 00:45:37 +02:00

113 lines
3.3 KiB
Rust

use async_trait::async_trait;
use automation_lib::action_callback::ActionCallback;
use automation_lib::config::{InfoConfig, MqttDeviceConfig};
use automation_lib::device::{Device, LuaDeviceCreate};
use automation_lib::event::OnMqtt;
use automation_lib::messages::{RemoteAction, RemoteMessage};
use automation_lib::mqtt::WrappedAsyncClient;
use automation_macro::{Device, LuaDeviceConfig};
use lua_typed::Typed;
use rumqttc::{Publish, matches};
use tracing::{debug, error, trace};
#[derive(Debug, Clone, LuaDeviceConfig, Typed)]
#[typed(as = "IkeaRemoteConfig")]
pub struct Config {
#[device_config(flatten)]
#[typed(flatten)]
pub info: InfoConfig,
#[device_config(default)]
#[typed(default)]
pub single_button: bool,
#[device_config(flatten)]
#[typed(flatten)]
pub mqtt: MqttDeviceConfig,
#[device_config(from_lua)]
pub client: WrappedAsyncClient,
#[device_config(from_lua, default)]
#[typed(default)]
pub callback: ActionCallback<(IkeaRemote, bool)>,
#[device_config(from_lua, default)]
#[typed(default)]
pub battery_callback: ActionCallback<(IkeaRemote, f32)>,
}
crate::register_type!(Config);
#[derive(Debug, Clone, Device)]
pub struct IkeaRemote {
config: Config,
}
crate::register_device!(IkeaRemote);
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<Self, Self::Error> {
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
if matches(&message.topic, &self.config.mqtt.topic) {
let message = match RemoteMessage::try_from(message) {
Ok(message) => message,
Err(err) => {
error!(id = Device::get_id(self), "Failed to parse message: {err}");
return;
}
};
if let Some(action) = message.action {
debug!(id = Device::get_id(self), "Remote action = {:?}", action);
let on = if self.config.single_button {
match action {
RemoteAction::On => Some(true),
RemoteAction::BrightnessMoveUp => Some(false),
_ => None,
}
} else {
match action {
RemoteAction::On => Some(true),
RemoteAction::Off => Some(false),
_ => None,
}
};
if let Some(on) = on {
self.config.callback.call((self.clone(), on)).await;
}
}
if let Some(battery) = message.battery {
self.config
.battery_callback
.call((self.clone(), battery))
.await;
}
}
}
}