Use broadcast for mqtt message so we can have a queue

This commit is contained in:
Dreaded_X 2023-01-10 22:59:26 +01:00
parent 5ee8eaf8fb
commit e9d1cf554d
5 changed files with 19 additions and 39 deletions

View File

@ -95,40 +95,25 @@ pub fn start(mut mqtt_rx: mqtt::Receiver, mut presence_rx: presence::Receiver, m
let (tx, mut rx) = mpsc::channel(100); let (tx, mut rx) = mpsc::channel(100);
tokio::spawn(async move { tokio::spawn(async move {
// @TODO Handle error better
loop { loop {
tokio::select! { tokio::select! {
res = mqtt_rx.changed() => { Ok(message) = mqtt_rx.recv() => {
if !res.is_ok() { devices.on_mqtt(&message).await;
break;
}
// @TODO Not ideal that we have to clone here, but not sure how to work around that
let message = mqtt_rx.borrow().clone();
if let Some(message) = message {
devices.on_mqtt(&message).await;
}
} }
res = presence_rx.changed() => { Ok(_) = presence_rx.changed() => {
if !res.is_ok() {
break;
}
let presence = *presence_rx.borrow(); let presence = *presence_rx.borrow();
devices.on_presence(presence).await; devices.on_presence(presence).await;
} }
res = light_sensor_rx.changed() => { Ok(_) = light_sensor_rx.changed() => {
if !res.is_ok() {
break;
}
let darkness = *light_sensor_rx.borrow(); let darkness = *light_sensor_rx.borrow();
devices.on_darkness(darkness).await; devices.on_darkness(darkness).await;
} }
// @TODO Handle receiving None better, otherwise it might constantly run doing
// nothing
Some(cmd) = rx.recv() => devices.handle_cmd(cmd) Some(cmd) = rx.recv() => devices.handle_cmd(cmd)
} }
} }
unreachable!("Did not expect this");
}); });
return DeviceHandle { tx }; return DeviceHandle { tx };

View File

@ -28,14 +28,12 @@ pub async fn start(mut mqtt_rx: mqtt::Receiver, config: LightSensorConfig, clien
let mut light_sensor = LightSensor { is_dark: is_dark.clone(), mqtt: config.mqtt, min: config.min, max: config.max, tx }; let mut light_sensor = LightSensor { is_dark: is_dark.clone(), mqtt: config.mqtt, min: config.min, max: config.max, tx };
tokio::spawn(async move { tokio::spawn(async move {
while mqtt_rx.changed().await.is_ok() { loop {
let message = mqtt_rx.borrow().clone(); // @TODO Handle errors, warn if lagging
if let Some(message) = message { if let Ok(message) = mqtt_rx.recv().await {
light_sensor.on_mqtt(&message).await; light_sensor.on_mqtt(&message).await;
} }
} }
unreachable!("Did not expect this");
}); });
return is_dark; return is_dark;

View File

@ -8,7 +8,7 @@ use automation::{
config::{Config, OpenIDConfig}, config::{Config, OpenIDConfig},
devices, devices,
hue_bridge::HueBridge, hue_bridge::HueBridge,
light_sensor, mqtt::{self, Mqtt}, light_sensor, mqtt::Mqtt,
ntfy::Ntfy, ntfy::Ntfy,
presence, presence,
}; };

View File

@ -3,15 +3,15 @@ use serde::{Serialize, Deserialize};
use tracing::{error, debug}; use tracing::{error, debug};
use rumqttc::{Publish, Event, Incoming, EventLoop}; use rumqttc::{Publish, Event, Incoming, EventLoop};
use tokio::sync::watch; use tokio::sync::broadcast;
#[async_trait] #[async_trait]
pub trait OnMqtt { pub trait OnMqtt {
async fn on_mqtt(&mut self, message: &Publish); async fn on_mqtt(&mut self, message: &Publish);
} }
pub type Receiver = watch::Receiver<Option<Publish>>; pub type Receiver = broadcast::Receiver<Publish>;
type Sender = watch::Sender<Option<Publish>>; type Sender = broadcast::Sender<Publish>;
pub struct Mqtt { pub struct Mqtt {
tx: Sender, tx: Sender,
@ -20,7 +20,7 @@ pub struct Mqtt {
impl Mqtt { impl Mqtt {
pub fn new(eventloop: EventLoop) -> Self { pub fn new(eventloop: EventLoop) -> Self {
let (tx, _rx) = watch::channel(None); let (tx, _rx) = broadcast::channel(100);
Self { tx, eventloop } Self { tx, eventloop }
} }
@ -35,7 +35,7 @@ impl Mqtt {
let notification = self.eventloop.poll().await; let notification = self.eventloop.poll().await;
match notification { match notification {
Ok(Event::Incoming(Incoming::Publish(p))) => { Ok(Event::Incoming(Incoming::Publish(p))) => {
self.tx.send(Some(p)).ok(); self.tx.send(p).ok();
}, },
Ok(..) => continue, Ok(..) => continue,
Err(err) => { Err(err) => {

View File

@ -30,15 +30,12 @@ pub async fn start(mut mqtt_rx: mqtt::Receiver, mqtt: MqttDeviceConfig, client:
let mut presence = Presence { devices: HashMap::new(), overall_presence: overall_presence.clone(), mqtt, tx }; let mut presence = Presence { devices: HashMap::new(), overall_presence: overall_presence.clone(), mqtt, tx };
tokio::spawn(async move { tokio::spawn(async move {
while mqtt_rx.changed().await.is_ok() { loop {
// @TODO Not ideal that we have to clone here, but not sure how to work around that // @TODO Handle errors, warn if lagging
let message = mqtt_rx.borrow().clone(); if let Ok(message) = mqtt_rx.recv().await {
if let Some(message) = message {
presence.on_mqtt(&message).await; presence.on_mqtt(&message).await;
} }
} }
unreachable!("Did not expect this");
}); });
return overall_presence; return overall_presence;