Compare commits
1 Commits
feature/im
...
6c7a774d7e
| Author | SHA1 | Date | |
|---|---|---|---|
|
6c7a774d7e
|
@@ -1,6 +1,5 @@
|
|||||||
local ntfy = require("config.ntfy")
|
local ntfy = require("config.ntfy")
|
||||||
|
|
||||||
--- @class BatteryModule: Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
--- @type {[string]: number}
|
--- @type {[string]: number}
|
||||||
@@ -18,7 +17,7 @@ function module.callback(device, battery)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function notify_low_battery()
|
function module.notify_low_battery()
|
||||||
-- Don't send notifications if there are now devices with low battery
|
-- Don't send notifications if there are now devices with low battery
|
||||||
if next(low_battery) == nil then
|
if next(low_battery) == nil then
|
||||||
print("No devices with low battery")
|
print("No devices with low battery")
|
||||||
@@ -39,9 +38,4 @@ local function notify_low_battery()
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @type Schedule
|
|
||||||
module.schedule = {
|
|
||||||
["0 0 21 */1 * *"] = notify_low_battery,
|
|
||||||
}
|
|
||||||
|
|
||||||
return module
|
return module
|
||||||
|
|||||||
@@ -29,4 +29,14 @@ return {
|
|||||||
require("config.rooms"),
|
require("config.rooms"),
|
||||||
require("config.windows"),
|
require("config.windows"),
|
||||||
},
|
},
|
||||||
|
-- TODO: Make this also part of the modules
|
||||||
|
schedule = {
|
||||||
|
["0 0 19 * * *"] = function()
|
||||||
|
require("config.rooms.bedroom").set_airfilter_on(true)
|
||||||
|
end,
|
||||||
|
["0 0 20 * * *"] = function()
|
||||||
|
require("config.rooms.bedroom").set_airfilter_on(false)
|
||||||
|
end,
|
||||||
|
["0 0 21 */1 * *"] = require("config.battery").notify_low_battery,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ local presence = require("config.presence")
|
|||||||
local utils = require("automation:utils")
|
local utils = require("automation:utils")
|
||||||
local variables = require("automation:variables")
|
local variables = require("automation:variables")
|
||||||
|
|
||||||
--- @class DebugModule: Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
if variables.debug == "true" then
|
if variables.debug == "true" then
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
local debug = require("config.debug")
|
local debug = require("config.debug")
|
||||||
local utils = require("automation:utils")
|
local utils = require("automation:utils")
|
||||||
|
|
||||||
--- @class HallwayAutomationModule: Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
local timeout = utils.Timeout.new()
|
local timeout = utils.Timeout.new()
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
local utils = require("automation:utils")
|
local utils = require("automation:utils")
|
||||||
|
|
||||||
--- @class HelperModule: Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
--- @param topic string
|
--- @param topic string
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ local light = require("config.light")
|
|||||||
local presence = require("config.presence")
|
local presence = require("config.presence")
|
||||||
local secrets = require("automation:secrets")
|
local secrets = require("automation:secrets")
|
||||||
|
|
||||||
--- @class HueBridgeModule: Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
module.ip = "10.0.0.102"
|
module.ip = "10.0.0.102"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
local devices = require("automation:devices")
|
local devices = require("automation:devices")
|
||||||
local helper = require("config.helper")
|
local helper = require("config.helper")
|
||||||
|
|
||||||
--- @class LightModule: Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
--- @class OnPresence
|
--- @class OnPresence
|
||||||
@@ -35,7 +34,6 @@ function module.setup(mqtt_client)
|
|||||||
callback = callback,
|
callback = callback,
|
||||||
})
|
})
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
return {
|
return {
|
||||||
module.device,
|
module.device,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
local devices = require("automation:devices")
|
local devices = require("automation:devices")
|
||||||
local secrets = require("automation:secrets")
|
local secrets = require("automation:secrets")
|
||||||
|
|
||||||
--- @class NtfyModule: Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
local ntfy_topic = secrets.ntfy_topic
|
local ntfy_topic = secrets.ntfy_topic
|
||||||
@@ -25,7 +24,6 @@ function module.setup()
|
|||||||
topic = ntfy_topic,
|
topic = ntfy_topic,
|
||||||
})
|
})
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
return {
|
return {
|
||||||
ntfy,
|
ntfy,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ local devices = require("automation:devices")
|
|||||||
local helper = require("config.helper")
|
local helper = require("config.helper")
|
||||||
local ntfy = require("config.ntfy")
|
local ntfy = require("config.ntfy")
|
||||||
|
|
||||||
--- @class PresenceModule: Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
--- @class OnPresence
|
--- @class OnPresence
|
||||||
@@ -62,7 +61,6 @@ function module.setup(mqtt_client)
|
|||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
return {
|
return {
|
||||||
presence,
|
presence,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ local devices = require("automation:devices")
|
|||||||
local helper = require("config.helper")
|
local helper = require("config.helper")
|
||||||
local ntfy = require("config.ntfy")
|
local ntfy = require("config.ntfy")
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
|
--- @type SetupFunction
|
||||||
function module.setup(mqtt_client)
|
function module.setup(mqtt_client)
|
||||||
local light = devices.LightOnOff.new({
|
local light = devices.LightOnOff.new({
|
||||||
name = "Light",
|
name = "Light",
|
||||||
@@ -30,7 +30,6 @@ function module.setup(mqtt_client)
|
|||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
return {
|
return {
|
||||||
light,
|
light,
|
||||||
washer,
|
washer,
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ local helper = require("config.helper")
|
|||||||
local hue_bridge = require("config.hue_bridge")
|
local hue_bridge = require("config.hue_bridge")
|
||||||
local windows = require("config.windows")
|
local windows = require("config.windows")
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
--- @type AirFilter?
|
--- @type AirFilter?
|
||||||
local air_filter = nil
|
local air_filter = nil
|
||||||
|
|
||||||
|
--- @type SetupFunction
|
||||||
function module.setup(mqtt_client)
|
function module.setup(mqtt_client)
|
||||||
local lights = devices.HueGroup.new({
|
local lights = devices.HueGroup.new({
|
||||||
identifier = "bedroom_lights",
|
identifier = "bedroom_lights",
|
||||||
@@ -55,24 +55,20 @@ function module.setup(mqtt_client)
|
|||||||
})
|
})
|
||||||
windows.add(window)
|
windows.add(window)
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
return {
|
return {
|
||||||
devices = {
|
|
||||||
lights,
|
lights,
|
||||||
lights_relax,
|
lights_relax,
|
||||||
air_filter,
|
air_filter,
|
||||||
switch,
|
switch,
|
||||||
window,
|
window,
|
||||||
},
|
|
||||||
schedule = {
|
|
||||||
["0 0 19 * * *"] = function()
|
|
||||||
air_filter:set_on(true)
|
|
||||||
end,
|
|
||||||
["0 0 20 * * *"] = function()
|
|
||||||
air_filter:set_on(false)
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- @param on boolean
|
||||||
|
function module.set_airfilter_on(on)
|
||||||
|
if air_filter then
|
||||||
|
air_filter:set_on(on)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return module
|
return module
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ local helper = require("config.helper")
|
|||||||
local presence = require("config.presence")
|
local presence = require("config.presence")
|
||||||
local windows = require("config.windows")
|
local windows = require("config.windows")
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
|
--- @type SetupFunction
|
||||||
function module.setup(mqtt_client)
|
function module.setup(mqtt_client)
|
||||||
local light = devices.LightOnOff.new({
|
local light = devices.LightOnOff.new({
|
||||||
name = "Light",
|
name = "Light",
|
||||||
@@ -25,7 +25,6 @@ function module.setup(mqtt_client)
|
|||||||
})
|
})
|
||||||
windows.add(window)
|
windows.add(window)
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
return {
|
return {
|
||||||
light,
|
light,
|
||||||
window,
|
window,
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ local presence = require("config.presence")
|
|||||||
local utils = require("automation:utils")
|
local utils = require("automation:utils")
|
||||||
local windows = require("config.windows")
|
local windows = require("config.windows")
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
|
--- @type SetupFunction
|
||||||
function module.setup(mqtt_client)
|
function module.setup(mqtt_client)
|
||||||
local main_light = devices.HueGroup.new({
|
local main_light = devices.HueGroup.new({
|
||||||
identifier = "hallway_main_light",
|
identifier = "hallway_main_light",
|
||||||
@@ -97,7 +97,6 @@ function module.setup(mqtt_client)
|
|||||||
windows.add(frontdoor)
|
windows.add(frontdoor)
|
||||||
hallway_automation.set_door(frontdoor)
|
hallway_automation.set_door(frontdoor)
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
return {
|
return {
|
||||||
main_light,
|
main_light,
|
||||||
storage_light,
|
storage_light,
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ local devices = require("automation:devices")
|
|||||||
local helper = require("config.helper")
|
local helper = require("config.helper")
|
||||||
local hue_bridge = require("config.hue_bridge")
|
local hue_bridge = require("config.hue_bridge")
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
|
--- @type SetupFunction
|
||||||
function module.setup(mqtt_client)
|
function module.setup(mqtt_client)
|
||||||
local light = devices.HueGroup.new({
|
local light = devices.HueGroup.new({
|
||||||
identifier = "hallway_top_light",
|
identifier = "hallway_top_light",
|
||||||
@@ -37,7 +37,6 @@ function module.setup(mqtt_client)
|
|||||||
battery_callback = battery.callback,
|
battery_callback = battery.callback,
|
||||||
})
|
})
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
return {
|
return {
|
||||||
light,
|
light,
|
||||||
top_switch,
|
top_switch,
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ local helper = require("config.helper")
|
|||||||
local hue_bridge = require("config.hue_bridge")
|
local hue_bridge = require("config.hue_bridge")
|
||||||
local presence = require("config.presence")
|
local presence = require("config.presence")
|
||||||
|
|
||||||
--- @class KitchenModule: Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
--- @type HueGroup?
|
--- @type HueGroup?
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ local hue_bridge = require("config.hue_bridge")
|
|||||||
local presence = require("config.presence")
|
local presence = require("config.presence")
|
||||||
local windows = require("config.windows")
|
local windows = require("config.windows")
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
|
--- @type SetupFunction
|
||||||
function module.setup(mqtt_client)
|
function module.setup(mqtt_client)
|
||||||
local lights = devices.HueGroup.new({
|
local lights = devices.HueGroup.new({
|
||||||
identifier = "living_lights",
|
identifier = "living_lights",
|
||||||
@@ -109,7 +109,6 @@ function module.setup(mqtt_client)
|
|||||||
})
|
})
|
||||||
windows.add(window)
|
windows.add(window)
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
return {
|
return {
|
||||||
lights,
|
lights,
|
||||||
lights_relax,
|
lights_relax,
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ local devices = require("automation:devices")
|
|||||||
local helper = require("config.helper")
|
local helper = require("config.helper")
|
||||||
local presence = require("config.presence")
|
local presence = require("config.presence")
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
|
--- @type SetupFunction
|
||||||
function module.setup(mqtt_client)
|
function module.setup(mqtt_client)
|
||||||
local light = devices.LightBrightness.new({
|
local light = devices.LightBrightness.new({
|
||||||
name = "Light",
|
name = "Light",
|
||||||
@@ -31,7 +31,6 @@ function module.setup(mqtt_client)
|
|||||||
battery_callback = battery.callback,
|
battery_callback = battery.callback,
|
||||||
})
|
})
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
return {
|
return {
|
||||||
light,
|
light,
|
||||||
door,
|
door,
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ local helper = require("config.helper")
|
|||||||
local presence = require("config.presence")
|
local presence = require("config.presence")
|
||||||
local utils = require("automation:utils")
|
local utils = require("automation:utils")
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
|
--- @type SetupFunction
|
||||||
function module.setup(mqtt_client)
|
function module.setup(mqtt_client)
|
||||||
local charger = devices.OutletOnOff.new({
|
local charger = devices.OutletOnOff.new({
|
||||||
name = "Charger",
|
name = "Charger",
|
||||||
@@ -57,7 +57,6 @@ function module.setup(mqtt_client)
|
|||||||
battery_callback = battery.callback,
|
battery_callback = battery.callback,
|
||||||
})
|
})
|
||||||
|
|
||||||
--- @type Module
|
|
||||||
return {
|
return {
|
||||||
charger,
|
charger,
|
||||||
outlets,
|
outlets,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
local ntfy = require("config.ntfy")
|
local ntfy = require("config.ntfy")
|
||||||
local presence = require("config.presence")
|
local presence = require("config.presence")
|
||||||
|
|
||||||
--- @class WindowsModule: Module
|
|
||||||
local module = {}
|
local module = {}
|
||||||
|
|
||||||
--- @class OnPresence
|
--- @class OnPresence
|
||||||
|
|||||||
@@ -11,17 +11,13 @@ local FulfillmentConfig
|
|||||||
---@field fulfillment FulfillmentConfig
|
---@field fulfillment FulfillmentConfig
|
||||||
---@field modules (Module)[]
|
---@field modules (Module)[]
|
||||||
---@field mqtt MqttConfig
|
---@field mqtt MqttConfig
|
||||||
|
---@field schedule (table<string, fun() | fun()[]>)?
|
||||||
local Config
|
local Config
|
||||||
|
|
||||||
---@alias SetupFunction fun(mqtt_client: AsyncClient): Module | DeviceInterface[] | nil
|
|
||||||
|
|
||||||
---@alias Schedule table<string, fun() | fun()[]>
|
|
||||||
|
|
||||||
---@class Module
|
---@class Module
|
||||||
---@field setup (SetupFunction)?
|
---@field setup (fun(mqtt_client: AsyncClient): Module | DeviceInterface[] | nil)?
|
||||||
---@field devices (DeviceInterface)[]?
|
---@field devices DeviceInterface[]?
|
||||||
---@field schedule Schedule?
|
---@field [number] Module[]?
|
||||||
---@field [number] (Module)[]?
|
|
||||||
local Module
|
local Module
|
||||||
|
|
||||||
---@class MqttConfig
|
---@class MqttConfig
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use std::process;
|
|||||||
|
|
||||||
use ::config::{Environment, File};
|
use ::config::{Environment, File};
|
||||||
use automation::config::{Config, Setup};
|
use automation::config::{Config, Setup};
|
||||||
|
use automation::schedule::start_scheduler;
|
||||||
use automation::secret::EnvironmentSecretFile;
|
use automation::secret::EnvironmentSecretFile;
|
||||||
use automation::version::VERSION;
|
use automation::version::VERSION;
|
||||||
use automation::web::{ApiError, User};
|
use automation::web::{ApiError, User};
|
||||||
@@ -144,7 +145,7 @@ async fn app() -> anyhow::Result<()> {
|
|||||||
device_manager.add(device).await;
|
device_manager.add(device).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolved.scheduler.start().await?;
|
start_scheduler(config.schedule).await?;
|
||||||
|
|
||||||
// Create google home fulfillment route
|
// Create google home fulfillment route
|
||||||
let fulfillment = Router::new().route("/google_home", post(fulfillment));
|
let fulfillment = Router::new().route("/google_home", post(fulfillment));
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use automation::config::generate_definitions;
|
use automation::config::{Config, FulfillmentConfig, Module as ConfigModule};
|
||||||
use automation_lib::Module;
|
use automation_lib::Module;
|
||||||
|
use automation_lib::mqtt::{MqttConfig, WrappedAsyncClient};
|
||||||
|
use lua_typed::Typed;
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
|
|
||||||
extern crate automation_devices;
|
extern crate automation_devices;
|
||||||
@@ -25,6 +27,24 @@ fn write_definitions(filename: &str, definitions: &str) -> std::io::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn config_definitions() -> String {
|
||||||
|
let mut output = "---@meta\n\n".to_string();
|
||||||
|
|
||||||
|
output +=
|
||||||
|
&FulfillmentConfig::generate_full().expect("FulfillmentConfig should have a definition");
|
||||||
|
output += "\n";
|
||||||
|
output += &Config::generate_full().expect("Config should have a definition");
|
||||||
|
output += "\n";
|
||||||
|
output += &ConfigModule::generate_full().expect("Module should have a definition");
|
||||||
|
output += "\n";
|
||||||
|
output += &MqttConfig::generate_full().expect("MqttConfig should have a definition");
|
||||||
|
output += "\n";
|
||||||
|
output +=
|
||||||
|
&WrappedAsyncClient::generate_full().expect("WrappedAsyncClient should have a definition");
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
@@ -39,7 +59,7 @@ fn main() -> std::io::Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write_definitions("config.lua", &generate_definitions())?;
|
write_definitions("config.lua", &config_definitions())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
119
src/config.rs
119
src/config.rs
@@ -1,6 +1,5 @@
|
|||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::net::{Ipv4Addr, SocketAddr};
|
use std::net::{Ipv4Addr, SocketAddr};
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use automation_lib::action_callback::ActionCallback;
|
use automation_lib::action_callback::ActionCallback;
|
||||||
use automation_lib::device::Device;
|
use automation_lib::device::Device;
|
||||||
@@ -10,8 +9,6 @@ use lua_typed::Typed;
|
|||||||
use mlua::FromLua;
|
use mlua::FromLua;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::schedule::Scheduler;
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Setup {
|
pub struct Setup {
|
||||||
#[serde(default = "default_entrypoint")]
|
#[serde(default = "default_entrypoint")]
|
||||||
@@ -38,20 +35,15 @@ pub struct FulfillmentConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct SetupFunction(mlua::Function);
|
pub struct SetupFunction(mlua::Function);
|
||||||
|
|
||||||
impl Typed for SetupFunction {
|
impl Typed for SetupFunction {
|
||||||
fn type_name() -> String {
|
fn type_name() -> String {
|
||||||
"SetupFunction".into()
|
format!(
|
||||||
}
|
"fun(mqtt_client: {}): {} | DeviceInterface[] | nil",
|
||||||
|
|
||||||
fn generate_header() -> Option<String> {
|
|
||||||
Some(format!(
|
|
||||||
"---@alias {} fun(mqtt_client: {}): {} | DeviceInterface[] | nil\n",
|
|
||||||
Self::type_name(),
|
|
||||||
WrappedAsyncClient::type_name(),
|
WrappedAsyncClient::type_name(),
|
||||||
Module::type_name()
|
Module::type_name()
|
||||||
))
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,53 +53,11 @@ impl FromLua for SetupFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for SetupFunction {
|
|
||||||
type Target = mlua::Function;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct Schedule(HashMap<String, ActionCallback<()>>);
|
pub struct Module {
|
||||||
|
pub setup: Option<SetupFunction>,
|
||||||
impl Typed for Schedule {
|
pub devices: Vec<Box<dyn Device>>,
|
||||||
fn type_name() -> String {
|
pub modules: Vec<Module>,
|
||||||
"Schedule".into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_header() -> Option<String> {
|
|
||||||
Some(format!(
|
|
||||||
"---@alias {} {}\n",
|
|
||||||
Self::type_name(),
|
|
||||||
HashMap::<String, ActionCallback<()>>::type_name(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromLua for Schedule {
|
|
||||||
fn from_lua(value: mlua::Value, lua: &mlua::Lua) -> mlua::Result<Self> {
|
|
||||||
Ok(Self(FromLua::from_lua(value, lua)?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoIterator for Schedule {
|
|
||||||
type Item = <HashMap<String, ActionCallback<()>> as IntoIterator>::Item;
|
|
||||||
|
|
||||||
type IntoIter = <HashMap<String, ActionCallback<()>> as IntoIterator>::IntoIter;
|
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
|
||||||
self.0.into_iter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
struct Module {
|
|
||||||
setup: Option<SetupFunction>,
|
|
||||||
devices: Vec<Box<dyn Device>>,
|
|
||||||
schedule: Schedule,
|
|
||||||
modules: Vec<Module>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add option to typed to rename field
|
// TODO: Add option to typed to rename field
|
||||||
@@ -123,14 +73,10 @@ impl Typed for Module {
|
|||||||
fn generate_members() -> Option<String> {
|
fn generate_members() -> Option<String> {
|
||||||
Some(format!(
|
Some(format!(
|
||||||
r#"---@field setup {}
|
r#"---@field setup {}
|
||||||
---@field devices {}?
|
---@field devices DeviceInterface[]?
|
||||||
---@field schedule {}?
|
---@field [number] Module[]?
|
||||||
---@field [number] {}?
|
|
||||||
"#,
|
"#,
|
||||||
Option::<SetupFunction>::type_name(),
|
Option::<SetupFunction>::type_name()
|
||||||
Vec::<Box<dyn Device>>::type_name(),
|
|
||||||
Schedule::type_name(),
|
|
||||||
Vec::<Module>::type_name(),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,9 +103,8 @@ impl FromLua for Module {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let setup = table.get("setup")?;
|
let setup = table.get("setup")?;
|
||||||
let devices = table.get("devices").unwrap_or_default();
|
|
||||||
let schedule = table.get("schedule").unwrap_or_default();
|
|
||||||
|
|
||||||
|
let devices = table.get("devices").unwrap_or_else(|_| Vec::new());
|
||||||
let mut modules = Vec::new();
|
let mut modules = Vec::new();
|
||||||
|
|
||||||
for module in table.sequence_values::<Module>() {
|
for module in table.sequence_values::<Module>() {
|
||||||
@@ -169,7 +114,6 @@ impl FromLua for Module {
|
|||||||
Ok(Module {
|
Ok(Module {
|
||||||
setup,
|
setup,
|
||||||
devices,
|
devices,
|
||||||
schedule,
|
|
||||||
modules,
|
modules,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -196,10 +140,10 @@ impl Modules {
|
|||||||
lua: &mlua::Lua,
|
lua: &mlua::Lua,
|
||||||
client: &WrappedAsyncClient,
|
client: &WrappedAsyncClient,
|
||||||
) -> mlua::Result<Resolved> {
|
) -> mlua::Result<Resolved> {
|
||||||
let mut devices = Vec::new();
|
|
||||||
let mut scheduler = Scheduler::default();
|
|
||||||
|
|
||||||
let mut modules: VecDeque<_> = self.0.into();
|
let mut modules: VecDeque<_> = self.0.into();
|
||||||
|
|
||||||
|
let mut devices = Vec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let Some(module) = modules.pop_front() else {
|
let Some(module) = modules.pop_front() else {
|
||||||
break;
|
break;
|
||||||
@@ -208,7 +152,7 @@ impl Modules {
|
|||||||
modules.extend(module.modules);
|
modules.extend(module.modules);
|
||||||
|
|
||||||
if let Some(setup) = module.setup {
|
if let Some(setup) = module.setup {
|
||||||
let result: mlua::Value = setup.call_async(client.clone()).await?;
|
let result: mlua::Value = setup.0.call_async(client.clone()).await?;
|
||||||
|
|
||||||
if result.is_nil() {
|
if result.is_nil() {
|
||||||
// We ignore nil results
|
// We ignore nil results
|
||||||
@@ -228,19 +172,15 @@ impl Modules {
|
|||||||
}
|
}
|
||||||
|
|
||||||
devices.extend(module.devices);
|
devices.extend(module.devices);
|
||||||
for (cron, f) in module.schedule {
|
|
||||||
scheduler.add_job(cron, f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Resolved { devices, scheduler })
|
Ok(Resolved { devices })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Resolved {
|
pub struct Resolved {
|
||||||
pub devices: Vec<Box<dyn Device>>,
|
pub devices: Vec<Box<dyn Device>>,
|
||||||
pub scheduler: Scheduler,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, LuaDeviceConfig, Typed)]
|
#[derive(Debug, LuaDeviceConfig, Typed)]
|
||||||
@@ -250,6 +190,9 @@ pub struct Config {
|
|||||||
pub modules: Modules,
|
pub modules: Modules,
|
||||||
#[device_config(from_lua)]
|
#[device_config(from_lua)]
|
||||||
pub mqtt: MqttConfig,
|
pub mqtt: MqttConfig,
|
||||||
|
#[device_config(from_lua, default)]
|
||||||
|
#[typed(default)]
|
||||||
|
pub schedule: HashMap<String, ActionCallback<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FulfillmentConfig> for SocketAddr {
|
impl From<FulfillmentConfig> for SocketAddr {
|
||||||
@@ -264,25 +207,3 @@ fn default_fulfillment_ip() -> Ipv4Addr {
|
|||||||
fn default_fulfillment_port() -> u16 {
|
fn default_fulfillment_port() -> u16 {
|
||||||
7878
|
7878
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_definitions() -> String {
|
|
||||||
let mut output = "---@meta\n\n".to_string();
|
|
||||||
|
|
||||||
output +=
|
|
||||||
&FulfillmentConfig::generate_full().expect("FulfillmentConfig should have a definition");
|
|
||||||
output += "\n";
|
|
||||||
output += &Config::generate_full().expect("Config should have a definition");
|
|
||||||
output += "\n";
|
|
||||||
output += &SetupFunction::generate_full().expect("SetupFunction should have a definition");
|
|
||||||
output += "\n";
|
|
||||||
output += &Schedule::generate_full().expect("Schedule should have a definition");
|
|
||||||
output += "\n";
|
|
||||||
output += &Module::generate_full().expect("Module should have a definition");
|
|
||||||
output += "\n";
|
|
||||||
output += &MqttConfig::generate_full().expect("MqttConfig should have a definition");
|
|
||||||
output += "\n";
|
|
||||||
output +=
|
|
||||||
&WrappedAsyncClient::generate_full().expect("WrappedAsyncClient should have a definition");
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,22 +1,15 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
|
||||||
use automation_lib::action_callback::ActionCallback;
|
use automation_lib::action_callback::ActionCallback;
|
||||||
use tokio_cron_scheduler::{Job, JobScheduler, JobSchedulerError};
|
use tokio_cron_scheduler::{Job, JobScheduler, JobSchedulerError};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
pub async fn start_scheduler(
|
||||||
pub struct Scheduler {
|
schedule: HashMap<String, ActionCallback<()>>,
|
||||||
jobs: Vec<(String, ActionCallback<()>)>,
|
) -> Result<(), JobSchedulerError> {
|
||||||
}
|
|
||||||
|
|
||||||
impl Scheduler {
|
|
||||||
pub fn add_job(&mut self, cron: String, f: ActionCallback<()>) {
|
|
||||||
self.jobs.push((cron, f));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn start(self) -> Result<(), JobSchedulerError> {
|
|
||||||
let scheduler = JobScheduler::new().await?;
|
let scheduler = JobScheduler::new().await?;
|
||||||
|
|
||||||
for (s, f) in self.jobs {
|
for (s, f) in schedule {
|
||||||
let job = {
|
let job = {
|
||||||
move |_uuid, _lock| -> Pin<Box<dyn Future<Output = ()> + Send>> {
|
move |_uuid, _lock| -> Pin<Box<dyn Future<Output = ()> + Send>> {
|
||||||
let f = f.clone();
|
let f = f.clone();
|
||||||
@@ -34,4 +27,3 @@ impl Scheduler {
|
|||||||
|
|
||||||
scheduler.start().await
|
scheduler.start().await
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user