Compare commits

..

8 Commits

Author SHA1 Message Date
a2e65c2d1a refactor: Remove unneeded wrapper functions when specifying callbacks
All checks were successful
Build and deploy / build (push) Successful in 10m32s
Build and deploy / Deploy container (push) Successful in 45s
These wrappers can be moved up to where the callback itself is defined
instead of having to wrap the call manually. This also works a lot nicer
now that it is possible to provide multiple callback functions.
2025-09-08 04:13:01 +02:00
e26fd9f132 fix: Front door presence does not get cleared properly 2025-09-08 04:06:02 +02:00
eb0c80c4ce feat(callback)!: ActionCallback can now receive any amount of arguments
ActionCallback now only has one generics argument that has to implement
IntoLuaMulti, this makes ActionCallback much more flexible as it no
longer always requires two arguments.
2025-09-08 04:06:01 +02:00
352654107a feat: Added derive macro to implement IntoLua on structs that implement Serialize
This can be very useful if you want to convert a data struct to a lua
table without having to write the boilerplane (however small it may
be).

It also adds the macro on several state structs so they can be
converted to lua in the upcoming ActionCallback refactor.
2025-09-08 04:06:00 +02:00
3a7f2f9bd7 fix: IkeaRemote callback is missing default specifier 2025-09-08 04:05:43 +02:00
3be11b0c6a feat: Allow for multiple callbacks inside of an ActionCallback
This also results in the conversion being performed when the
ActionCallback is instantiated instead of when it is called, this should
make it easier to catch errors.
2025-09-08 04:02:47 +02:00
e880efe4cf refactor: Store callback function directly instead of in the registry 2025-09-08 04:02:47 +02:00
e2fb680cd6 feat: Log version string during startup 2025-09-08 04:02:40 +02:00
2 changed files with 68 additions and 61 deletions

View File

@@ -28,7 +28,13 @@ impl mlua::UserData for WrappedAsyncClient {
methods.add_async_method(
"send_message",
async |_lua, this, (topic, message): (String, mlua::Value)| {
let message = serde_json::to_string(&message).unwrap();
// serde_json converts nil => "null", but we actually want nil to send an empty
// message
let message = if message.is_nil() {
"".into()
} else {
serde_json::to_string(&message).unwrap()
};
debug!("message = {message}");

View File

@@ -425,12 +425,15 @@ device_manager:add(HueSwitch.new({
local hallway_light_automation = {
timeout = Timeout.new(),
forced = false,
switch_callback = function(self, on)
switch_callback = function(self)
return function(_, on)
self.timeout:cancel()
self.group.set_on(on)
self.forced = on
end
end,
door_callback = function(self, open)
door_callback = function(self)
return function(_, open)
if open then
self.timeout:cancel()
@@ -442,8 +445,10 @@ local hallway_light_automation = {
end
end)
end
end
end,
trash_callback = function(self, open)
trash_callback = function(self)
return function(_, open)
if open then
self.group.set_on(true)
else
@@ -455,20 +460,23 @@ local hallway_light_automation = {
self.group.set_on(false)
end
end
end
end,
light_callback = function(self, on)
light_callback = function(self)
return function(_, state)
if
on
state.on
and (self.trash == nil or self.trash:open_percent()) == 0
and (self.door == nil or self.door:open_percent() == 0)
then
-- If the door and trash are not open, that means the light got turned on manually
self.timeout:cancel()
self.forced = true
elseif not on then
elseif not state.on then
-- The light is never forced when it is off
self.forced = false
end
end
end,
}
@@ -477,9 +485,7 @@ local hallway_storage = LightBrightness.new({
room = "Hallway",
topic = mqtt_z2m("hallway/storage"),
client = mqtt_client,
callback = function(_, state)
hallway_light_automation:light_callback(state.state)
end,
callback = hallway_light_automation:light_callback(),
})
turn_off_when_away(hallway_storage)
device_manager:add(hallway_storage)
@@ -504,13 +510,12 @@ hallway_light_automation.group = {
end,
}
local frontdoor_presence = {
timeout = Timeout.new(),
}
setmetatable(frontdoor_presence, {
__call = function(self, open)
local function presence(duration)
local timeout = Timeout.new()
return function(_, open)
if open then
self.timeout:cancel()
timeout:cancel()
if not presence_system:overall_presence() then
mqtt_client:send_message(mqtt_automation("presence/contact/frontdoor"), {
@@ -519,21 +524,19 @@ setmetatable(frontdoor_presence, {
})
end
else
self.timeout:start(debug and 10 or 15 * 60, function()
mqtt_client:send_message(mqtt_automation("presence/contact/frontdoor"), {})
timeout:start(duration, function()
mqtt_client:send_message(mqtt_automation("presence/contact/frontdoor"), nil)
end)
end
end,
})
end
end
device_manager:add(IkeaRemote.new({
name = "Remote",
room = "Hallway",
client = mqtt_client,
topic = mqtt_z2m("hallway/remote"),
callback = function(_, on)
hallway_light_automation:switch_callback(on)
end,
callback = hallway_light_automation:switch_callback(),
battery_callback = check_battery,
}))
local hallway_frontdoor = ContactSensor.new({
@@ -546,10 +549,10 @@ local hallway_frontdoor = ContactSensor.new({
topic = mqtt_automation("presence/contact/frontdoor"),
timeout = debug and 10 or 15 * 60,
},
callback = function(_, open)
hallway_light_automation:door_callback(open)
frontdoor_presence(open)
end,
callback = {
presence(debug and 10 or 15 * 60),
hallway_light_automation:door_callback(),
},
battery_callback = check_battery,
})
device_manager:add(hallway_frontdoor)
@@ -561,9 +564,7 @@ local hallway_trash = ContactSensor.new({
sensor_type = "Drawer",
topic = mqtt_z2m("hallway/trash"),
client = mqtt_client,
callback = function(_, open)
hallway_light_automation:trash_callback(open)
end,
callback = hallway_light_automation:trash_callback(),
battery_callback = check_battery,
})
device_manager:add(hallway_trash)