ActionCallback now always returns self and state can be anything serializable

This commit is contained in:
Dreaded_X 2024-12-08 02:50:52 +01:00
parent eefb476d7f
commit 41d2af655b
Signed by: Dreaded_X
GPG Key ID: FA5F485356B0D2D4
7 changed files with 40 additions and 29 deletions

View File

@ -32,7 +32,7 @@ pub struct Config {
#[device_config(from_lua, default)] #[device_config(from_lua, default)]
pub presence: Option<PresenceDeviceConfig>, pub presence: Option<PresenceDeviceConfig>,
#[device_config(from_lua, default)] #[device_config(from_lua, default)]
pub callback: ActionCallback<bool>, pub callback: ActionCallback<ContactSensor, bool>,
#[device_config(from_lua)] #[device_config(from_lua)]
pub client: WrappedAsyncClient, pub client: WrappedAsyncClient,
} }
@ -116,7 +116,7 @@ impl OnMqtt for ContactSensor {
return; 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}"); debug!(id = self.get_id(), "Updating state to {is_closed}");
self.state_mut().await.is_closed = is_closed; self.state_mut().await.is_closed = is_closed;

View File

@ -21,10 +21,10 @@ pub struct Config {
pub client: WrappedAsyncClient, pub client: WrappedAsyncClient,
#[device_config(from_lua, default)] #[device_config(from_lua, default)]
pub left_callback: ActionCallback<()>, pub left_callback: ActionCallback<HueSwitch, ()>,
#[device_config(from_lua, default)] #[device_config(from_lua, default)]
pub right_callback: ActionCallback<()>, pub right_callback: ActionCallback<HueSwitch, ()>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -58,7 +58,7 @@ impl LuaDeviceCreate for HueSwitch {
#[async_trait] #[async_trait]
impl OnMqtt for HueSwitch { impl OnMqtt for HueSwitch {
async fn on_mqtt(&self, message: Publish) { 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) { if matches(&message.topic, &self.config.mqtt.topic) {
let action = match serde_json::from_slice::<Zigbee929003017102>(&message.payload) { let action = match serde_json::from_slice::<Zigbee929003017102>(&message.payload) {
Ok(message) => message.action, Ok(message) => message.action,
@ -70,8 +70,12 @@ impl OnMqtt for HueSwitch {
debug!(id = Device::get_id(self), "Remote action = {:?}", action); debug!(id = Device::get_id(self), "Remote action = {:?}", action);
match action { match action {
Zigbee929003017102Action::LeftPress => self.config.left_callback.call(()).await, Zigbee929003017102Action::LeftPress => {
Zigbee929003017102Action::RightPress => self.config.right_callback.call(()).await, self.config.left_callback.call(self, &()).await
}
Zigbee929003017102Action::RightPress => {
self.config.right_callback.call(self, &()).await
}
_ => {} _ => {}
} }
} }

View File

@ -36,7 +36,7 @@ pub struct Config {
pub outlet_type: OutletType, pub outlet_type: OutletType,
#[device_config(from_lua, default)] #[device_config(from_lua, default)]
pub callback: ActionCallback<(IkeaOutlet, bool)>, pub callback: ActionCallback<IkeaOutlet, bool>,
#[device_config(from_lua)] #[device_config(from_lua)]
pub client: WrappedAsyncClient, pub client: WrappedAsyncClient,
@ -109,7 +109,7 @@ impl OnMqtt for IkeaOutlet {
return; 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}"); debug!(id = Device::get_id(self), "Updating state to {state}");
self.state_mut().await.last_known_state = state; self.state_mut().await.last_known_state = state;

View File

@ -24,7 +24,7 @@ pub struct Config {
pub client: WrappedAsyncClient, pub client: WrappedAsyncClient,
#[device_config(from_lua)] #[device_config(from_lua)]
pub callback: ActionCallback<bool>, pub callback: ActionCallback<IkeaRemote, bool>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -84,7 +84,7 @@ impl OnMqtt for IkeaRemote {
}; };
if let Some(on) = on { if let Some(on) = on {
self.config.callback.call(on).await; self.config.callback.call(self, &on).await;
} }
} }
} }

View File

@ -1,6 +1,7 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use mlua::{FromLua, IntoLuaMulti}; use mlua::{FromLua, IntoLua, LuaSerdeExt};
use serde::Serialize;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Internal { struct Internal {
@ -9,21 +10,23 @@ struct Internal {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ActionCallback<T> { pub struct ActionCallback<T, S> {
internal: Option<Internal>, internal: Option<Internal>,
phantom: PhantomData<T>, _this: PhantomData<T>,
_state: PhantomData<S>,
} }
impl<T> Default for ActionCallback<T> { impl<T, S> Default for ActionCallback<T, S> {
fn default() -> Self { fn default() -> Self {
Self { Self {
internal: None, internal: None,
phantom: PhantomData::<T>, _this: PhantomData::<T>,
_state: PhantomData::<S>,
} }
} }
} }
impl<T> FromLua for ActionCallback<T> { impl<T, S> FromLua for ActionCallback<T, S> {
fn from_lua(value: mlua::Value, lua: &mlua::Lua) -> mlua::Result<Self> { fn from_lua(value: mlua::Value, lua: &mlua::Lua) -> mlua::Result<Self> {
let uuid = uuid::Uuid::new_v4(); let uuid = uuid::Uuid::new_v4();
lua.set_named_registry_value(&uuid.to_string(), value)?; lua.set_named_registry_value(&uuid.to_string(), value)?;
@ -33,27 +36,31 @@ impl<T> FromLua for ActionCallback<T> {
uuid, uuid,
lua: lua.clone(), lua: lua.clone(),
}), }),
phantom: PhantomData::<T>, _this: PhantomData::<T>,
_state: PhantomData::<S>,
}) })
} }
} }
// TODO: Return proper error here // TODO: Return proper error here
impl<T> ActionCallback<T> impl<T, S> ActionCallback<T, S>
where 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 { let Some(internal) = self.internal.as_ref() else {
return; return;
}; };
let state = internal.lua.to_value(state).unwrap();
let callback: mlua::Value = internal let callback: mlua::Value = internal
.lua .lua
.named_registry_value(&internal.uuid.to_string()) .named_registry_value(&internal.uuid.to_string())
.unwrap(); .unwrap();
match callback { 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"), _ => todo!("Only functions are currently supported"),
} }
} }

View File

@ -29,7 +29,7 @@ impl mlua::UserData for Timeout {
methods.add_async_method( methods.add_async_method(
"start", "start",
|_lua, this, (timeout, callback): (u64, ActionCallback<bool>)| async move { |_lua, this, (timeout, callback): (u64, ActionCallback<mlua::Value, bool>)| async move {
if let Some(handle) = this.state.write().await.handle.take() { if let Some(handle) = this.state.write().await.handle.take() {
handle.abort(); handle.abort();
} }
@ -42,7 +42,7 @@ impl mlua::UserData for Timeout {
async move { async move {
tokio::time::sleep(timeout).await; tokio::time::sleep(timeout).await;
callback.call(false).await; callback.call(&mlua::Nil, &false).await;
} }
})); }));

View File

@ -90,7 +90,7 @@ automation.device_manager:add(IkeaRemote.new({
client = mqtt_client, client = mqtt_client,
topic = mqtt_z2m("living/remote"), topic = mqtt_z2m("living/remote"),
single_button = true, single_button = true,
callback = function(on) callback = function(_, on)
if on then if on then
if living_mixer:is_on() then if living_mixer:is_on() then
living_mixer:set_on(false) living_mixer:set_on(false)
@ -133,7 +133,7 @@ local kettle = IkeaOutlet.new({
}) })
automation.device_manager:add(kettle) automation.device_manager:add(kettle)
local function set_kettle(on) local function set_kettle(_, on)
kettle:set_on(on) kettle:set_on(on)
end end
@ -269,7 +269,7 @@ automation.device_manager:add(IkeaRemote.new({
room = "Hallway", room = "Hallway",
client = mqtt_client, client = mqtt_client,
topic = mqtt_z2m("hallway/remote"), topic = mqtt_z2m("hallway/remote"),
callback = function(on) callback = function(_, on)
hallway_light_automation:switch_callback(on) hallway_light_automation:switch_callback(on)
end, end,
})) }))
@ -281,7 +281,7 @@ automation.device_manager:add(ContactSensor.new({
topic = mqtt_automation("presence/contact/frontdoor"), topic = mqtt_automation("presence/contact/frontdoor"),
timeout = debug and 10 or 15 * 60, timeout = debug and 10 or 15 * 60,
}, },
callback = function(open) callback = function(_, open)
hallway_light_automation:door_callback(open) hallway_light_automation:door_callback(open)
end, end,
})) }))
@ -289,7 +289,7 @@ automation.device_manager:add(ContactSensor.new({
identifier = "hallway_trash", identifier = "hallway_trash",
topic = mqtt_z2m("hallway/trash"), topic = mqtt_z2m("hallway/trash"),
client = mqtt_client, client = mqtt_client,
callback = function(open) callback = function(_, open)
hallway_light_automation:trash_callback(open) hallway_light_automation:trash_callback(open)
end, end,
})) }))