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:
9
Cargo.lock
generated
9
Cargo.lock
generated
@@ -119,7 +119,6 @@ dependencies = [
|
||||
"air_filter_types",
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"automation_cast",
|
||||
"automation_lib",
|
||||
"automation_macro",
|
||||
"axum",
|
||||
@@ -127,7 +126,6 @@ dependencies = [
|
||||
"dyn-clone",
|
||||
"eui48",
|
||||
"google_home",
|
||||
"impls",
|
||||
"mlua",
|
||||
"reqwest",
|
||||
"rumqttc",
|
||||
@@ -150,7 +148,6 @@ dependencies = [
|
||||
"dyn-clone",
|
||||
"futures",
|
||||
"google_home",
|
||||
"impls",
|
||||
"indexmap",
|
||||
"mlua",
|
||||
"reqwest",
|
||||
@@ -919,12 +916,6 @@ dependencies = [
|
||||
"icu_properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "impls"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a46645bbd70538861a90d0f26c31537cdf1e44aae99a794fb75a664b70951bc"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.11.0"
|
||||
|
||||
@@ -43,7 +43,6 @@ eui48 = { version = "1.1.0", features = [
|
||||
], default-features = false }
|
||||
futures = "0.3.25"
|
||||
hostname = "0.4.0"
|
||||
impls = "1.0.3"
|
||||
indexmap = { version = "2.0.0", features = ["serde"] }
|
||||
itertools = "0.13.0"
|
||||
json_value_merge = "2.0.0"
|
||||
|
||||
@@ -6,7 +6,6 @@ edition = "2024"
|
||||
[dependencies]
|
||||
automation_lib = { workspace = true }
|
||||
automation_macro = { workspace = true }
|
||||
automation_cast = { workspace = true }
|
||||
google_home = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
async-trait = { workspace = true }
|
||||
@@ -15,7 +14,6 @@ rumqttc = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
impls = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
reqwest = { workspace = true } # Use rustls, since the other packages also use rustls
|
||||
anyhow = { workspace = true }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use async_trait::async_trait;
|
||||
use automation_lib::config::InfoConfig;
|
||||
use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use automation_macro::{LuaDeviceConfig, impl_device};
|
||||
use google_home::device::Name;
|
||||
use google_home::errors::ErrorCode;
|
||||
use google_home::traits::{
|
||||
@@ -62,6 +62,7 @@ impl AirFilter {
|
||||
Ok(reqwest::get(url).await?.json().await?)
|
||||
}
|
||||
}
|
||||
impl_device!(AirFilter);
|
||||
|
||||
#[async_trait]
|
||||
impl LuaDeviceCreate for AirFilter {
|
||||
|
||||
@@ -10,7 +10,7 @@ use automation_lib::event::{OnMqtt, OnPresence};
|
||||
use automation_lib::messages::{ContactMessage, PresenceMessage};
|
||||
use automation_lib::mqtt::WrappedAsyncClient;
|
||||
use automation_lib::presence::DEFAULT_PRESENCE;
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use automation_macro::{LuaDeviceConfig, impl_device};
|
||||
use google_home::device;
|
||||
use google_home::errors::{DeviceError, ErrorCode};
|
||||
use google_home::traits::OpenClose;
|
||||
@@ -66,6 +66,7 @@ pub struct ContactSensor {
|
||||
config: Config,
|
||||
state: Arc<RwLock<State>>,
|
||||
}
|
||||
impl_device!(ContactSensor);
|
||||
|
||||
impl ContactSensor {
|
||||
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
||||
|
||||
@@ -6,7 +6,7 @@ use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_lib::event::{OnDarkness, OnPresence};
|
||||
use automation_lib::messages::{DarknessMessage, PresenceMessage};
|
||||
use automation_lib::mqtt::WrappedAsyncClient;
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use automation_macro::{LuaDeviceConfig, impl_device};
|
||||
use tracing::{trace, warn};
|
||||
|
||||
#[derive(Debug, LuaDeviceConfig, Clone)]
|
||||
@@ -22,6 +22,7 @@ pub struct Config {
|
||||
pub struct DebugBridge {
|
||||
config: Config,
|
||||
}
|
||||
impl_device!(DebugBridge);
|
||||
|
||||
#[async_trait]
|
||||
impl LuaDeviceCreate for DebugBridge {
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::net::SocketAddr;
|
||||
use async_trait::async_trait;
|
||||
use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_lib::event::{OnDarkness, OnPresence};
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use automation_macro::{LuaDeviceConfig, impl_device};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{error, trace, warn};
|
||||
|
||||
@@ -33,6 +33,7 @@ pub struct Config {
|
||||
pub struct HueBridge {
|
||||
config: Config,
|
||||
}
|
||||
impl_device!(HueBridge);
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct FlagMessage {
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::net::SocketAddr;
|
||||
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use automation_macro::{LuaDeviceConfig, impl_device};
|
||||
use google_home::errors::ErrorCode;
|
||||
use google_home::traits::OnOff;
|
||||
use tracing::{error, trace, warn};
|
||||
@@ -23,6 +23,7 @@ pub struct Config {
|
||||
pub struct HueGroup {
|
||||
config: Config,
|
||||
}
|
||||
impl_device!(HueGroup);
|
||||
|
||||
// Couple of helper function to get the correct urls
|
||||
#[async_trait]
|
||||
|
||||
@@ -4,7 +4,7 @@ use automation_lib::config::{InfoConfig, MqttDeviceConfig};
|
||||
use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_lib::event::OnMqtt;
|
||||
use automation_lib::mqtt::WrappedAsyncClient;
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use automation_macro::{LuaDeviceConfig, impl_device};
|
||||
use rumqttc::{Publish, matches};
|
||||
use serde::Deserialize;
|
||||
use tracing::{debug, trace, warn};
|
||||
@@ -55,6 +55,7 @@ struct State {
|
||||
pub struct HueSwitch {
|
||||
config: Config,
|
||||
}
|
||||
impl_device!(HueSwitch);
|
||||
|
||||
impl Device for HueSwitch {
|
||||
fn get_id(&self) -> String {
|
||||
|
||||
@@ -4,7 +4,7 @@ use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_lib::event::OnMqtt;
|
||||
use automation_lib::messages::{RemoteAction, RemoteMessage};
|
||||
use automation_lib::mqtt::WrappedAsyncClient;
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use automation_macro::{LuaDeviceConfig, impl_device};
|
||||
use axum::async_trait;
|
||||
use rumqttc::{Publish, matches};
|
||||
use tracing::{debug, error, trace};
|
||||
@@ -31,6 +31,7 @@ pub struct Config {
|
||||
pub struct IkeaRemote {
|
||||
config: Config,
|
||||
}
|
||||
impl_device!(IkeaRemote);
|
||||
|
||||
impl Device for IkeaRemote {
|
||||
fn get_id(&self) -> String {
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::str::Utf8Error;
|
||||
use async_trait::async_trait;
|
||||
use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_lib::event::OnPresence;
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use automation_macro::{LuaDeviceConfig, impl_device};
|
||||
use bytes::{Buf, BufMut};
|
||||
use google_home::errors::{self, DeviceError};
|
||||
use google_home::traits::OnOff;
|
||||
@@ -26,6 +26,7 @@ pub struct Config {
|
||||
pub struct KasaOutlet {
|
||||
config: Config,
|
||||
}
|
||||
impl_device!(KasaOutlet);
|
||||
|
||||
#[async_trait]
|
||||
impl LuaDeviceCreate for KasaOutlet {
|
||||
|
||||
@@ -11,9 +11,6 @@ mod wake_on_lan;
|
||||
mod washer;
|
||||
mod zigbee;
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use automation_cast::Cast;
|
||||
use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use zigbee::light::{LightBrightness, LightColorTemperature, LightOnOff};
|
||||
use zigbee::outlet::{OutletOnOff, OutletPower};
|
||||
@@ -37,128 +34,6 @@ macro_rules! register_device {
|
||||
};
|
||||
}
|
||||
|
||||
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("on", |_lua, this, _: ()| async move {
|
||||
Ok((this.deref().cast() as Option<&dyn google_home::traits::OnOff>)
|
||||
.expect("Cast should be valid")
|
||||
.on()
|
||||
.await
|
||||
.unwrap())
|
||||
});
|
||||
}
|
||||
|
||||
if impls::impls!($device: google_home::traits::Brightness) {
|
||||
methods.add_async_method("set_brightness", |_lua, this, brightness: u8| async move {
|
||||
(this.deref().cast() as Option<&dyn google_home::traits::Brightness>)
|
||||
.expect("Cast should be valid")
|
||||
.set_brightness(brightness)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_async_method("brightness", |_lua, this, _: ()| async move {
|
||||
Ok((this.deref().cast() as Option<&dyn google_home::traits::Brightness>)
|
||||
.expect("Cast should be valid")
|
||||
.brightness()
|
||||
.await
|
||||
.unwrap())
|
||||
});
|
||||
}
|
||||
|
||||
if impls::impls!($device: google_home::traits::ColorSetting) {
|
||||
methods.add_async_method("set_color_temperature", |_lua, this, temperature: u32| async move {
|
||||
(this.deref().cast() as Option<&dyn google_home::traits::ColorSetting>)
|
||||
.expect("Cast should be valid")
|
||||
.set_color(google_home::traits::Color {temperature})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_async_method("color_temperature", |_lua, this, _: ()| async move {
|
||||
Ok((this.deref().cast() as Option<&dyn google_home::traits::ColorSetting>)
|
||||
.expect("Cast should be valid")
|
||||
.color()
|
||||
.await
|
||||
.temperature)
|
||||
});
|
||||
}
|
||||
|
||||
if impls::impls!($device: google_home::traits::OpenClose) {
|
||||
// TODO: Make discrete_only_open_close and query_only_open_close static, that way we can
|
||||
// add only the supported functions and drop _percet if discrete is true
|
||||
methods.add_async_method("set_open_percent", |_lua, this, open_percent: u8| async move {
|
||||
(this.deref().cast() as Option<&dyn google_home::traits::OpenClose>)
|
||||
.expect("Cast should be valid")
|
||||
.set_open_percent(open_percent)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_async_method("open_percent", |_lua, this, _: ()| async move {
|
||||
Ok((this.deref().cast() as Option<&dyn google_home::traits::OpenClose>)
|
||||
.expect("Cast should be valid")
|
||||
.open_percent()
|
||||
.await
|
||||
.unwrap())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_device!(LightOnOff);
|
||||
impl_device!(LightBrightness);
|
||||
impl_device!(LightColorTemperature);
|
||||
impl_device!(OutletOnOff);
|
||||
impl_device!(OutletPower);
|
||||
impl_device!(AirFilter);
|
||||
impl_device!(ContactSensor);
|
||||
impl_device!(DebugBridge);
|
||||
impl_device!(HueBridge);
|
||||
impl_device!(HueGroup);
|
||||
impl_device!(HueSwitch);
|
||||
impl_device!(IkeaRemote);
|
||||
impl_device!(KasaOutlet);
|
||||
impl_device!(LightSensor);
|
||||
impl_device!(WakeOnLAN);
|
||||
impl_device!(Washer);
|
||||
|
||||
pub fn register_with_lua(lua: &mlua::Lua) -> mlua::Result<()> {
|
||||
register_device!(lua, LightOnOff);
|
||||
register_device!(lua, LightBrightness);
|
||||
|
||||
@@ -6,7 +6,7 @@ use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_lib::event::{self, Event, EventChannel, OnMqtt};
|
||||
use automation_lib::messages::BrightnessMessage;
|
||||
use automation_lib::mqtt::WrappedAsyncClient;
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use automation_macro::{LuaDeviceConfig, impl_device};
|
||||
use rumqttc::Publish;
|
||||
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use tracing::{debug, trace, warn};
|
||||
@@ -36,6 +36,7 @@ pub struct LightSensor {
|
||||
config: Config,
|
||||
state: Arc<RwLock<State>>,
|
||||
}
|
||||
impl_device!(LightSensor);
|
||||
|
||||
impl LightSensor {
|
||||
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
||||
|
||||
@@ -6,7 +6,7 @@ use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_lib::event::OnMqtt;
|
||||
use automation_lib::messages::ActivateMessage;
|
||||
use automation_lib::mqtt::WrappedAsyncClient;
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use automation_macro::{LuaDeviceConfig, impl_device};
|
||||
use eui48::MacAddress;
|
||||
use google_home::device;
|
||||
use google_home::errors::ErrorCode;
|
||||
@@ -32,6 +32,7 @@ pub struct Config {
|
||||
pub struct WakeOnLAN {
|
||||
config: Config,
|
||||
}
|
||||
impl_device!(WakeOnLAN);
|
||||
|
||||
#[async_trait]
|
||||
impl LuaDeviceCreate for WakeOnLAN {
|
||||
|
||||
@@ -7,7 +7,7 @@ use automation_lib::event::{self, Event, EventChannel, OnMqtt};
|
||||
use automation_lib::messages::PowerMessage;
|
||||
use automation_lib::mqtt::WrappedAsyncClient;
|
||||
use automation_lib::ntfy::{Notification, Priority};
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use automation_macro::{LuaDeviceConfig, impl_device};
|
||||
use rumqttc::Publish;
|
||||
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use tracing::{debug, error, trace, warn};
|
||||
@@ -36,6 +36,7 @@ pub struct Washer {
|
||||
config: Config,
|
||||
state: Arc<RwLock<State>>,
|
||||
}
|
||||
impl_device!(Washer);
|
||||
|
||||
impl Washer {
|
||||
async fn state(&self) -> RwLockReadGuard<'_, State> {
|
||||
|
||||
@@ -10,7 +10,7 @@ use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_lib::event::{OnMqtt, OnPresence};
|
||||
use automation_lib::helpers::serialization::state_deserializer;
|
||||
use automation_lib::mqtt::WrappedAsyncClient;
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use automation_macro::{LuaDeviceConfig, impl_device};
|
||||
use google_home::device;
|
||||
use google_home::errors::ErrorCode;
|
||||
use google_home::traits::{Brightness, Color, ColorSetting, ColorTemperatureRange, OnOff};
|
||||
@@ -96,8 +96,11 @@ pub struct Light<T: LightState> {
|
||||
}
|
||||
|
||||
pub type LightOnOff = Light<StateOnOff>;
|
||||
impl_device!(LightOnOff -> OnOff);
|
||||
pub type LightBrightness = Light<StateBrightness>;
|
||||
impl_device!(LightBrightness -> OnOff, Brightness);
|
||||
pub type LightColorTemperature = Light<StateColorTemperature>;
|
||||
impl_device!(LightColorTemperature -> OnOff, Brightness, ColorSetting);
|
||||
|
||||
impl<T: LightState> Light<T> {
|
||||
async fn state(&self) -> RwLockReadGuard<'_, T> {
|
||||
|
||||
@@ -10,7 +10,7 @@ use automation_lib::device::{Device, LuaDeviceCreate};
|
||||
use automation_lib::event::{OnMqtt, OnPresence};
|
||||
use automation_lib::helpers::serialization::state_deserializer;
|
||||
use automation_lib::mqtt::WrappedAsyncClient;
|
||||
use automation_macro::LuaDeviceConfig;
|
||||
use automation_macro::{LuaDeviceConfig, impl_device};
|
||||
use google_home::device;
|
||||
use google_home::errors::ErrorCode;
|
||||
use google_home::traits::OnOff;
|
||||
@@ -92,7 +92,9 @@ pub struct Outlet<T: OutletState> {
|
||||
}
|
||||
|
||||
pub type OutletOnOff = Outlet<StateOnOff>;
|
||||
impl_device!(OutletOnOff -> OnOff);
|
||||
pub type OutletPower = Outlet<StatePower>;
|
||||
impl_device!(OutletPower -> OnOff);
|
||||
|
||||
impl<T: OutletState> Outlet<T> {
|
||||
async fn state(&self) -> RwLockReadGuard<'_, T> {
|
||||
|
||||
@@ -23,4 +23,3 @@ tokio-cron-scheduler = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
dyn-clone = { workspace = true }
|
||||
impls = { workspace = true }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
1
automation_lib/src/lua/mod.rs
Normal file
1
automation_lib/src/lua/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod traits;
|
||||
83
automation_lib/src/lua/traits.rs
Normal file
83
automation_lib/src/lua/traits.rs
Normal 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 {}
|
||||
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
|
||||
70
automation_macro/src/impl_device.rs
Normal file
70
automation_macro/src/impl_device.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::parse::Parse;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::{Path, Token, parse_macro_input};
|
||||
|
||||
struct ImplDevice {
|
||||
ty: Path,
|
||||
impls: Option<Punctuated<Path, Token![,]>>,
|
||||
}
|
||||
|
||||
impl Parse for ImplDevice {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let ty = input.parse()?;
|
||||
let impls = if input.peek(Token![->]) {
|
||||
input.parse::<Token![->]>()?;
|
||||
Some(input.parse_terminated(Path::parse, Token![,])?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(ImplDevice { ty, impls })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn impl_device_macro(input: proc_macro::TokenStream) -> TokenStream {
|
||||
let ImplDevice { ty, impls } = parse_macro_input!(input as ImplDevice);
|
||||
|
||||
let impls: Vec<_> = impls
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|i| {
|
||||
let ident = i
|
||||
.segments
|
||||
.last()
|
||||
.expect("There should be at least one segment")
|
||||
.ident
|
||||
.clone();
|
||||
|
||||
quote! {
|
||||
::automation_lib::lua::traits::#ident::add_methods(methods);
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
quote! {
|
||||
impl mlua::UserData for #ty {
|
||||
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_async_function("new", |_lua, config| async {
|
||||
let device: #ty = 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()) });
|
||||
|
||||
#(
|
||||
#impls
|
||||
)*
|
||||
}
|
||||
}
|
||||
}.into()
|
||||
}
|
||||
@@ -1,12 +1,20 @@
|
||||
#![feature(iter_intersperse)]
|
||||
mod impl_device;
|
||||
mod lua_device_config;
|
||||
|
||||
use lua_device_config::impl_lua_device_config_macro;
|
||||
use syn::{DeriveInput, parse_macro_input};
|
||||
|
||||
use crate::impl_device::impl_device_macro;
|
||||
|
||||
#[proc_macro_derive(LuaDeviceConfig, attributes(device_config))]
|
||||
pub fn lua_device_config_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let ast = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
impl_lua_device_config_macro(&ast).into()
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn impl_device(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
impl_device_macro(input)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user