WIP
This commit is contained in:
@@ -742,11 +742,15 @@ devs:add(devices.ContactSensor.new({
|
|||||||
battery_callback = check_battery,
|
battery_callback = check_battery,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
-- HACK: If the devices config contains a function it will call it so we have to remove it
|
||||||
|
devs.add = nil
|
||||||
|
|
||||||
---@type Config
|
---@type Config
|
||||||
return {
|
return {
|
||||||
fulfillment = {
|
fulfillment = {
|
||||||
openid_url = "https://login.huizinga.dev/api/oidc",
|
openid_url = "https://login.huizinga.dev/api/oidc",
|
||||||
},
|
},
|
||||||
|
mqtt = mqtt_client,
|
||||||
devices = devs,
|
devices = devs,
|
||||||
schedule = {
|
schedule = {
|
||||||
["0 0 19 * * *"] = function()
|
["0 0 19 * * *"] = function()
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ local FulfillmentConfig
|
|||||||
|
|
||||||
---@class Config
|
---@class Config
|
||||||
---@field fulfillment FulfillmentConfig
|
---@field fulfillment FulfillmentConfig
|
||||||
---@field devices DeviceInterface[]?
|
---@field devices Devices?
|
||||||
|
---@field mqtt AsyncClient
|
||||||
---@field schedule table<string, fun() | fun()[]>?
|
---@field schedule table<string, fun() | fun()[]>?
|
||||||
local Config
|
local Config
|
||||||
|
|
||||||
|
---@alias Devices (DeviceInterface | fun(client: AsyncClient): Devices)[]
|
||||||
|
|||||||
@@ -139,9 +139,11 @@ async fn app() -> anyhow::Result<()> {
|
|||||||
let entrypoint = Path::new(&setup.entrypoint);
|
let entrypoint = Path::new(&setup.entrypoint);
|
||||||
let config: Config = lua.load(entrypoint).eval_async().await?;
|
let config: Config = lua.load(entrypoint).eval_async().await?;
|
||||||
|
|
||||||
for device in config.devices {
|
if let Some(devices) = config.devices {
|
||||||
|
for device in devices.get(&lua, &config.mqtt).await? {
|
||||||
device_manager.add(device).await;
|
device_manager.add(device).await;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
start_scheduler(config.schedule).await?;
|
start_scheduler(config.schedule).await?;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use automation::config::{Config, FulfillmentConfig};
|
use automation::config::{Config, Devices, FulfillmentConfig};
|
||||||
use automation_lib::Module;
|
use automation_lib::Module;
|
||||||
use lua_typed::Typed;
|
use lua_typed::Typed;
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
@@ -33,6 +33,8 @@ fn config_definitions() -> String {
|
|||||||
&FulfillmentConfig::generate_full().expect("FulfillmentConfig should have a definition");
|
&FulfillmentConfig::generate_full().expect("FulfillmentConfig should have a definition");
|
||||||
output += "\n";
|
output += "\n";
|
||||||
output += &Config::generate_full().expect("Config should have a definition");
|
output += &Config::generate_full().expect("Config should have a definition");
|
||||||
|
output += "\n";
|
||||||
|
output += &Devices::generate_full().expect("Devices should have a definition");
|
||||||
|
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::net::{Ipv4Addr, SocketAddr};
|
use std::net::{Ipv4Addr, SocketAddr};
|
||||||
|
|
||||||
use automation_lib::action_callback::ActionCallback;
|
use automation_lib::action_callback::ActionCallback;
|
||||||
use automation_lib::device::Device;
|
use automation_lib::device::Device;
|
||||||
|
use automation_lib::mqtt::WrappedAsyncClient;
|
||||||
use automation_macro::LuaDeviceConfig;
|
use automation_macro::LuaDeviceConfig;
|
||||||
use lua_typed::Typed;
|
use lua_typed::Typed;
|
||||||
|
use mlua::FromLua;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@@ -32,12 +34,78 @@ pub struct FulfillmentConfig {
|
|||||||
pub port: u16,
|
pub port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Devices(mlua::Value);
|
||||||
|
|
||||||
|
impl Devices {
|
||||||
|
pub async fn get(
|
||||||
|
self,
|
||||||
|
lua: &mlua::Lua,
|
||||||
|
client: &WrappedAsyncClient,
|
||||||
|
) -> mlua::Result<Vec<Box<dyn Device>>> {
|
||||||
|
let mut devices = Vec::new();
|
||||||
|
let initial_table = match self.0 {
|
||||||
|
mlua::Value::Table(table) => table,
|
||||||
|
mlua::Value::Function(f) => f.call_async(client.clone()).await?,
|
||||||
|
_ => Err(mlua::Error::runtime(format!(
|
||||||
|
"Expected table or function, instead found: {}",
|
||||||
|
self.0.type_name()
|
||||||
|
)))?,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut queue: VecDeque<mlua::Table> = [initial_table].into();
|
||||||
|
loop {
|
||||||
|
let Some(table) = queue.pop_front() else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
for pair in table.pairs() {
|
||||||
|
let (_, value): (mlua::Value, _) = pair?;
|
||||||
|
|
||||||
|
match value {
|
||||||
|
mlua::Value::UserData(_) => devices.push(Box::from_lua(value, lua)?),
|
||||||
|
mlua::Value::Function(f) => {
|
||||||
|
queue.push_back(f.call_async(client.clone()).await?);
|
||||||
|
}
|
||||||
|
_ => Err(mlua::Error::runtime(format!(
|
||||||
|
"Expected a device, table, or function, instead found: {}",
|
||||||
|
value.type_name()
|
||||||
|
)))?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(devices)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromLua for Devices {
|
||||||
|
fn from_lua(value: mlua::Value, _lua: &mlua::Lua) -> mlua::Result<Self> {
|
||||||
|
Ok(Devices(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Typed for Devices {
|
||||||
|
fn type_name() -> String {
|
||||||
|
"Devices".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_header() -> Option<String> {
|
||||||
|
Some(format!(
|
||||||
|
"---@alias {} (DeviceInterface | fun(client: {}): Devices)[]\n",
|
||||||
|
<Self as Typed>::type_name(),
|
||||||
|
<WrappedAsyncClient as Typed>::type_name()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, LuaDeviceConfig, Typed)]
|
#[derive(Debug, LuaDeviceConfig, Typed)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub fulfillment: FulfillmentConfig,
|
pub fulfillment: FulfillmentConfig,
|
||||||
#[device_config(from_lua, default)]
|
#[device_config(from_lua, default)]
|
||||||
#[typed(default)]
|
pub devices: Option<Devices>,
|
||||||
pub devices: Vec<Box<dyn Device>>,
|
#[device_config(from_lua)]
|
||||||
|
pub mqtt: WrappedAsyncClient,
|
||||||
#[device_config(from_lua, default)]
|
#[device_config(from_lua, default)]
|
||||||
#[typed(default)]
|
#[typed(default)]
|
||||||
pub schedule: HashMap<String, ActionCallback<()>>,
|
pub schedule: HashMap<String, ActionCallback<()>>,
|
||||||
|
|||||||
Reference in New Issue
Block a user