diff --git a/automation_devices/src/ntfy.rs b/automation_devices/src/ntfy.rs index 864f69f..fc3a915 100644 --- a/automation_devices/src/ntfy.rs +++ b/automation_devices/src/ntfy.rs @@ -104,6 +104,24 @@ impl Ntfy { } } +// impl Typed for Ntfy { +// fn type_name() -> String { +// "Ntfy".into() +// } +// +// fn generate_header() -> Option { +// let type_name = ::type_name(); +// Some(format!("---@class {type_name}\nlocal {type_name}\n")) +// } +// +// fn generate_members() -> Option { +// Some(format!( +// "---@async\n---@param notification Notification\nfunction {}:send_notification(notification) end\n", +// ::type_name(), +// )) +// } +// } + #[async_trait] impl LuaDeviceCreate for Ntfy { type Config = Config; diff --git a/automation_devices/src/zigbee/light.rs b/automation_devices/src/zigbee/light.rs index 65be8cf..5294706 100644 --- a/automation_devices/src/zigbee/light.rs +++ b/automation_devices/src/zigbee/light.rs @@ -44,8 +44,8 @@ where #[serde(default)] pub callback: ActionCallback<(Light, T)>, - #[serde(default)] #[device_config(from_lua)] + #[serde(default)] pub client: WrappedAsyncClient, } crate::register_type!(Config); diff --git a/automation_lib/src/lib.rs b/automation_lib/src/lib.rs index 1cfedb4..359d71a 100644 --- a/automation_lib/src/lib.rs +++ b/automation_lib/src/lib.rs @@ -1,4 +1,3 @@ -#![allow(incomplete_features)] #![feature(iterator_try_collect)] #![feature(with_negative_coherence)] diff --git a/config.lua b/config.lua index 9f7d396..6874f37 100644 --- a/config.lua +++ b/config.lua @@ -2,17 +2,21 @@ local devices = require("automation:devices") local device_manager = require("automation:device_manager") local utils = require("automation:utils") local secrets = require("automation:secrets") -local debug = require("automation:variables").debug or false +local debug = require("automation:variables").debug and true or false print(_VERSION) local host = utils.get_hostname() print("Running @" .. host) +--- @param topic string +--- @return string local function mqtt_z2m(topic) return "zigbee2mqtt/" .. topic end +--- @param topic string +--- @return string local function mqtt_automation(topic) return "automation/" .. topic end @@ -35,7 +39,10 @@ local ntfy = devices.Ntfy.new({ }) device_manager:add(ntfy) +--- @type {[string]: number} local low_battery = {} +--- @param device InterfaceDevice +--- @param battery number local function check_battery(device, battery) local id = device:get_id() if battery < 15 then @@ -66,11 +73,13 @@ device_manager:schedule("0 0 21 */1 * *", function() }) end) -local on_presence = { - add = function(self, f) - self[#self + 1] = f - end, -} +--- @class OnPresence +--- @field [integer] fun(presence: boolean) +local on_presence = {} +--- @param f fun(presence: boolean) +function on_presence:add(f) + self[#self + 1] = f +end local presence_system = devices.Presence.new({ topic = mqtt_automation("presence/+/#"), @@ -110,11 +119,13 @@ on_presence:add(function(presence) }) end) -local window_sensors = { - add = function(self, f) - self[#self + 1] = f - end, -} +--- @class WindowSensor +--- @field [integer] InterfaceOpenClose +local window_sensors = {} +--- @param sensor InterfaceOpenClose +function window_sensors:add(sensor) + self[#self + 1] = sensor +end on_presence:add(function(presence) if not presence then local open = {} @@ -139,6 +150,7 @@ on_presence:add(function(presence) end end) +--- @param device InterfaceOnOff local function turn_off_when_away(device) on_presence:add(function(presence) if not presence then @@ -147,11 +159,13 @@ local function turn_off_when_away(device) end) end -local on_light = { - add = function(self, f) - self[#self + 1] = f - end, -} +--- @class OnLight +--- @field [integer] fun(light: boolean) +local on_light = {} +--- @param f fun(light: boolean) +function on_light:add(f) + self[#self + 1] = f +end device_manager:add(devices.LightSensor.new({ identifier = "living_light_sensor", topic = mqtt_z2m("living/light"), @@ -290,6 +304,8 @@ device_manager:add(devices.IkeaRemote.new({ local function kettle_timeout() local timeout = utils.Timeout.new() + --- @param self InterfaceOnOff + --- @param state OutletStatePower return function(self, state) if state.state and state.power < 100 then timeout:start(3, function() @@ -301,6 +317,7 @@ local function kettle_timeout() end end +--- @type OutletPower local kettle = devices.OutletPower.new({ outlet_type = "Kettle", name = "Kettle", @@ -312,6 +329,7 @@ local kettle = devices.OutletPower.new({ turn_off_when_away(kettle) device_manager:add(kettle) +--- @param on boolean local function set_kettle(_, on) kettle:set_on(on) end @@ -336,9 +354,12 @@ device_manager:add(devices.IkeaRemote.new({ battery_callback = check_battery, })) +--- @param duration number local function off_timeout(duration) local timeout = utils.Timeout.new() + --- @param self InterfaceOnOff + --- @param state {state: boolean} return function(self, state) if state.state then timeout:start(duration, function() diff --git a/definitions.bak/automation:devices.lua.bak b/definitions.bak/automation:devices.lua.bak new file mode 100644 index 0000000..d629c6c --- /dev/null +++ b/definitions.bak/automation:devices.lua.bak @@ -0,0 +1,42 @@ +---@meta + +local devices + +---@class Action +---@field action +---| "broadcast" +---| "view" +---@field extras table | nil +---@field label string | nil +---@field clear boolean|nil + +---@alias Priority +---| "min" +---| "low" +---| "default" +---| "high" +---| "max" + +---@class Notification +---@field title string +---@field message string | nil +-- NOTE: It might be possible to specify this down to the actual possible values +---@field tags string[] | nil +---@field priority Priority | nil +---@field actions Action[] | nil + +---@class Ntfy +local Ntfy +---@async +---@param notification Notification +function Ntfy:send_notification(notification) end + +---@class NtfyConfig +---@field topic string + +devices.Ntfy = {} +---@param config NtfyConfig +---@return Ntfy +function devices.Ntfy.new(config) end + +return devices diff --git a/definitions.bak/automation:secrets.lua.bak b/definitions.bak/automation:secrets.lua.bak new file mode 100644 index 0000000..6494943 --- /dev/null +++ b/definitions.bak/automation:secrets.lua.bak @@ -0,0 +1,6 @@ +---@meta + +---@type table +local secrets + +return secrets diff --git a/definitions.bak/automation:utils.lua.bak b/definitions.bak/automation:utils.lua.bak new file mode 100644 index 0000000..d8b380c --- /dev/null +++ b/definitions.bak/automation:utils.lua.bak @@ -0,0 +1,27 @@ +---@meta + +local utils + +---@class Timeout +local Timeout +---@async +---@param timeout number +---@param callback fun() +function Timeout:start(timeout, callback) end +---@async +function Timeout:cancel() end +---@async +---@return boolean +function Timeout:is_waiting() end + +utils.Timeout = {} +---@return Timeout +function utils.Timeout.new() end + +--- @return string hostname +function utils.get_hostname() end + +--- @return number epoch +function utils.get_epoch() end + +return utils diff --git a/definitions.bak/automation:variables.lua.bak b/definitions.bak/automation:variables.lua.bak new file mode 100644 index 0000000..6f09c6d --- /dev/null +++ b/definitions.bak/automation:variables.lua.bak @@ -0,0 +1,6 @@ +---@meta + +---@type table +local variables + +return variables diff --git a/definitions/automation:devices.lua b/definitions/automation:devices.lua new file mode 100644 index 0000000..5344b5d --- /dev/null +++ b/definitions/automation:devices.lua @@ -0,0 +1,322 @@ +---@meta + +local devices + +---@class KasaOutletConfig +---@field identifier string +---@field ip string +local KasaOutletConfig + +---@class KasaOutlet: InterfaceDevice, InterfaceOnOff +local KasaOutlet +devices.KasaOutlet = {} +---@param config KasaOutletConfig +---@return KasaOutlet +function devices.KasaOutlet.new(config) end + +---@class AirFilter: InterfaceDevice, InterfaceOnOff +local AirFilter +devices.AirFilter = {} +---@param config AirFilterConfig +---@return AirFilter +function devices.AirFilter.new(config) end + +---@class AirFilterConfig +---@field name string +---@field room string? +---@field url string +local AirFilterConfig + +---@class Presence: InterfaceDevice +local Presence +devices.Presence = {} +---@param config PresenceConfig +---@return Presence +function devices.Presence.new(config) end + +---@class PresenceConfig +---@field topic string +---@field callback fun(_: Presence, _: boolean) | fun(_: Presence, _: boolean)[]? +---@field client AsyncClient +local PresenceConfig + +---@class FlagIDs +---@field presence integer +---@field darkness integer +local FlagIDs + +---@class HueBridgeConfig +---@field identifier string +---@field ip string +---@field login string +---@field flags FlagIDs +local HueBridgeConfig + +---@class HueBridge: InterfaceDevice +local HueBridge +devices.HueBridge = {} +---@param config HueBridgeConfig +---@return HueBridge +function devices.HueBridge.new(config) end + +---@class WasherConfig +---@field identifier string +---@field topic string +---@field threshold number +---@field done_callback fun(_: Washer) | fun(_: Washer)[]? +---@field client AsyncClient +local WasherConfig + +---@class Washer: InterfaceDevice +local Washer +devices.Washer = {} +---@param config WasherConfig +---@return Washer +function devices.Washer.new(config) end + +---@class LightSensor: InterfaceDevice +local LightSensor +devices.LightSensor = {} +---@param config LightSensorConfig +---@return LightSensor +function devices.LightSensor.new(config) end + +---@class LightSensorConfig +---@field identifier string +---@field topic string +---@field min integer +---@field max integer +---@field callback fun(_: LightSensor, _: boolean) | fun(_: LightSensor, _: boolean)[]? +---@field client AsyncClient +local LightSensorConfig + +---@class HueGroupConfig +---@field identifier string +---@field ip string +---@field login string +---@field group_id integer +---@field scene_id string +local HueGroupConfig + +---@class HueGroup: InterfaceDevice, InterfaceOnOff +local HueGroup +devices.HueGroup = {} +---@param config HueGroupConfig +---@return HueGroup +function devices.HueGroup.new(config) end + +---@class IkeaRemote: InterfaceDevice +local IkeaRemote +devices.IkeaRemote = {} +---@param config IkeaRemoteConfig +---@return IkeaRemote +function devices.IkeaRemote.new(config) end + +---@class IkeaRemoteConfig +---@field name string +---@field room string? +---@field single_button boolean? +---@field topic string +---@field client AsyncClient +---@field callback fun(_: IkeaRemote, _: boolean) | fun(_: IkeaRemote, _: boolean)[]? +---@field battery_callback fun(_: IkeaRemote, _: number) | fun(_: IkeaRemote, _: number)[]? +local IkeaRemoteConfig + +---@class WolConfig +---@field name string +---@field room string? +---@field topic string +---@field mac_address string +---@field broadcast_ip string? +---@field client AsyncClient +local WolConfig + +---@class WakeOnLAN: InterfaceDevice +local WakeOnLAN +devices.WakeOnLAN = {} +---@param config WolConfig +---@return WakeOnLAN +function devices.WakeOnLAN.new(config) end + +---@class ConfigOutletOutletStateOnOff +---@field name string +---@field room string? +---@field topic string +---@field outlet_type OutletType? +---@field callback fun(_: OutletOnOff, _: OutletStateOnOff) | fun(_: OutletOnOff, _: OutletStateOnOff)[]? +---@field client AsyncClient +local ConfigOutletOutletStateOnOff + +---@class OutletStatePower +---@field state boolean +---@field power number +local OutletStatePower + +---@class ConfigOutletOutletStatePower +---@field name string +---@field room string? +---@field topic string +---@field outlet_type OutletType? +---@field callback fun(_: OutletPower, _: OutletStatePower) | fun(_: OutletPower, _: OutletStatePower)[]? +---@field client AsyncClient +local ConfigOutletOutletStatePower + +---@alias OutletType +---| "Outlet" +---| "Kettle" + +---@class OutletStateOnOff +---@field state boolean +local OutletStateOnOff + +---@class OutletOnOff: InterfaceDevice, InterfaceOnOff +local OutletOnOff +devices.OutletOnOff = {} +---@param config ConfigOutletOutletStateOnOff +---@return OutletOnOff +function devices.OutletOnOff.new(config) end + +---@class OutletPower: InterfaceDevice, InterfaceOnOff +local OutletPower +devices.OutletPower = {} +---@param config ConfigOutletOutletStatePower +---@return OutletPower +function devices.OutletPower.new(config) end + +---@class ContactSensorConfig +---@field name string +---@field room string? +---@field topic string +---@field sensor_type SensorType? +---@field callback fun(_: ContactSensor, _: boolean) | fun(_: ContactSensor, _: boolean)[]? +---@field battery_callback fun(_: ContactSensor, _: number) | fun(_: ContactSensor, _: number)[]? +---@field client AsyncClient? +local ContactSensorConfig + +---@alias SensorType +---| "Door" +---| "Drawer" +---| "Window" + +---@class ContactSensor: InterfaceDevice, InterfaceOpenClose +local ContactSensor +devices.ContactSensor = {} +---@param config ContactSensorConfig +---@return ContactSensor +function devices.ContactSensor.new(config) end + +---@class LightStateOnOff +---@field state boolean +local LightStateOnOff + +---@class ConfigLightLightStateColorTemperature +---@field name string +---@field room string? +---@field topic string +---@field callback fun(_: LightColorTemperature, _: LightStateColorTemperature) | fun(_: LightColorTemperature, _: LightStateColorTemperature)[]? +---@field client AsyncClient? +local ConfigLightLightStateColorTemperature + +---@class LightStateBrightness +---@field state boolean +---@field brightness number +local LightStateBrightness + +---@class LightStateColorTemperature +---@field state boolean +---@field brightness number +---@field color_temp integer +local LightStateColorTemperature + +---@class LightBrightness: InterfaceDevice, InterfaceOnOff, InterfaceBrightness +local LightBrightness +devices.LightBrightness = {} +---@param config ConfigLightLightStateBrightness +---@return LightBrightness +function devices.LightBrightness.new(config) end + +---@class LightColorTemperature: InterfaceDevice, InterfaceOnOff, InterfaceBrightness, InterfaceColorSetting +local LightColorTemperature +devices.LightColorTemperature = {} +---@param config ConfigLightLightStateColorTemperature +---@return LightColorTemperature +function devices.LightColorTemperature.new(config) end + +---@class ConfigLightLightStateOnOff +---@field name string +---@field room string? +---@field topic string +---@field callback fun(_: LightOnOff, _: LightStateOnOff) | fun(_: LightOnOff, _: LightStateOnOff)[]? +---@field client AsyncClient? +local ConfigLightLightStateOnOff + +---@class ConfigLightLightStateBrightness +---@field name string +---@field room string? +---@field topic string +---@field callback fun(_: LightBrightness, _: LightStateBrightness) | fun(_: LightBrightness, _: LightStateBrightness)[]? +---@field client AsyncClient? +local ConfigLightLightStateBrightness + +---@class LightOnOff: InterfaceDevice, InterfaceOnOff +local LightOnOff +devices.LightOnOff = {} +---@param config ConfigLightLightStateOnOff +---@return LightOnOff +function devices.LightOnOff.new(config) end + +---@class Action +---@field action +---| "broadcast" +---@field extras table? +---@field label string +---@field clear boolean? +local Action + +---@class NtfyConfig +---@field url string? +---@field topic string +local NtfyConfig + +---@class Notification +---@field title string +---@field message string? +---@field tags string[]? +---@field priority Priority? +---@field actions Action[]? +local Notification + +---@alias Priority +---| "min" +---| "low" +---| "default" +---| "high" +---| "max" + +---@class Ntfy: InterfaceDevice +local Ntfy +devices.Ntfy = {} +---@param config NtfyConfig +---@return Ntfy +function devices.Ntfy.new(config) end + +---@class HueSwitch: InterfaceDevice +local HueSwitch +devices.HueSwitch = {} +---@param config HueSwitchConfig +---@return HueSwitch +function devices.HueSwitch.new(config) end + +---@class HueSwitchConfig +---@field name string +---@field room string? +---@field topic string +---@field client AsyncClient +---@field left_callback fun(_: HueSwitch) | fun(_: HueSwitch)[]? +---@field right_callback fun(_: HueSwitch) | fun(_: HueSwitch)[]? +---@field left_hold_callback fun(_: HueSwitch) | fun(_: HueSwitch)[]? +---@field right_hold_callback fun(_: HueSwitch) | fun(_: HueSwitch)[]? +---@field battery_callback fun(_: HueSwitch, _: number) | fun(_: HueSwitch, _: number)[]? +local HueSwitchConfig + +return devices diff --git a/src/bin/generate_definitions.rs b/src/bin/generate_definitions.rs new file mode 100644 index 0000000..eee496d --- /dev/null +++ b/src/bin/generate_definitions.rs @@ -0,0 +1,3 @@ +fn main() { + automation_devices::generate_definitions() +}