From 41d2af655b64394cb19b7acdd329f4e559e91ec9 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Sun, 8 Dec 2024 02:50:52 +0100 Subject: [PATCH] ActionCallback now always returns self and state can be anything serializable --- automation_devices/src/contact_sensor.rs | 4 ++-- automation_devices/src/hue_switch.rs | 14 ++++++++---- automation_devices/src/ikea_outlet.rs | 4 ++-- automation_devices/src/ikea_remote.rs | 4 ++-- automation_lib/src/action_callback.rs | 29 +++++++++++++++--------- automation_lib/src/helpers/timeout.rs | 4 ++-- config.lua | 10 ++++---- 7 files changed, 40 insertions(+), 29 deletions(-) diff --git a/automation_devices/src/contact_sensor.rs b/automation_devices/src/contact_sensor.rs index 630a8bc..935b07b 100644 --- a/automation_devices/src/contact_sensor.rs +++ b/automation_devices/src/contact_sensor.rs @@ -32,7 +32,7 @@ pub struct Config { #[device_config(from_lua, default)] pub presence: Option, #[device_config(from_lua, default)] - pub callback: ActionCallback, + pub callback: ActionCallback, #[device_config(from_lua)] pub client: WrappedAsyncClient, } @@ -116,7 +116,7 @@ impl OnMqtt for ContactSensor { return; } - self.config.callback.call(!is_closed).await; + self.config.callback.call(self, &!is_closed).await; debug!(id = self.get_id(), "Updating state to {is_closed}"); self.state_mut().await.is_closed = is_closed; diff --git a/automation_devices/src/hue_switch.rs b/automation_devices/src/hue_switch.rs index ce94b73..14ae990 100644 --- a/automation_devices/src/hue_switch.rs +++ b/automation_devices/src/hue_switch.rs @@ -21,10 +21,10 @@ pub struct Config { pub client: WrappedAsyncClient, #[device_config(from_lua, default)] - pub left_callback: ActionCallback<()>, + pub left_callback: ActionCallback, #[device_config(from_lua, default)] - pub right_callback: ActionCallback<()>, + pub right_callback: ActionCallback, } #[derive(Debug, Clone)] @@ -58,7 +58,7 @@ impl LuaDeviceCreate for HueSwitch { #[async_trait] impl OnMqtt for HueSwitch { async fn on_mqtt(&self, message: Publish) { - // Check if the message is from the deviec itself or from a remote + // Check if the message is from the device itself or from a remote if matches(&message.topic, &self.config.mqtt.topic) { let action = match serde_json::from_slice::(&message.payload) { Ok(message) => message.action, @@ -70,8 +70,12 @@ impl OnMqtt for HueSwitch { debug!(id = Device::get_id(self), "Remote action = {:?}", action); match action { - Zigbee929003017102Action::LeftPress => self.config.left_callback.call(()).await, - Zigbee929003017102Action::RightPress => self.config.right_callback.call(()).await, + Zigbee929003017102Action::LeftPress => { + self.config.left_callback.call(self, &()).await + } + Zigbee929003017102Action::RightPress => { + self.config.right_callback.call(self, &()).await + } _ => {} } } diff --git a/automation_devices/src/ikea_outlet.rs b/automation_devices/src/ikea_outlet.rs index c309efd..6e200ef 100644 --- a/automation_devices/src/ikea_outlet.rs +++ b/automation_devices/src/ikea_outlet.rs @@ -36,7 +36,7 @@ pub struct Config { pub outlet_type: OutletType, #[device_config(from_lua, default)] - pub callback: ActionCallback<(IkeaOutlet, bool)>, + pub callback: ActionCallback, #[device_config(from_lua)] pub client: WrappedAsyncClient, @@ -109,7 +109,7 @@ impl OnMqtt for IkeaOutlet { return; } - self.config.callback.call((self.clone(), state)).await; + self.config.callback.call(self, &state).await; debug!(id = Device::get_id(self), "Updating state to {state}"); self.state_mut().await.last_known_state = state; diff --git a/automation_devices/src/ikea_remote.rs b/automation_devices/src/ikea_remote.rs index b2995f9..c81c508 100644 --- a/automation_devices/src/ikea_remote.rs +++ b/automation_devices/src/ikea_remote.rs @@ -24,7 +24,7 @@ pub struct Config { pub client: WrappedAsyncClient, #[device_config(from_lua)] - pub callback: ActionCallback, + pub callback: ActionCallback, } #[derive(Debug, Clone)] @@ -84,7 +84,7 @@ impl OnMqtt for IkeaRemote { }; if let Some(on) = on { - self.config.callback.call(on).await; + self.config.callback.call(self, &on).await; } } } diff --git a/automation_lib/src/action_callback.rs b/automation_lib/src/action_callback.rs index fe21dbb..0d6fa93 100644 --- a/automation_lib/src/action_callback.rs +++ b/automation_lib/src/action_callback.rs @@ -1,6 +1,7 @@ use std::marker::PhantomData; -use mlua::{FromLua, IntoLuaMulti}; +use mlua::{FromLua, IntoLua, LuaSerdeExt}; +use serde::Serialize; #[derive(Debug, Clone)] struct Internal { @@ -9,21 +10,23 @@ struct Internal { } #[derive(Debug, Clone)] -pub struct ActionCallback { +pub struct ActionCallback { internal: Option, - phantom: PhantomData, + _this: PhantomData, + _state: PhantomData, } -impl Default for ActionCallback { +impl Default for ActionCallback { fn default() -> Self { Self { internal: None, - phantom: PhantomData::, + _this: PhantomData::, + _state: PhantomData::, } } } -impl FromLua for ActionCallback { +impl FromLua for ActionCallback { fn from_lua(value: mlua::Value, lua: &mlua::Lua) -> mlua::Result { let uuid = uuid::Uuid::new_v4(); lua.set_named_registry_value(&uuid.to_string(), value)?; @@ -33,27 +36,31 @@ impl FromLua for ActionCallback { uuid, lua: lua.clone(), }), - phantom: PhantomData::, + _this: PhantomData::, + _state: PhantomData::, }) } } // TODO: Return proper error here -impl ActionCallback +impl ActionCallback where - T: IntoLuaMulti + Sync + Send + Clone + 'static, + T: IntoLua + Sync + Send + Clone + 'static, + S: Serialize, { - pub async fn call(&self, state: T) { + pub async fn call(&self, this: &T, state: &S) { let Some(internal) = self.internal.as_ref() else { return; }; + let state = internal.lua.to_value(state).unwrap(); + let callback: mlua::Value = internal .lua .named_registry_value(&internal.uuid.to_string()) .unwrap(); match callback { - mlua::Value::Function(f) => f.call_async::<()>(state).await.unwrap(), + mlua::Value::Function(f) => f.call_async::<()>((this.clone(), state)).await.unwrap(), _ => todo!("Only functions are currently supported"), } } diff --git a/automation_lib/src/helpers/timeout.rs b/automation_lib/src/helpers/timeout.rs index 3432fed..a33cbb1 100644 --- a/automation_lib/src/helpers/timeout.rs +++ b/automation_lib/src/helpers/timeout.rs @@ -29,7 +29,7 @@ impl mlua::UserData for Timeout { methods.add_async_method( "start", - |_lua, this, (timeout, callback): (u64, ActionCallback)| async move { + |_lua, this, (timeout, callback): (u64, ActionCallback)| async move { if let Some(handle) = this.state.write().await.handle.take() { handle.abort(); } @@ -42,7 +42,7 @@ impl mlua::UserData for Timeout { async move { tokio::time::sleep(timeout).await; - callback.call(false).await; + callback.call(&mlua::Nil, &false).await; } })); diff --git a/config.lua b/config.lua index 5b3131d..4b9b711 100644 --- a/config.lua +++ b/config.lua @@ -90,7 +90,7 @@ automation.device_manager:add(IkeaRemote.new({ client = mqtt_client, topic = mqtt_z2m("living/remote"), single_button = true, - callback = function(on) + callback = function(_, on) if on then if living_mixer:is_on() then living_mixer:set_on(false) @@ -133,7 +133,7 @@ local kettle = IkeaOutlet.new({ }) automation.device_manager:add(kettle) -local function set_kettle(on) +local function set_kettle(_, on) kettle:set_on(on) end @@ -269,7 +269,7 @@ automation.device_manager:add(IkeaRemote.new({ room = "Hallway", client = mqtt_client, topic = mqtt_z2m("hallway/remote"), - callback = function(on) + callback = function(_, on) hallway_light_automation:switch_callback(on) end, })) @@ -281,7 +281,7 @@ automation.device_manager:add(ContactSensor.new({ topic = mqtt_automation("presence/contact/frontdoor"), timeout = debug and 10 or 15 * 60, }, - callback = function(open) + callback = function(_, open) hallway_light_automation:door_callback(open) end, })) @@ -289,7 +289,7 @@ automation.device_manager:add(ContactSensor.new({ identifier = "hallway_trash", topic = mqtt_z2m("hallway/trash"), client = mqtt_client, - callback = function(open) + callback = function(_, open) hallway_light_automation:trash_callback(open) end, }))