Compare commits
6 Commits
f7ba602762
...
295491c5fc
| Author | SHA1 | Date | |
|---|---|---|---|
|
295491c5fc
|
|||
|
9f244b3475
|
|||
|
15a6e83ad8
|
|||
|
c727579290
|
|||
|
19e8663f26
|
|||
|
f5c4495cad
|
11
Cargo.lock
generated
11
Cargo.lock
generated
@@ -96,7 +96,6 @@ dependencies = [
|
||||
"automation_lib",
|
||||
"axum",
|
||||
"config",
|
||||
"dotenvy",
|
||||
"git-version",
|
||||
"google_home",
|
||||
"mlua",
|
||||
@@ -433,12 +432,6 @@ dependencies = [
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dotenvy"
|
||||
version = "0.15.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.20"
|
||||
@@ -1108,7 +1101,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "lua_typed"
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.huizinga.dev/Dreaded_X/lua_typed#d5d6fc1638bd108514899a792ee64335af50fc8b"
|
||||
source = "git+https://git.huizinga.dev/Dreaded_X/lua_typed#08f5c4533a93131e8eda6702c062fb841d14d4e1"
|
||||
dependencies = [
|
||||
"eui48",
|
||||
"lua_typed_macro",
|
||||
@@ -1117,7 +1110,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "lua_typed_macro"
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.huizinga.dev/Dreaded_X/lua_typed#d5d6fc1638bd108514899a792ee64335af50fc8b"
|
||||
source = "git+https://git.huizinga.dev/Dreaded_X/lua_typed#08f5c4533a93131e8eda6702c062fb841d14d4e1"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"itertools",
|
||||
|
||||
@@ -23,7 +23,6 @@ automation_lib = { path = "./automation_lib" }
|
||||
automation_macro = { path = "./automation_macro" }
|
||||
axum = "0.8.4"
|
||||
bytes = "1.10.1"
|
||||
dotenvy = "0.15.7"
|
||||
dyn-clone = "1.0.20"
|
||||
eui48 = { version = "1.1.0", features = [
|
||||
"disp_hexstring",
|
||||
@@ -75,7 +74,6 @@ config = { version = "0.15.15", default-features = false, features = [
|
||||
"async",
|
||||
"toml",
|
||||
] }
|
||||
dotenvy = { workspace = true }
|
||||
git-version = "0.3.9"
|
||||
google_home = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
|
||||
@@ -3,18 +3,21 @@ use std::net::SocketAddr;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_lib::lua::traits::PartialUserData;
|
||||
use automation_macro::{Device, LuaDeviceConfig};
|
||||
use lua_typed::Typed;
|
||||
use mlua::LuaSerdeExt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{error, trace, warn};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Deserialize, Typed)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[typed(rename_all = "snake_case")]
|
||||
pub enum Flag {
|
||||
Presence,
|
||||
Darkness,
|
||||
}
|
||||
crate::register_type!(Flag);
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Typed)]
|
||||
pub struct FlagIDs {
|
||||
@@ -36,12 +39,36 @@ pub struct Config {
|
||||
crate::register_type!(Config);
|
||||
|
||||
#[derive(Debug, Clone, Device)]
|
||||
#[device(add_methods = Self::add_methods)]
|
||||
#[device(extra_user_data = SetFlag)]
|
||||
pub struct HueBridge {
|
||||
config: Config,
|
||||
}
|
||||
crate::register_device!(HueBridge);
|
||||
|
||||
struct SetFlag;
|
||||
impl PartialUserData<HueBridge> for SetFlag {
|
||||
fn add_methods<M: mlua::UserDataMethods<HueBridge>>(methods: &mut M) {
|
||||
methods.add_async_method(
|
||||
"set_flag",
|
||||
async |lua, this, (flag, value): (mlua::Value, bool)| {
|
||||
let flag: Flag = lua.from_value(flag)?;
|
||||
|
||||
this.set_flag(flag, value).await;
|
||||
|
||||
Ok(())
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn definitions() -> Option<String> {
|
||||
Some(format!(
|
||||
"---@async\n---@param flag {}\n---@param value boolean\nfunction {}:set_flag(flag, value) end\n",
|
||||
<Flag as Typed>::type_name(),
|
||||
<HueBridge as Typed>::type_name(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct FlagMessage {
|
||||
flag: bool,
|
||||
@@ -89,19 +116,6 @@ impl HueBridge {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_async_method(
|
||||
"set_flag",
|
||||
async |lua, this, (flag, value): (mlua::Value, bool)| {
|
||||
let flag: Flag = lua.from_value(flag)?;
|
||||
|
||||
this.set_flag(flag, value).await;
|
||||
|
||||
Ok(())
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for HueBridge {
|
||||
|
||||
@@ -20,7 +20,7 @@ use tracing::debug;
|
||||
macro_rules! register_device {
|
||||
($device:ty) => {
|
||||
::inventory::submit!(crate::RegisteredDevice::new(
|
||||
stringify!($device),
|
||||
<$device as ::lua_typed::Typed>::type_name,
|
||||
::mlua::Lua::create_proxy::<$device>
|
||||
));
|
||||
|
||||
@@ -30,20 +30,24 @@ macro_rules! register_device {
|
||||
|
||||
pub(crate) use register_device;
|
||||
|
||||
type DeviceNameFn = fn() -> String;
|
||||
type RegisterDeviceFn = fn(lua: &mlua::Lua) -> mlua::Result<mlua::AnyUserData>;
|
||||
|
||||
pub struct RegisteredDevice {
|
||||
name: &'static str,
|
||||
name_fn: DeviceNameFn,
|
||||
register_fn: RegisterDeviceFn,
|
||||
}
|
||||
|
||||
impl RegisteredDevice {
|
||||
pub const fn new(name: &'static str, register_fn: RegisterDeviceFn) -> Self {
|
||||
Self { name, register_fn }
|
||||
pub const fn new(name_fn: DeviceNameFn, register_fn: RegisterDeviceFn) -> Self {
|
||||
Self {
|
||||
name_fn,
|
||||
register_fn,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn get_name(&self) -> &'static str {
|
||||
self.name
|
||||
pub fn get_name(&self) -> String {
|
||||
(self.name_fn)()
|
||||
}
|
||||
|
||||
pub fn register(&self, lua: &mlua::Lua) -> mlua::Result<mlua::AnyUserData> {
|
||||
@@ -58,15 +62,16 @@ pub fn create_module(lua: &mlua::Lua) -> mlua::Result<mlua::Table> {
|
||||
|
||||
debug!("Loading devices...");
|
||||
for device in inventory::iter::<RegisteredDevice> {
|
||||
debug!(name = device.get_name(), "Registering device");
|
||||
let name = device.get_name();
|
||||
debug!(name, "Registering device");
|
||||
let proxy = device.register(lua)?;
|
||||
devices.set(device.get_name(), proxy)?;
|
||||
devices.set(name, proxy)?;
|
||||
}
|
||||
|
||||
Ok(devices)
|
||||
}
|
||||
|
||||
inventory::submit! {Module::new("devices", create_module)}
|
||||
inventory::submit! {Module::new("automation:devices", create_module)}
|
||||
|
||||
macro_rules! register_type {
|
||||
($ty:ty) => {
|
||||
|
||||
@@ -3,6 +3,7 @@ use std::convert::Infallible;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_lib::lua::traits::PartialUserData;
|
||||
use automation_macro::{Device, LuaDeviceConfig};
|
||||
use lua_typed::Typed;
|
||||
use mlua::LuaSerdeExt;
|
||||
@@ -90,14 +91,15 @@ pub struct Config {
|
||||
crate::register_type!(Config);
|
||||
|
||||
#[derive(Debug, Clone, Device)]
|
||||
#[device(add_methods = Self::add_methods)]
|
||||
#[device(extra_user_data = SendNotification)]
|
||||
pub struct Ntfy {
|
||||
config: Config,
|
||||
}
|
||||
crate::register_device!(Ntfy);
|
||||
|
||||
impl Ntfy {
|
||||
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||
struct SendNotification;
|
||||
impl PartialUserData<Ntfy> for SendNotification {
|
||||
fn add_methods<M: mlua::UserDataMethods<Ntfy>>(methods: &mut M) {
|
||||
methods.add_async_method(
|
||||
"send_notification",
|
||||
async |lua, this, notification: mlua::Value| {
|
||||
@@ -109,6 +111,14 @@ impl Ntfy {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn definitions() -> Option<String> {
|
||||
Some(format!(
|
||||
"---@async\n---@param notification {}\nfunction {}:send_notification(notification) end\n",
|
||||
<Notification as Typed>::type_name(),
|
||||
<Ntfy as Typed>::type_name(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
||||
@@ -6,6 +6,7 @@ use automation_lib::action_callback::ActionCallback;
|
||||
use automation_lib::config::MqttDeviceConfig;
|
||||
use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_lib::event::OnMqtt;
|
||||
use automation_lib::lua::traits::PartialUserData;
|
||||
use automation_lib::messages::PresenceMessage;
|
||||
use automation_lib::mqtt::WrappedAsyncClient;
|
||||
use automation_macro::{Device, LuaDeviceConfig};
|
||||
@@ -39,13 +40,29 @@ pub struct State {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Device)]
|
||||
#[device(add_methods = Self::add_methods)]
|
||||
#[device(extra_user_data = OverallPresence)]
|
||||
pub struct Presence {
|
||||
config: Config,
|
||||
state: Arc<RwLock<State>>,
|
||||
}
|
||||
crate::register_device!(Presence);
|
||||
|
||||
struct OverallPresence;
|
||||
impl PartialUserData<Presence> for OverallPresence {
|
||||
fn add_methods<M: mlua::UserDataMethods<Presence>>(methods: &mut M) {
|
||||
methods.add_async_method("overall_presence", async |_lua, this, ()| {
|
||||
Ok(this.state().await.current_overall_presence)
|
||||
});
|
||||
}
|
||||
|
||||
fn definitions() -> Option<String> {
|
||||
Some(format!(
|
||||
"---@async\n---@return boolean\nfunction {}:overall_presence() end\n",
|
||||
<Presence as Typed>::type_name(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Presence {
|
||||
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
||||
self.state.read().await
|
||||
@@ -54,12 +71,6 @@ impl Presence {
|
||||
async fn state_mut(&self) -> RwLockWriteGuard<'_, State> {
|
||||
self.state.write().await
|
||||
}
|
||||
|
||||
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_async_method("overall_presence", async |_lua, this, ()| {
|
||||
Ok(this.state().await.current_overall_presence)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
||||
@@ -10,6 +10,12 @@ pub struct ActionCallback<P> {
|
||||
_parameters: PhantomData<P>,
|
||||
}
|
||||
|
||||
impl Typed for ActionCallback<()> {
|
||||
fn type_name() -> String {
|
||||
"fun() | fun()[]".into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Typed> Typed for ActionCallback<A> {
|
||||
fn type_name() -> String {
|
||||
let type_name = A::type_name();
|
||||
|
||||
@@ -5,7 +5,7 @@ use lua_typed::Typed;
|
||||
use rumqttc::{MqttOptions, Transport};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, Typed)]
|
||||
pub struct MqttConfig {
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
|
||||
@@ -4,6 +4,8 @@ use std::sync::Arc;
|
||||
|
||||
use futures::Future;
|
||||
use futures::future::join_all;
|
||||
use lua_typed::Typed;
|
||||
use mlua::FromLua;
|
||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||
use tokio_cron_scheduler::{Job, JobScheduler};
|
||||
use tracing::{debug, instrument, trace};
|
||||
@@ -13,7 +15,7 @@ use crate::event::{Event, EventChannel, OnMqtt};
|
||||
|
||||
pub type DeviceMap = HashMap<String, Box<dyn Device>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, FromLua)]
|
||||
pub struct DeviceManager {
|
||||
devices: Arc<RwLock<DeviceMap>>,
|
||||
event_channel: EventChannel,
|
||||
@@ -142,3 +144,9 @@ impl mlua::UserData for DeviceManager {
|
||||
methods.add_method("event_channel", |_lua, this, ()| Ok(this.event_channel()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Typed for DeviceManager {
|
||||
fn type_name() -> String {
|
||||
"DeviceManager".into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ pub fn load_modules(lua: &mlua::Lua) -> mlua::Result<()> {
|
||||
for module in inventory::iter::<Module> {
|
||||
debug!(name = module.get_name(), "Loading module");
|
||||
let table = module.register(lua)?;
|
||||
lua.register_module(&format!("automation:{}", module.get_name()), table)?;
|
||||
lua.register_module(module.get_name(), table)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -8,6 +8,10 @@ pub trait PartialUserData<T> {
|
||||
fn interface_name() -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
fn definitions() -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Device;
|
||||
|
||||
@@ -28,4 +28,4 @@ fn create_module(lua: &mlua::Lua) -> mlua::Result<mlua::Table> {
|
||||
Ok(utils)
|
||||
}
|
||||
|
||||
inventory::submit! {Module::new("utils", create_module)}
|
||||
inventory::submit! {Module::new("automation:utils", create_module)}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use lua_typed::Typed;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::task::JoinHandle;
|
||||
use tracing::debug;
|
||||
@@ -74,3 +75,44 @@ impl mlua::UserData for Timeout {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Typed for Timeout {
|
||||
fn type_name() -> String {
|
||||
"Timeout".into()
|
||||
}
|
||||
|
||||
fn generate_header() -> Option<String> {
|
||||
let type_name = Self::type_name();
|
||||
Some(format!("---@class {type_name}\nlocal {type_name}\n"))
|
||||
}
|
||||
|
||||
fn generate_members() -> Option<String> {
|
||||
let mut output = String::new();
|
||||
|
||||
let type_name = Self::type_name();
|
||||
|
||||
output += &format!(
|
||||
"---@async\n---@param timeout number\n---@param callback {}\nfunction {type_name}:start(timeout, callback) end\n",
|
||||
ActionCallback::<()>::type_name()
|
||||
);
|
||||
|
||||
output += &format!("---@async\nfunction {type_name}:cancel() end\n",);
|
||||
|
||||
output +=
|
||||
&format!("---@async\n---@return boolean\nfunction {type_name}:is_waiting() end\n",);
|
||||
|
||||
Some(output)
|
||||
}
|
||||
|
||||
fn generate_footer() -> Option<String> {
|
||||
let mut output = String::new();
|
||||
|
||||
let type_name = Self::type_name();
|
||||
|
||||
output += &format!("utils.{type_name} = {{}}\n");
|
||||
output += &format!("---@return {type_name}\n");
|
||||
output += &format!("function utils.{type_name}.new() end\n");
|
||||
|
||||
Some(output)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use lua_typed::Typed;
|
||||
use mlua::FromLua;
|
||||
use mlua::{FromLua, LuaSerdeExt};
|
||||
use rumqttc::{AsyncClient, Event, EventLoop, Incoming};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use crate::Module;
|
||||
use crate::config::MqttConfig;
|
||||
use crate::device_manager::DeviceManager;
|
||||
use crate::event::{self, EventChannel};
|
||||
|
||||
#[derive(Debug, Clone, FromLua)]
|
||||
@@ -14,6 +17,37 @@ impl Typed for WrappedAsyncClient {
|
||||
fn type_name() -> String {
|
||||
"AsyncClient".into()
|
||||
}
|
||||
|
||||
fn generate_header() -> Option<String> {
|
||||
let type_name = Self::type_name();
|
||||
Some(format!("---@class {type_name}\nlocal {type_name}\n"))
|
||||
}
|
||||
|
||||
fn generate_members() -> Option<String> {
|
||||
let mut output = String::new();
|
||||
|
||||
let type_name = Self::type_name();
|
||||
|
||||
output += &format!(
|
||||
"---@async\n---@param topic string\n---@param message table?\nfunction {type_name}:send_message(topic, message) end\n"
|
||||
);
|
||||
|
||||
Some(output)
|
||||
}
|
||||
|
||||
fn generate_footer() -> Option<String> {
|
||||
let mut output = String::new();
|
||||
|
||||
let type_name = Self::type_name();
|
||||
|
||||
output += &format!("mqtt.{type_name} = {{}}\n");
|
||||
output += &format!("---@param device_manager {}\n", DeviceManager::type_name());
|
||||
output += &format!("---@param config {}\n", MqttConfig::type_name());
|
||||
output += &format!("---@return {type_name}\n");
|
||||
output += "function mqtt.new(device_manager, config) end\n";
|
||||
|
||||
Some(output)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for WrappedAsyncClient {
|
||||
@@ -77,3 +111,25 @@ pub fn start(mut eventloop: EventLoop, event_channel: &EventChannel) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn create_module(lua: &mlua::Lua) -> mlua::Result<mlua::Table> {
|
||||
let mqtt = lua.create_table()?;
|
||||
let mqtt_new = lua.create_function(
|
||||
move |lua, (device_manager, config): (DeviceManager, mlua::Value)| {
|
||||
let event_channel = device_manager.event_channel();
|
||||
let config: MqttConfig = lua.from_value(config)?;
|
||||
|
||||
// Create a mqtt client
|
||||
// TODO: When starting up, the devices are not yet created, this could lead to a device being out of sync
|
||||
let (client, eventloop) = AsyncClient::new(config.into(), 100);
|
||||
start(eventloop, &event_channel);
|
||||
|
||||
Ok(WrappedAsyncClient(client))
|
||||
},
|
||||
)?;
|
||||
mqtt.set("new", mqtt_new)?;
|
||||
|
||||
Ok(mqtt)
|
||||
}
|
||||
|
||||
inventory::submit! {Module::new("automation:mqtt", create_module)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::{ToTokens, quote};
|
||||
use quote::quote;
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::spanned::Spanned;
|
||||
@@ -9,7 +9,7 @@ use syn::{Attribute, DeriveInput, Token, parenthesized};
|
||||
|
||||
enum Attr {
|
||||
Trait(TraitAttr),
|
||||
AddMethods(AddMethodsAttr),
|
||||
ExtraUserData(ExtraUserDataAttr),
|
||||
}
|
||||
|
||||
impl Attr {
|
||||
@@ -20,9 +20,9 @@ impl Attr {
|
||||
let input;
|
||||
_ = parenthesized!(input in meta.input);
|
||||
parsed = Some(Attr::Trait(input.parse()?));
|
||||
} else if meta.path.is_ident("add_methods") {
|
||||
} else if meta.path.is_ident("extra_user_data") {
|
||||
let value = meta.value()?;
|
||||
parsed = Some(Attr::AddMethods(value.parse()?));
|
||||
parsed = Some(Attr::ExtraUserData(value.parse()?));
|
||||
} else {
|
||||
return Err(syn::Error::new(meta.path.span(), "Unknown attribute"));
|
||||
}
|
||||
@@ -95,28 +95,18 @@ impl Parse for Aliases {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct AddMethodsAttr(syn::Path);
|
||||
struct ExtraUserDataAttr(syn::Ident);
|
||||
|
||||
impl Parse for AddMethodsAttr {
|
||||
impl Parse for ExtraUserDataAttr {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
Ok(Self(input.parse()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for AddMethodsAttr {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
let Self(path) = self;
|
||||
|
||||
tokens.extend(quote! {
|
||||
#path
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct Implementation {
|
||||
name: syn::Ident,
|
||||
traits: Traits,
|
||||
add_methods: Vec<AddMethodsAttr>,
|
||||
extra_user_data: Vec<ExtraUserDataAttr>,
|
||||
}
|
||||
|
||||
impl quote::ToTokens for Implementation {
|
||||
@@ -124,9 +114,10 @@ impl quote::ToTokens for Implementation {
|
||||
let Self {
|
||||
name,
|
||||
traits,
|
||||
add_methods,
|
||||
extra_user_data,
|
||||
} = &self;
|
||||
let Traits(traits) = traits;
|
||||
let extra_user_data: Vec<_> = extra_user_data.iter().map(|tr| tr.0.clone()).collect();
|
||||
|
||||
tokens.extend(quote! {
|
||||
impl mlua::UserData for #name {
|
||||
@@ -151,7 +142,7 @@ impl quote::ToTokens for Implementation {
|
||||
)*
|
||||
|
||||
#(
|
||||
#add_methods(methods);
|
||||
<#extra_user_data as ::automation_lib::lua::traits::PartialUserData<#name>>::add_methods(methods);
|
||||
)*
|
||||
}
|
||||
}
|
||||
@@ -178,7 +169,7 @@ impl quote::ToTokens for Implementation {
|
||||
format!(": {interfaces}")
|
||||
};
|
||||
|
||||
Some(format!("---@class {type_name}{interfaces}\nlocal {type_name}"))
|
||||
Some(format!("---@class {type_name}{interfaces}\nlocal {type_name}\n"))
|
||||
}
|
||||
|
||||
fn generate_members() -> Option<String> {
|
||||
@@ -191,6 +182,15 @@ impl quote::ToTokens for Implementation {
|
||||
output += &format!("---@return {type_name}\n");
|
||||
output += &format!("function devices.{type_name}.new(config) end\n");
|
||||
|
||||
output += &<::automation_lib::lua::traits::Device as ::automation_lib::lua::traits::PartialUserData<#name>>::definitions().unwrap_or("".into());
|
||||
|
||||
#(
|
||||
output += &<::automation_lib::lua::traits::#traits as ::automation_lib::lua::traits::PartialUserData<#name>>::definitions().unwrap_or("".into());
|
||||
)*
|
||||
#(
|
||||
output += &<#extra_user_data as ::automation_lib::lua::traits::PartialUserData<#name>>::definitions().unwrap_or("".into());
|
||||
)*
|
||||
|
||||
|
||||
Some(output)
|
||||
}
|
||||
@@ -220,7 +220,7 @@ impl Implementations {
|
||||
all.extend(&attribute.traits);
|
||||
}
|
||||
}
|
||||
Attr::AddMethods(attribute) => add_methods.push(attribute),
|
||||
Attr::ExtraUserData(attribute) => add_methods.push(attribute),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ impl Implementations {
|
||||
.map(|(alias, traits)| Implementation {
|
||||
name: alias.unwrap_or(name.clone()),
|
||||
traits,
|
||||
add_methods: add_methods.clone(),
|
||||
extra_user_data: add_methods.clone(),
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
|
||||
@@ -21,7 +21,7 @@ local fulfillment = {
|
||||
openid_url = "https://login.huizinga.dev/api/oidc",
|
||||
}
|
||||
|
||||
local mqtt_client = require("automation:mqtt").new({
|
||||
local mqtt_client = require("automation:mqtt").new(device_manager, {
|
||||
host = ((host == "zeus" or host == "hephaestus") and "olympus.lan.huizinga.dev") or "mosquitto",
|
||||
port = 8883,
|
||||
client_name = "automation-" .. host,
|
||||
|
||||
22
src/main.rs
22
src/main.rs
@@ -9,18 +9,15 @@ use std::path::Path;
|
||||
use std::process;
|
||||
|
||||
use ::config::{Environment, File};
|
||||
use automation_lib::config::{FulfillmentConfig, MqttConfig};
|
||||
use automation_lib::config::FulfillmentConfig;
|
||||
use automation_lib::device_manager::DeviceManager;
|
||||
use automation_lib::mqtt::{self, WrappedAsyncClient};
|
||||
use axum::extract::{FromRef, State};
|
||||
use axum::http::StatusCode;
|
||||
use axum::routing::post;
|
||||
use axum::{Json, Router};
|
||||
use config::Config;
|
||||
use dotenvy::dotenv;
|
||||
use google_home::{GoogleHome, Request, Response};
|
||||
use mlua::LuaSerdeExt;
|
||||
use rumqttc::AsyncClient;
|
||||
use tokio::net::TcpListener;
|
||||
use tracing::{debug, error, info, warn};
|
||||
use web::{ApiError, User};
|
||||
@@ -75,8 +72,6 @@ async fn fulfillment(
|
||||
}
|
||||
|
||||
async fn app() -> anyhow::Result<()> {
|
||||
dotenv().ok();
|
||||
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
info!(version = VERSION, "automation_rs");
|
||||
@@ -141,21 +136,6 @@ async fn app() -> anyhow::Result<()> {
|
||||
|
||||
automation_lib::load_modules(&lua)?;
|
||||
|
||||
let mqtt = lua.create_table()?;
|
||||
let event_channel = device_manager.event_channel();
|
||||
let mqtt_new = lua.create_function(move |lua, config: mlua::Value| {
|
||||
let config: MqttConfig = lua.from_value(config)?;
|
||||
|
||||
// Create a mqtt client
|
||||
// TODO: When starting up, the devices are not yet created, this could lead to a device being out of sync
|
||||
let (client, eventloop) = AsyncClient::new(config.into(), 100);
|
||||
mqtt::start(eventloop, &event_channel);
|
||||
|
||||
Ok(WrappedAsyncClient(client))
|
||||
})?;
|
||||
mqtt.set("new", mqtt_new)?;
|
||||
lua.register_module("automation:mqtt", mqtt)?;
|
||||
|
||||
lua.register_module("automation:device_manager", device_manager.clone())?;
|
||||
|
||||
lua.register_module("automation:variables", lua.to_value(&config.variables)?)?;
|
||||
|
||||
Reference in New Issue
Block a user