feat: 通知当前亮度,重构 mqtt 相关代码。#5.

This commit is contained in:
2023-02-19 10:13:45 +08:00
parent 550328ba1e
commit 6e65ef1a4d
10 changed files with 246 additions and 64 deletions

View File

@@ -1,7 +1,7 @@
use paris::error;
use tokio::sync::{broadcast, OnceCell};
use crate::{display, picker::led_color::LedColor};
use crate::{display, picker::led_color::LedColor, models};
use super::mqtt::MqttRpc;
@@ -32,6 +32,10 @@ impl Manager {
}
}
pub async fn listen(&self) {
self.client.listen().await
}
pub async fn publish_led_colors(&self, colors: &Vec<LedColor>) -> anyhow::Result<()> {
let payload = colors
.iter()
@@ -45,6 +49,9 @@ impl Manager {
pub async fn publish_led_sub_pixels(&self, payload: Vec<u8>) -> anyhow::Result<()> {
self.client.publish_led_sub_pixels(payload).await
}
pub async fn publish_desktop_cmd(&self, msg: models::MqMessage) -> anyhow::Result<()> {
self.client.publish_desktop_cmd(msg).await
}
pub fn client(&self) -> &MqttRpc {
&self.client

View File

@@ -1,88 +1,157 @@
use crate::display;
use crate::{display, models};
use image::EncodableLayout;
use paris::warn;
use rumqttc::{AsyncClient, Event, Incoming, MqttOptions, QoS};
use std::time::Duration;
use paris::{warn, info, error};
use rumqttc::{
AsyncClient, ConnectReturnCode, Event, EventLoop, Incoming, MqttOptions, Outgoing, QoS,
};
use std::{borrow::Borrow, rc::Rc, sync::Arc, time::Duration};
use tauri::async_runtime::{Mutex, TokioJoinHandle};
use time::{format_description, OffsetDateTime};
use tokio::{sync::broadcast, task};
use tokio::{sync::broadcast, task, time::sleep};
const DISPLAY_TOPIC: &'static str = "display-ambient-light/display";
const DISPLAY_BRIGHTNESS_TOPIC: &'static str = "display-ambient-light/board/brightness";
const BOARD_SEND_CMD: &'static str = "display-ambient-light/board/cmd";
const DESKTOP_SEND_CMD: &'static str = "display-ambient-light/desktop/cmd";
pub struct MqttRpc {
client: AsyncClient,
change_display_brightness_tx: broadcast::Sender<display::DisplayBrightness>,
message_tx: broadcast::Sender<models::MqMessage>,
eventloop: Arc<Mutex<EventLoop>>,
}
impl MqttRpc {
pub fn new() -> Self {
let mut options = MqttOptions::new("rumqtt-async", "192.168.31.11", 1883);
options.set_keep_alive(Duration::from_secs(5));
options.set_clean_session(false);
let (client, mut eventloop) = AsyncClient::new(options, 10);
let (change_display_brightness_tx, _) =
broadcast::channel::<display::DisplayBrightness>(16);
let change_display_brightness_tx2 = change_display_brightness_tx.clone();
task::spawn(async move {
loop {
match eventloop.poll().await {
Ok(notification) => {
let handled = || -> anyhow::Result<()> {
// println!("MQTT notification = {:?}", notification);
if let Event::Incoming(notification) = notification {
if let Incoming::Publish(notification) = notification {
match notification.topic.as_str() {
DISPLAY_BRIGHTNESS_TOPIC => {
let payload_text = String::from_utf8(
notification.payload.as_bytes().to_owned(),
)
.map_err(|err| {
anyhow::anyhow!("can not parse json. {:?}", err)
})?;
let display_brightness: display::DisplayBrightness =
serde_json::from_str(payload_text.as_str())
.map_err(|err| {
anyhow::anyhow!(
"can not deserialize display brightness. {:?}",
err
)
})?;
change_display_brightness_tx2
.send(display_brightness)
.map_err(|err| {
anyhow::anyhow!(
"can not broadcast display brightness. {:?}",
err
)
})?;
}
&_ => {}
};
}
}
Ok(())
};
if let Err(err) = handled() {
warn!("handle notification was failed. Error: {:?}", err);
}
}
Err(err) => {
println!("MQTT Error Event = {:?}", err);
}
}
}
});
let (message_tx, _) = broadcast::channel::<models::MqMessage>(32);
Self {
client,
change_display_brightness_tx,
message_tx,
eventloop: Arc::new(Mutex::new(eventloop)),
}
}
pub async fn initialize(&mut self) -> anyhow::Result<()> {
pub async fn listen(&self) {
let change_display_brightness_tx2 = self.change_display_brightness_tx.clone();
let message_tx_cloned = self.message_tx.clone();
let mut eventloop = self.eventloop.clone().lock_owned().await;
loop {
match eventloop.poll().await {
Ok(notification) => {
if let Event::Incoming(notification) = notification {
if let Incoming::Publish(notification) = notification {
match notification.topic.as_str() {
DISPLAY_BRIGHTNESS_TOPIC => {
let payload_text = String::from_utf8(
notification.payload.as_bytes().to_owned(),
);
match payload_text {
Ok(payload_text) => {
let display_brightness: Result<
display::DisplayBrightness,
_,
> = serde_json::from_str(payload_text.as_str());
match display_brightness {
Ok(display_brightness) => {
match change_display_brightness_tx2
.send(display_brightness)
{
Ok(_) => {}
Err(err) => {
warn!(
"can not broadcast display brightness. {:?}",
err
);
}
};
}
Err(err) => {
warn!(
"can not deserialize display brightness. {:?}",
err
);
}
}
}
Err(err) => {
warn!(
"can not decode display brightness message. {:?}",
err
);
}
};
}
BOARD_SEND_CMD => {
let payload_text = String::from_utf8(
notification.payload.as_bytes().to_owned(),
);
match payload_text {
Ok(payload_text) => {
let message: Result<models::MqMessage, _> =
serde_json::from_str(payload_text.as_str());
match message {
Ok(message) => {
match message_tx_cloned.send(message) {
Ok(_) => {}
Err(err) => {
warn!(
"can not broadcast mq message. {:?}",
err
);
}
};
}
Err(err) => {
warn!(
"can not deserialize mq message. {:?}",
err
);
}
}
}
Err(err) => {
warn!("can not decode mq message message. {:?}", err);
}
};
}
&_ => {}
};
} else if let Incoming::ConnAck(connAck) = notification {
if connAck.code == ConnectReturnCode::Success {
match self.initialize().await {
Ok(_) => {
info!("resubscribe topics!");
}
Err(err) => {
info!("resubscribe topics failed! {:?}", err);
}
};
}
} else if let Incoming::Disconnect = notification {
error!("MQTT Disconnected!");
}
}
}
Err(err) => {
println!("MQTT Error Event = {:?}", err);
}
}
}
}
pub async fn initialize(&self) -> anyhow::Result<()> {
self.subscribe_board().await?;
self.subscribe_display().await?;
self.broadcast_desktop_online();
@@ -102,7 +171,7 @@ impl MqttRpc {
.map_err(|err| anyhow::anyhow!("subscribe board failed. {:?}", err))
}
fn broadcast_desktop_online(&mut self) {
fn broadcast_desktop_online(&self) {
let client = self.client.to_owned();
task::spawn(async move {
loop {
@@ -146,7 +215,22 @@ impl MqttRpc {
.map_err(|error| anyhow::anyhow!("mqtt publish failed. {}", error))
}
pub fn subscribe_change_display_brightness_rx(&self) -> broadcast::Receiver<display::DisplayBrightness> {
pub fn subscribe_change_display_brightness_rx(
&self,
) -> broadcast::Receiver<display::DisplayBrightness> {
self.change_display_brightness_tx.subscribe()
}
pub async fn publish_desktop_cmd(&self, msg: models::MqMessage) -> anyhow::Result<()> {
let str = serde_json::to_string(&msg)
.map_err(|err| anyhow::anyhow!("can not serialize {:?}. {:?}", msg, err))?;
self.client
.publish(
DESKTOP_SEND_CMD,
rumqttc::QoS::AtLeastOnce,
false,
str.as_bytes(),
)
.await
.map_err(|error| anyhow::anyhow!("mqtt publish failed. {}", error))
}
}