automation_rs/src/mqtt.rs

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)))
}
}