Made the impl_device macro more explicit about the implemented traits

This also converts impl_device into a procedural macro and get rid of a
lot of "magic" that was happening.
This commit is contained in:
2025-08-28 03:02:45 +02:00
parent c5262dcf35
commit d2b01123b8
26 changed files with 197 additions and 208 deletions

View File

@@ -7,51 +7,6 @@ use mlua::ObjectLike;
use crate::event::{OnDarkness, OnMqtt, OnNotification, OnPresence};
// TODO: Make this a proper macro
macro_rules! impl_device {
($device:ty) => {
impl mlua::UserData for $device {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_async_function("new", |_lua, config| async {
let device: $device = LuaDeviceCreate::create(config)
.await
.map_err(mlua::ExternalError::into_lua_err)?;
Ok(device)
});
methods.add_method("__box", |_lua, this, _: ()| {
let b: Box<dyn Device> = Box::new(this.clone());
Ok(b)
});
methods.add_async_method("get_id", |_lua, this, _: ()| async move { Ok(this.get_id()) });
if impls::impls!($device: google_home::traits::OnOff) {
methods.add_async_method("set_on", |_lua, this, on: bool| async move {
(this.deref().cast() as Option<&dyn google_home::traits::OnOff>)
.expect("Cast should be valid")
.set_on(on)
.await
.unwrap();
Ok(())
});
methods.add_async_method("is_on", |_lua, this, _: ()| async move {
Ok((this.deref().cast() as Option<&dyn google_home::traits::OnOff>)
.expect("Cast should be valid")
.on()
.await
.unwrap())
});
}
}
}
};
}
pub(crate) use impl_device;
#[async_trait::async_trait]
pub trait LuaDeviceCreate {
type Config;

View File

@@ -1,5 +1,4 @@
#![allow(incomplete_features)]
#![feature(specialization)]
pub mod action_callback;
pub mod config;
@@ -8,6 +7,7 @@ pub mod device_manager;
pub mod error;
pub mod event;
pub mod helpers;
pub mod lua;
pub mod messages;
pub mod mqtt;
pub mod ntfy;

View File

@@ -0,0 +1 @@
pub mod traits;

View File

@@ -0,0 +1,83 @@
use std::ops::Deref;
// 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)
where
Self: Sized + google_home::traits::OnOff + 'static,
{
methods.add_async_method("set_on", |_lua, this, on: bool| async move {
this.deref().set_on(on).await.unwrap();
Ok(())
});
methods.add_async_method("on", |_lua, this, ()| async move {
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)
where
Self: Sized + google_home::traits::Brightness + 'static,
{
methods.add_async_method("set_brightness", |_lua, this, brightness: u8| async move {
this.set_brightness(brightness).await.unwrap();
Ok(())
});
methods.add_async_method("brightness", |_lua, this, _: ()| async move {
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)
where
Self: Sized + google_home::traits::ColorSetting + 'static,
{
methods.add_async_method(
"set_color_temperature",
|_lua, this, temperature: u32| async move {
this.set_color(google_home::traits::Color { temperature })
.await
.unwrap();
Ok(())
},
);
methods.add_async_method("color_temperature", |_lua, this, ()| async move {
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)
where
Self: Sized + google_home::traits::OpenClose + 'static,
{
methods.add_async_method(
"set_open_percent",
|_lua, this, open_percent: u8| async move {
this.set_open_percent(open_percent).await.unwrap();
Ok(())
},
);
methods.add_async_method("open_percent", |_lua, this, _: ()| async move {
Ok(this.open_percent().await.unwrap())
});
}
}
impl<T> OpenClose for T where T: google_home::traits::OpenClose {}

View File

@@ -1,15 +1,13 @@
use std::collections::HashMap;
use std::convert::Infallible;
use std::ops::Deref;
use async_trait::async_trait;
use automation_cast::Cast;
use automation_macro::LuaDeviceConfig;
use automation_macro::{LuaDeviceConfig, impl_device};
use serde::Serialize;
use serde_repr::*;
use tracing::{error, trace, warn};
use crate::device::{Device, LuaDeviceCreate, impl_device};
use crate::device::{Device, LuaDeviceCreate};
use crate::event::{self, Event, EventChannel, OnNotification, OnPresence};
#[derive(Debug, Serialize_repr, Clone, Copy)]
@@ -125,7 +123,6 @@ pub struct Config {
pub struct Ntfy {
config: Config,
}
impl_device!(Ntfy);
#[async_trait]

View File

@@ -1,16 +1,14 @@
use std::collections::HashMap;
use std::ops::Deref;
use std::sync::Arc;
use async_trait::async_trait;
use automation_cast::Cast;
use automation_macro::LuaDeviceConfig;
use automation_macro::{LuaDeviceConfig, impl_device};
use rumqttc::Publish;
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use tracing::{debug, trace, warn};
use crate::config::MqttDeviceConfig;
use crate::device::{Device, LuaDeviceCreate, impl_device};
use crate::device::{Device, LuaDeviceCreate};
use crate::event::{self, Event, EventChannel, OnMqtt};
use crate::messages::PresenceMessage;
use crate::mqtt::WrappedAsyncClient;
@@ -38,6 +36,7 @@ pub struct Presence {
config: Config,
state: Arc<RwLock<State>>,
}
impl_device!(Presence);
impl Presence {
async fn state(&self) -> RwLockReadGuard<'_, State> {
@@ -49,8 +48,6 @@ impl Presence {
}
}
impl_device!(Presence);
#[async_trait]
impl LuaDeviceCreate for Presence {
type Config = Config;