feat!: Improve device type registration
All checks were successful
Build and deploy / build (push) Successful in 10m37s
Build and deploy / Deploy container (push) Successful in 38s

Instead of one function that contains all the device types available in
`automation_devices` a global registry is used were each device can
register itself.
This commit is contained in:
2025-09-10 02:59:32 +02:00
parent f0e4c9dd21
commit 4e28ad0f85
16 changed files with 58 additions and 36 deletions

View File

@@ -24,6 +24,7 @@ pub struct Config {
pub struct AirFilter {
config: Config,
}
crate::register_device!(AirFilter);
#[derive(Debug, Error)]
pub enum Error {

View File

@@ -54,6 +54,7 @@ pub struct ContactSensor {
config: Config,
state: Arc<RwLock<State>>,
}
crate::register_device!(ContactSensor);
impl ContactSensor {
async fn state(&self) -> RwLockReadGuard<'_, State> {

View File

@@ -35,6 +35,7 @@ pub struct Config {
pub struct HueBridge {
config: Config,
}
crate::register_device!(HueBridge);
#[derive(Debug, Serialize)]
struct FlagMessage {

View File

@@ -24,6 +24,7 @@ pub struct Config {
pub struct HueGroup {
config: Config,
}
crate::register_device!(HueGroup);
// Couple of helper function to get the correct urls
#[async_trait]

View File

@@ -59,6 +59,7 @@ struct State {
pub struct HueSwitch {
config: Config,
}
crate::register_device!(HueSwitch);
impl Device for HueSwitch {
fn get_id(&self) -> String {

View File

@@ -33,6 +33,7 @@ pub struct Config {
pub struct IkeaRemote {
config: Config,
}
crate::register_device!(IkeaRemote);
impl Device for IkeaRemote {
fn get_id(&self) -> String {

View File

@@ -26,6 +26,7 @@ pub struct Config {
pub struct KasaOutlet {
config: Config,
}
crate::register_device!(KasaOutlet);
#[async_trait]
impl LuaDeviceCreate for KasaOutlet {

View File

@@ -14,48 +14,51 @@ mod zigbee;
use automation_lib::Module;
use automation_lib::device::{Device, LuaDeviceCreate};
use zigbee::light::{LightBrightness, LightColorTemperature, LightOnOff};
use zigbee::outlet::{OutletOnOff, OutletPower};
pub use self::air_filter::AirFilter;
pub use self::contact_sensor::ContactSensor;
pub use self::hue_bridge::HueBridge;
pub use self::hue_group::HueGroup;
pub use self::hue_switch::HueSwitch;
pub use self::ikea_remote::IkeaRemote;
pub use self::kasa_outlet::KasaOutlet;
pub use self::light_sensor::LightSensor;
pub use self::ntfy::*;
pub use self::presence::Presence;
pub use self::wake_on_lan::WakeOnLAN;
pub use self::washer::Washer;
use tracing::debug;
macro_rules! register_device {
($lua:expr, $table:expr, $device:ty) => {
$table.set(stringify!($device), $lua.create_proxy::<$device>()?)?;
($device:ty) => {
::inventory::submit!(crate::RegisteredDevice::new(
stringify!($device),
::mlua::Lua::create_proxy::<$device>
));
};
}
pub(crate) use register_device;
type RegisterFn = fn(lua: &mlua::Lua) -> mlua::Result<mlua::AnyUserData>;
pub struct RegisteredDevice {
name: &'static str,
register_fn: RegisterFn,
}
impl RegisteredDevice {
pub const fn new(name: &'static str, register_fn: RegisterFn) -> Self {
Self { name, register_fn }
}
pub const fn get_name(&self) -> &'static str {
self.name
}
pub fn register(&self, lua: &mlua::Lua) -> mlua::Result<mlua::AnyUserData> {
(self.register_fn)(lua)
}
}
inventory::collect!(RegisteredDevice);
pub fn create_module(lua: &mlua::Lua) -> mlua::Result<mlua::Table> {
let devices = lua.create_table()?;
register_device!(lua, devices, AirFilter);
register_device!(lua, devices, ContactSensor);
register_device!(lua, devices, HueBridge);
register_device!(lua, devices, HueGroup);
register_device!(lua, devices, HueSwitch);
register_device!(lua, devices, IkeaRemote);
register_device!(lua, devices, KasaOutlet);
register_device!(lua, devices, LightBrightness);
register_device!(lua, devices, LightColorTemperature);
register_device!(lua, devices, LightOnOff);
register_device!(lua, devices, LightSensor);
register_device!(lua, devices, Ntfy);
register_device!(lua, devices, OutletOnOff);
register_device!(lua, devices, OutletPower);
register_device!(lua, devices, Presence);
register_device!(lua, devices, WakeOnLAN);
register_device!(lua, devices, Washer);
debug!("Loading devices...");
for device in inventory::iter::<RegisteredDevice> {
debug!(name = device.get_name(), "Registering device");
let proxy = device.register(lua)?;
devices.set(device.get_name(), proxy)?;
}
Ok(devices)
}

View File

@@ -39,6 +39,7 @@ pub struct LightSensor {
config: Config,
state: Arc<RwLock<State>>,
}
crate::register_device!(LightSensor);
impl LightSensor {
async fn state(&self) -> RwLockReadGuard<'_, State> {

View File

@@ -97,6 +97,7 @@ pub struct Config {
pub struct Ntfy {
config: Config,
}
crate::register_device!(Ntfy);
impl Ntfy {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {

View File

@@ -39,6 +39,7 @@ pub struct Presence {
config: Config,
state: Arc<RwLock<State>>,
}
crate::register_device!(Presence);
impl Presence {
async fn state(&self) -> RwLockReadGuard<'_, State> {

View File

@@ -32,6 +32,7 @@ pub struct Config {
pub struct WakeOnLAN {
config: Config,
}
crate::register_device!(WakeOnLAN);
#[async_trait]
impl LuaDeviceCreate for WakeOnLAN {

View File

@@ -38,6 +38,7 @@ pub struct Washer {
config: Config,
state: Arc<RwLock<State>>,
}
crate::register_device!(Washer);
impl Washer {
async fn state(&self) -> RwLockReadGuard<'_, State> {

View File

@@ -99,8 +99,13 @@ pub struct Light<T: LightState> {
}
pub type LightOnOff = Light<StateOnOff>;
crate::register_device!(LightOnOff);
pub type LightBrightness = Light<StateBrightness>;
crate::register_device!(LightBrightness);
pub type LightColorTemperature = Light<StateColorTemperature>;
crate::register_device!(LightColorTemperature);
impl<T: LightState> Light<T> {
async fn state(&self) -> RwLockReadGuard<'_, T> {

View File

@@ -89,7 +89,10 @@ pub struct Outlet<T: OutletState> {
}
pub type OutletOnOff = Outlet<StateOnOff>;
crate::register_device!(OutletOnOff);
pub type OutletPower = Outlet<StatePower>;
crate::register_device!(OutletPower);
impl<T: OutletState> Outlet<T> {
async fn state(&self) -> RwLockReadGuard<'_, T> {

View File

@@ -37,9 +37,8 @@ impl Module {
}
pub fn load_modules(lua: &mlua::Lua) -> mlua::Result<()> {
debug!("Loading modules...");
for module in inventory::iter::<Module> {
debug!(name = module.get_name(), "Registering");
debug!(name = module.get_name(), "Loading module");
let table = module.register(lua)?;
lua.register_module(module.get_name(), table)?;
}