177 lines
4.1 KiB
Rust
177 lines
4.1 KiB
Rust
use async_trait::async_trait;
|
|
use serde::{Serialize, Deserialize};
|
|
use tracing::{error, debug};
|
|
|
|
use rumqttc::{Publish, Event, Incoming, EventLoop};
|
|
use tokio::sync::watch;
|
|
|
|
#[async_trait]
|
|
pub trait OnMqtt {
|
|
async fn on_mqtt(&mut self, message: &Publish);
|
|
}
|
|
|
|
pub type Receiver = watch::Receiver<Option<Publish>>;
|
|
|
|
pub fn start(mut eventloop: EventLoop) -> Receiver {
|
|
let (tx, rx) = watch::channel(None);
|
|
tokio::spawn(async move {
|
|
debug!("Listening for MQTT events");
|
|
loop {
|
|
let notification = eventloop.poll().await;
|
|
match notification {
|
|
Ok(Event::Incoming(Incoming::Publish(p))) => {
|
|
tx.send(Some(p)).ok();
|
|
},
|
|
Ok(..) => continue,
|
|
Err(err) => {
|
|
error!("{}", err);
|
|
break
|
|
},
|
|
}
|
|
}
|
|
|
|
todo!("Error in MQTT (most likely lost connection to mqtt server), we need to handle these errors!");
|
|
});
|
|
|
|
return rx;
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct OnOffMessage {
|
|
state: String
|
|
}
|
|
|
|
impl OnOffMessage {
|
|
pub fn new(state: bool) -> Self {
|
|
Self { state: if state {"ON"} else {"OFF"}.into() }
|
|
}
|
|
|
|
pub fn state(&self) -> bool {
|
|
self.state == "ON"
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&Publish> for OnOffMessage {
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(message: &Publish) -> Result<Self, Self::Error> {
|
|
serde_json::from_slice(&message.payload)
|
|
.or(Err(anyhow::anyhow!("Invalid message payload received: {:?}", message.payload)))
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct ActivateMessage {
|
|
activate: bool
|
|
}
|
|
|
|
impl ActivateMessage {
|
|
pub fn activate(&self) -> bool {
|
|
self.activate
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&Publish> for ActivateMessage {
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(message: &Publish) -> Result<Self, Self::Error> {
|
|
serde_json::from_slice(&message.payload)
|
|
.or(Err(anyhow::anyhow!("Invalid message payload received: {:?}", message.payload)))
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Copy, Clone)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum RemoteAction {
|
|
On,
|
|
Off,
|
|
BrightnessMoveUp,
|
|
BrightnessMoveDown,
|
|
BrightnessStop,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct RemoteMessage {
|
|
action: RemoteAction
|
|
}
|
|
|
|
impl RemoteMessage {
|
|
pub fn action(&self) -> RemoteAction {
|
|
self.action
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&Publish> for RemoteMessage {
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(message: &Publish) -> Result<Self, Self::Error> {
|
|
serde_json::from_slice(&message.payload)
|
|
.or(Err(anyhow::anyhow!("Invalid message payload received: {:?}", message.payload)))
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Serialize)]
|
|
pub struct PresenceMessage {
|
|
state: bool
|
|
}
|
|
|
|
impl PresenceMessage {
|
|
pub fn new(state: bool) -> Self {
|
|
Self { state }
|
|
}
|
|
|
|
pub fn present(&self) -> bool {
|
|
self.state
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&Publish> for PresenceMessage {
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(message: &Publish) -> Result<Self, Self::Error> {
|
|
serde_json::from_slice(&message.payload)
|
|
.or(Err(anyhow::anyhow!("Invalid message payload received: {:?}", message.payload)))
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct BrightnessMessage {
|
|
illuminance: isize,
|
|
}
|
|
|
|
impl BrightnessMessage {
|
|
pub fn illuminance(&self) -> isize {
|
|
self.illuminance
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&Publish> for BrightnessMessage {
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(message: &Publish) -> Result<Self, Self::Error> {
|
|
serde_json::from_slice(&message.payload)
|
|
.or(Err(anyhow::anyhow!("Invalid message payload received: {:?}", message.payload)))
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct ContactMessage {
|
|
contact: bool,
|
|
}
|
|
|
|
impl ContactMessage {
|
|
pub fn is_closed(&self) -> bool {
|
|
self.contact
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&Publish> for ContactMessage {
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(message: &Publish) -> Result<Self, Self::Error> {
|
|
serde_json::from_slice(&message.payload)
|
|
.or(Err(anyhow::anyhow!("Invalid message payload received: {:?}", message.payload)))
|
|
}
|
|
}
|
|
|