Rewrote impl_cast as a proc_macro to make it easier to work with
This commit is contained in:
parent
b54c9512b9
commit
ca8821b406
44
Cargo.lock
generated
44
Cargo.lock
generated
|
@ -31,7 +31,7 @@ checksum = "2cda8f4bcc10624c4e85bc66b3f452cca98cfa5ca002dc83a16aad2367641bea"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.105",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -42,7 +42,7 @@ checksum = "705339e0e4a9690e2908d2b3d049d85682cf19fbd5782494498fbf7003a6a282"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.105",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -292,7 +292,7 @@ checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.105",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -479,7 +479,8 @@ dependencies = [
|
|||
name = "impl_cast"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"paste",
|
||||
"quote",
|
||||
"syn 2.0.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -659,7 +660,7 @@ checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.105",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -682,18 +683,18 @@ checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7"
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.47"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
|
||||
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.21"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -916,7 +917,7 @@ checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.105",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -947,7 +948,7 @@ checksum = "9a5ec9fa74a20ebbe5d9ac23dac1fc96ba0ecfe9f50f2843b52e537b10fbcb4e"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.105",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1022,6 +1023,17 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "0.1.1"
|
||||
|
@ -1045,7 +1057,7 @@ checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.105",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1098,7 +1110,7 @@ checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.105",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1203,7 +1215,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.105",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1342,7 +1354,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.105",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -1376,7 +1388,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.105",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
|
18
Cargo.toml
18
Cargo.toml
|
@ -11,15 +11,18 @@ members = [
|
|||
|
||||
[dependencies]
|
||||
rumqttc = "0.18"
|
||||
serde = { version ="1.0.149", features = ["derive"] }
|
||||
serde = { version = "1.0.149", features = ["derive"] }
|
||||
serde_json = "1.0.89"
|
||||
impl_cast = {path = "./impl_cast"}
|
||||
google-home = {path = "./google-home"}
|
||||
impl_cast = { path = "./impl_cast", features = ["debug"] }
|
||||
google-home = { path = "./google-home" }
|
||||
paste = "1.0.10"
|
||||
tokio = { version = "1", features = ["rt-multi-thread"] }
|
||||
toml = "0.5.10"
|
||||
dotenvy = "0.15.0"
|
||||
reqwest = { version = "0.11.13", features = ["json", "rustls-tls"], default-features = false } # Use rustls, since the other packages also use rustls
|
||||
reqwest = { version = "0.11.13", features = [
|
||||
"json",
|
||||
"rustls-tls",
|
||||
], default-features = false } # Use rustls, since the other packages also use rustls
|
||||
axum = "0.6.1"
|
||||
serde_repr = "0.1.10"
|
||||
tracing = "0.1.37"
|
||||
|
@ -30,10 +33,13 @@ regex = "1.7.0"
|
|||
async-trait = "0.1.61"
|
||||
async-recursion = "1.0.0"
|
||||
futures = "0.3.25"
|
||||
eui48 = { version = "1.1.0", default-features = false, features = ["disp_hexstring", "serde"] }
|
||||
eui48 = { version = "1.1.0", default-features = false, features = [
|
||||
"disp_hexstring",
|
||||
"serde",
|
||||
] }
|
||||
thiserror = "1.0.38"
|
||||
anyhow = "1.0.68"
|
||||
wakey = "0.3.0"
|
||||
|
||||
[profile.release]
|
||||
lto=true
|
||||
lto = true
|
||||
|
|
|
@ -4,11 +4,12 @@ use crate::{
|
|||
errors::{DeviceError, ErrorCode},
|
||||
request::execute::CommandType,
|
||||
response,
|
||||
traits::{As, OnOff, Scene, Trait},
|
||||
traits::{OnOff, Scene, Trait},
|
||||
types::Type,
|
||||
};
|
||||
|
||||
pub trait GoogleHomeDevice: As<dyn OnOff> + As<dyn Scene> + 'static {
|
||||
#[impl_cast::device(As: OnOff + Scene)]
|
||||
pub trait GoogleHomeDevice: Sync + Send + 'static {
|
||||
fn get_device_type(&self) -> Type;
|
||||
fn get_device_name(&self) -> Name;
|
||||
fn get_id(&self) -> &str;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::{device::GoogleHomeDevice, errors::ErrorCode};
|
||||
use crate::errors::ErrorCode;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub enum Trait {
|
||||
|
@ -10,11 +10,8 @@ pub enum Trait {
|
|||
Scene,
|
||||
}
|
||||
|
||||
impl_cast::impl_setup!();
|
||||
impl_cast::impl_cast!(GoogleHomeDevice, OnOff);
|
||||
impl_cast::impl_cast!(GoogleHomeDevice, Scene);
|
||||
|
||||
pub trait OnOff: std::fmt::Debug + Sync + Send + 'static {
|
||||
#[impl_cast::device_trait]
|
||||
pub trait OnOff {
|
||||
fn is_command_only(&self) -> Option<bool> {
|
||||
None
|
||||
}
|
||||
|
@ -28,7 +25,8 @@ pub trait OnOff: std::fmt::Debug + Sync + Send + 'static {
|
|||
fn set_on(&mut self, on: bool) -> Result<(), ErrorCode>;
|
||||
}
|
||||
|
||||
pub trait Scene: std::fmt::Debug + Sync + Send + 'static {
|
||||
#[impl_cast::device_trait]
|
||||
pub trait Scene {
|
||||
fn is_scene_reversible(&self) -> Option<bool> {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -3,7 +3,13 @@ name = "impl_cast"
|
|||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
paste = "1.0.10"
|
||||
syn = { version = "2.0", features = ["extra-traits", "full"] }
|
||||
quote = "1.0"
|
||||
|
||||
[features]
|
||||
debug = [
|
||||
] # If enabled it will add std::fmt::Debug as a trait bound to device_traits
|
||||
|
|
|
@ -1,47 +1,161 @@
|
|||
pub extern crate paste;
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use syn::{parse::Parse, parse_macro_input, Ident, ItemTrait, Path, Token, TypeParamBound};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_setup {
|
||||
() => {
|
||||
pub trait As<T: ?Sized> {
|
||||
struct Attr {
|
||||
name: Ident,
|
||||
traits: Vec<Path>,
|
||||
}
|
||||
|
||||
impl Parse for Attr {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let mut traits = Vec::new();
|
||||
|
||||
let name = input.parse::<Ident>()?;
|
||||
input.parse::<Token![:]>()?;
|
||||
|
||||
loop {
|
||||
let ty = input.parse()?;
|
||||
traits.push(ty);
|
||||
|
||||
if input.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
input.parse::<Token![+]>()?;
|
||||
}
|
||||
|
||||
Ok(Attr { name, traits })
|
||||
}
|
||||
}
|
||||
|
||||
/// This macro enables optional trait bounds on a trait with an appropriate cast trait to convert
|
||||
/// to the optional traits
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(specialization)]
|
||||
///
|
||||
/// // Create some traits
|
||||
/// #[impl_cast::device_trait]
|
||||
/// trait OnOff {}
|
||||
/// #[impl_cast::device_trait]
|
||||
/// trait Brightness {}
|
||||
///
|
||||
/// // Create the main device trait
|
||||
/// #[impl_cast::device(As: OnOff + Brightness)]
|
||||
/// trait Device {}
|
||||
///
|
||||
/// // Create an implementation
|
||||
/// struct ExampleDevice {}
|
||||
/// impl Device for ExampleDevice {}
|
||||
/// impl OnOff for ExampleDevice {}
|
||||
///
|
||||
/// // Creates a boxed instance of the example device
|
||||
/// let example_device: Box<dyn Device> = Box::new(ExampleDevice {});
|
||||
///
|
||||
/// // Cast to the OnOff trait, which is implemented
|
||||
/// let as_on_off = As::<dyn OnOff>::cast(example_device.as_ref());
|
||||
/// assert!(as_on_off.is_some());
|
||||
///
|
||||
/// // Cast to the Brightness trait, which is not implemented
|
||||
/// let as_on_off = As::<dyn Brightness>::cast(example_device.as_ref());
|
||||
/// assert!(as_on_off.is_none());
|
||||
///
|
||||
/// // Finally we are going to consume the example device into an instance of the OnOff trait
|
||||
/// let consumed = As::<dyn OnOff>::consume(example_device);
|
||||
/// assert!(consumed.is_some())
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn device(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let Attr { name, traits } = parse_macro_input!(attr);
|
||||
let mut interface: ItemTrait = parse_macro_input!(item);
|
||||
|
||||
let prefix = quote! {
|
||||
pub trait #name<T: ?Sized + 'static> {
|
||||
fn consume(self: Box<Self>) -> Option<Box<T>>;
|
||||
fn cast(&self) -> Option<&T>;
|
||||
fn cast_mut(&mut self) -> Option<&mut T>;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_cast {
|
||||
($base:ident, $trait:ident) => {
|
||||
$crate::paste::paste! {
|
||||
impl<T: $base + $trait> As<dyn $trait> for T {
|
||||
fn consume(self: Box<Self>) -> Option<Box<dyn $trait>> {
|
||||
Some(self)
|
||||
}
|
||||
traits.iter().for_each(|device_trait| {
|
||||
interface.supertraits.push(TypeParamBound::Verbatim(quote! {
|
||||
#name<dyn #device_trait>
|
||||
}));
|
||||
});
|
||||
|
||||
fn cast(&self) -> Option<&dyn $trait> {
|
||||
Some(self)
|
||||
}
|
||||
let interface_ident = format_ident!("{}", interface.ident);
|
||||
let impls = traits
|
||||
.iter()
|
||||
.map(|device_trait| {
|
||||
quote! {
|
||||
impl<T> #name<dyn #device_trait> for T
|
||||
where
|
||||
T: #interface_ident + #device_trait + 'static,
|
||||
{
|
||||
fn consume(self: Box<Self>) -> Option<Box<dyn #device_trait>> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn cast_mut(&mut self) -> Option<&mut dyn $trait> {
|
||||
Some(self)
|
||||
}
|
||||
fn cast(&self) -> Option<&(dyn #device_trait + 'static)> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn cast_mut(&mut self) -> Option<&mut (dyn #device_trait + 'static)> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> #name<dyn #device_trait> for T
|
||||
where
|
||||
T: #interface_ident + ?Sized,
|
||||
{
|
||||
default fn consume(self: Box<Self>) -> Option<Box<dyn #device_trait>> {
|
||||
None
|
||||
}
|
||||
|
||||
default fn cast(&self) -> Option<&(dyn #device_trait + 'static)> {
|
||||
None
|
||||
}
|
||||
|
||||
default fn cast_mut(&mut self) -> Option<&mut (dyn #device_trait + 'static)> {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: $base> As<dyn $trait> for T {
|
||||
default fn consume(self: Box<Self>) -> Option<Box<dyn $trait>> {
|
||||
None
|
||||
}
|
||||
|
||||
default fn cast(&self) -> Option<&dyn $trait> {
|
||||
None
|
||||
}
|
||||
|
||||
default fn cast_mut(&mut self) -> Option<&mut dyn $trait> {
|
||||
None
|
||||
}
|
||||
})
|
||||
.fold(quote! {}, |acc, x| {
|
||||
quote! {
|
||||
// Not sure if this is the right way to do this
|
||||
#acc
|
||||
#x
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let tokens = quote! {
|
||||
#interface
|
||||
#prefix
|
||||
#impls
|
||||
};
|
||||
|
||||
tokens.into()
|
||||
}
|
||||
|
||||
// TODO: Not sure if this makes sense to have?
|
||||
/// This macro ensures that the device traits have the correct trait bounds
|
||||
#[proc_macro_attribute]
|
||||
pub fn device_trait(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let mut interface: ItemTrait = parse_macro_input!(item);
|
||||
|
||||
interface.supertraits.push(TypeParamBound::Verbatim(quote! {
|
||||
::core::marker::Sync + ::core::marker::Send + 'static
|
||||
}));
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
interface.supertraits.push(TypeParamBound::Verbatim(quote! {
|
||||
::std::fmt::Debug
|
||||
}));
|
||||
|
||||
interface.into_token_stream().into()
|
||||
}
|
||||
|
|
|
@ -25,48 +25,18 @@ use crate::{
|
|||
presence::{self, OnPresence},
|
||||
};
|
||||
|
||||
impl_cast::impl_setup!();
|
||||
impl_cast::impl_cast!(Device, OnMqtt);
|
||||
impl_cast::impl_cast!(Device, OnPresence);
|
||||
impl_cast::impl_cast!(Device, OnDarkness);
|
||||
impl_cast::impl_cast!(Device, GoogleHomeDevice);
|
||||
impl_cast::impl_cast!(Device, OnOff);
|
||||
|
||||
pub trait Device:
|
||||
As<dyn GoogleHomeDevice>
|
||||
+ As<dyn OnMqtt>
|
||||
+ As<dyn OnPresence>
|
||||
+ As<dyn OnDarkness>
|
||||
+ As<dyn OnOff>
|
||||
+ std::fmt::Debug
|
||||
+ Sync
|
||||
+ Send
|
||||
+ 'static
|
||||
{
|
||||
#[impl_cast::device(As: OnMqtt + OnPresence + OnDarkness + GoogleHomeDevice + OnOff)]
|
||||
pub trait Device: std::fmt::Debug + Sync + Send {
|
||||
fn get_id(&self) -> &str;
|
||||
}
|
||||
|
||||
// TODO: Add an inner type that we can wrap with Arc<RwLock<>> to make this type a little bit nicer
|
||||
// to work with
|
||||
#[derive(Debug)]
|
||||
struct Devices {
|
||||
devices: HashMap<String, Box<dyn Device>>,
|
||||
}
|
||||
|
||||
macro_rules! get_cast {
|
||||
($trait:ident) => {
|
||||
paste::paste! {
|
||||
pub fn [< as_ $trait:snake s >](&mut self) -> HashMap<&str, &mut dyn $trait> {
|
||||
self.devices
|
||||
.iter_mut()
|
||||
.filter_map(|(id, device)| {
|
||||
As::<dyn $trait>::cast_mut(device.as_mut())
|
||||
.map(|listener| (id.as_str(), listener))
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Command {
|
||||
Fullfillment {
|
||||
|
@ -165,7 +135,7 @@ impl Devices {
|
|||
tx,
|
||||
} => {
|
||||
let result =
|
||||
google_home.handle_request(payload, &mut self.as_google_home_devices());
|
||||
google_home.handle_request(payload, &mut self.get::<dyn GoogleHomeDevice>());
|
||||
tx.send(result).ok();
|
||||
}
|
||||
Command::AddDevice { device, tx } => {
|
||||
|
@ -181,41 +151,53 @@ impl Devices {
|
|||
self.devices.insert(device.get_id().to_owned(), device);
|
||||
}
|
||||
|
||||
get_cast!(OnMqtt);
|
||||
get_cast!(OnPresence);
|
||||
get_cast!(OnDarkness);
|
||||
get_cast!(GoogleHomeDevice);
|
||||
fn get<T>(&mut self) -> HashMap<&str, &mut T>
|
||||
where
|
||||
T: ?Sized + 'static,
|
||||
(dyn Device): As<T>,
|
||||
{
|
||||
self.devices
|
||||
.iter_mut()
|
||||
.filter_map(|(id, device)| As::<T>::cast_mut(device.as_mut()).map(|t| (id.as_str(), t)))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl OnMqtt for Devices {
|
||||
async fn on_mqtt(&mut self, message: &rumqttc::Publish) {
|
||||
self.as_on_mqtts().iter_mut().for_each(|(id, listener)| {
|
||||
let _span = span!(Level::TRACE, "on_mqtt").entered();
|
||||
trace!(id, "Handling");
|
||||
listener.on_mqtt(message).block_on();
|
||||
})
|
||||
self.get::<dyn OnMqtt>()
|
||||
.iter_mut()
|
||||
.for_each(|(id, listener)| {
|
||||
let _span = span!(Level::TRACE, "on_mqtt").entered();
|
||||
trace!(id, "Handling");
|
||||
listener.on_mqtt(message).block_on();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl OnPresence for Devices {
|
||||
async fn on_presence(&mut self, presence: bool) {
|
||||
self.as_on_presences().iter_mut().for_each(|(id, device)| {
|
||||
let _span = span!(Level::TRACE, "on_presence").entered();
|
||||
trace!(id, "Handling");
|
||||
device.on_presence(presence).block_on();
|
||||
})
|
||||
self.get::<dyn OnPresence>()
|
||||
.iter_mut()
|
||||
.for_each(|(id, device)| {
|
||||
let _span = span!(Level::TRACE, "on_presence").entered();
|
||||
trace!(id, "Handling");
|
||||
device.on_presence(presence).block_on();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl OnDarkness for Devices {
|
||||
async fn on_darkness(&mut self, dark: bool) {
|
||||
self.as_on_darknesss().iter_mut().for_each(|(id, device)| {
|
||||
let _span = span!(Level::TRACE, "on_darkness").entered();
|
||||
trace!(id, "Handling");
|
||||
device.on_darkness(dark).block_on();
|
||||
})
|
||||
self.get::<dyn OnDarkness>()
|
||||
.iter_mut()
|
||||
.for_each(|(id, device)| {
|
||||
let _span = span!(Level::TRACE, "on_darkness").entered();
|
||||
trace!(id, "Handling");
|
||||
device.on_darkness(dark).block_on();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ pub trait OnDarkness: Sync + Send + 'static {
|
|||
pub type Receiver = watch::Receiver<bool>;
|
||||
type Sender = watch::Sender<bool>;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LightSensor {
|
||||
mqtt: MqttDeviceConfig,
|
||||
min: isize,
|
||||
|
|
|
@ -10,7 +10,8 @@ use rumqttc::{Event, EventLoop, Incoming, Publish};
|
|||
use tokio::sync::broadcast;
|
||||
|
||||
#[async_trait]
|
||||
pub trait OnMqtt: Sync + Send + 'static {
|
||||
#[impl_cast::device_trait]
|
||||
pub trait OnMqtt {
|
||||
async fn on_mqtt(&mut self, message: &Publish);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ pub trait OnPresence: Sync + Send + 'static {
|
|||
pub type Receiver = watch::Receiver<bool>;
|
||||
type Sender = watch::Sender<bool>;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Presence {
|
||||
devices: HashMap<String, bool>,
|
||||
mqtt: MqttDeviceConfig,
|
||||
|
|
Loading…
Reference in New Issue
Block a user