feat: WIP
All checks were successful
Build and deploy / build (push) Successful in 11m41s
Build and deploy / Deploy container (push) Has been skipped

This commit is contained in:
2025-09-18 01:45:31 +02:00
parent 06b3154733
commit f1965d6eef
32 changed files with 778 additions and 52 deletions

View File

@@ -13,6 +13,7 @@ google_home = { workspace = true }
hostname = { workspace = true }
indexmap = { workspace = true }
inventory = { workspace = true }
lua_typed = { workspace = true }
mlua = { workspace = true }
rumqttc = { workspace = true }
serde = { workspace = true }

View File

@@ -1,6 +1,7 @@
use std::marker::PhantomData;
use futures::future::try_join_all;
use lua_typed::Typed;
use mlua::{FromLua, IntoLuaMulti};
#[derive(Debug, Clone)]
@@ -9,6 +10,23 @@ pub struct ActionCallback<P> {
_parameters: PhantomData<P>,
}
impl<A: Typed> Typed for ActionCallback<A> {
fn type_name() -> String {
let type_name = A::type_name();
format!("fun(_: {type_name}) | fun(_: {type_name})[]")
}
}
impl<A: Typed, B: Typed> Typed for ActionCallback<(A, B)> {
fn type_name() -> String {
let type_name_a = A::type_name();
let type_name_b = B::type_name();
format!(
"fun(_: {type_name_a}, _: {type_name_b}) | fun(_: {type_name_a}, _: {type_name_b})[]"
)
}
}
// NOTE: For some reason the derive macro combined with PhantomData leads to issues where it
// requires all types part of P to implement default, even if they never actually get constructed.
// By manually implemented Default it works fine.

View File

@@ -1,6 +1,7 @@
use std::net::{Ipv4Addr, SocketAddr};
use std::time::Duration;
use lua_typed::Typed;
use rumqttc::{MqttOptions, Transport};
use serde::Deserialize;
@@ -52,7 +53,7 @@ fn default_fulfillment_port() -> u16 {
7878
}
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, Deserialize, Typed)]
pub struct InfoConfig {
pub name: String,
pub room: Option<String>,
@@ -68,7 +69,7 @@ impl InfoConfig {
}
}
#[derive(Debug, Clone, Deserialize)]
#[derive(Debug, Clone, Deserialize, Typed)]
pub struct MqttDeviceConfig {
pub topic: String,
}

View File

@@ -1,5 +1,5 @@
#![allow(incomplete_features)]
#![feature(iterator_try_collect)]
#![feature(with_negative_coherence)]
use tracing::debug;

View File

@@ -1,11 +1,18 @@
use std::marker::PhantomData;
use std::ops::Deref;
use lua_typed::Typed;
// TODO: Enable and disable functions based on query_only and command_only
pub trait OnOff {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M)
pub struct OnOff<T> {
_phantom: PhantomData<T>,
}
impl<T: google_home::traits::OnOff + Typed> OnOff<T> {
pub fn add_methods<M: mlua::UserDataMethods<T>>(methods: &mut M)
where
Self: Sized + google_home::traits::OnOff + 'static,
T: Sized + 'static,
{
methods.add_async_method("set_on", async |_lua, this, on: bool| {
this.deref().set_on(on).await.unwrap();
@@ -17,13 +24,27 @@ pub trait OnOff {
Ok(this.deref().on().await.unwrap())
});
}
}
impl<T> OnOff for T where T: google_home::traits::OnOff {}
pub trait Brightness {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M)
pub fn generate_definitions() -> String {
let type_name = T::type_name();
let mut output = String::new();
output +=
&format!("---@async\n---@param on boolean\nfunction {type_name}:set_on(on) end\n");
output += &format!("---@async\n---@return boolean\nfunction {type_name}:on() end\n");
output
}
}
pub struct Brightness<T> {
_phantom: PhantomData<T>,
}
impl<T: google_home::traits::Brightness + Typed> Brightness<T> {
pub fn add_methods<M: mlua::UserDataMethods<T>>(methods: &mut M)
where
Self: Sized + google_home::traits::Brightness + 'static,
T: Sized + 'static,
{
methods.add_async_method("set_brightness", async |_lua, this, brightness: u8| {
this.set_brightness(brightness).await.unwrap();
@@ -35,13 +56,29 @@ pub trait Brightness {
Ok(this.brightness().await.unwrap())
});
}
}
impl<T> Brightness for T where T: google_home::traits::Brightness {}
pub trait ColorSetting {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M)
pub fn generate_definitions() -> String {
let type_name = T::type_name();
let mut output = String::new();
output += &format!(
"---@async\n---@param brightness integer\nfunction {type_name}:set_brightness(brightness) end\n"
);
output +=
&format!("---@async\n---@return integer\nfunction {type_name}:brightness() end\n");
output
}
}
pub struct ColorSetting<T> {
_phantom: PhantomData<T>,
}
impl<T: google_home::traits::ColorSetting + Typed> ColorSetting<T> {
pub fn add_methods<M: mlua::UserDataMethods<T>>(methods: &mut M)
where
Self: Sized + google_home::traits::ColorSetting + 'static,
T: Sized + 'static,
{
methods.add_async_method(
"set_color_temperature",
@@ -58,13 +95,30 @@ pub trait ColorSetting {
Ok(this.color().await.temperature)
});
}
}
impl<T> ColorSetting for T where T: google_home::traits::ColorSetting {}
pub trait OpenClose {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M)
pub fn generate_definitions() -> String {
let type_name = T::type_name();
let mut output = String::new();
output += &format!(
"---@async\n---@param temperature integer\nfunction {type_name}:set_color_temperature(temperature) end\n"
);
output += &format!(
"---@async\n---@return integer\nfunction {type_name}:color_temperature() end\n"
);
output
}
}
pub struct OpenClose<T> {
_phantom: PhantomData<T>,
}
impl<T: google_home::traits::OpenClose + Typed> OpenClose<T> {
pub fn add_methods<M: mlua::UserDataMethods<T>>(methods: &mut M)
where
Self: Sized + google_home::traits::OpenClose + 'static,
T: Sized + 'static,
{
methods.add_async_method("set_open_percent", async |_lua, this, open_percent: u8| {
this.set_open_percent(open_percent).await.unwrap();
@@ -76,5 +130,17 @@ pub trait OpenClose {
Ok(this.open_percent().await.unwrap())
});
}
pub fn generate_definitions() -> String {
let type_name = T::type_name();
let mut output = String::new();
output += &format!(
"---@async\n---@param open_percent integer\nfunction {type_name}:set_open_percent(open_percent) end\n"
);
output +=
&format!("---@async\n---@return integer\nfunction {type_name}:open_percent() end\n");
output
}
}
impl<T> OpenClose for T where T: google_home::traits::OpenClose {}

View File

@@ -1,5 +1,6 @@
use std::ops::{Deref, DerefMut};
use lua_typed::Typed;
use mlua::FromLua;
use rumqttc::{AsyncClient, Event, EventLoop, Incoming};
use tracing::{debug, warn};
@@ -9,6 +10,12 @@ use crate::event::{self, EventChannel};
#[derive(Debug, Clone, FromLua)]
pub struct WrappedAsyncClient(pub AsyncClient);
impl Typed for WrappedAsyncClient {
fn type_name() -> String {
"AsyncClient".into()
}
}
impl Deref for WrappedAsyncClient {
type Target = AsyncClient;