Add mcutie MQTT client implementation and improve library structure
- Integrated `mcutie` library as a core MQTT client for device communication. - Added support for Home Assistant entities (binary sensor, button) via MQTT. - Implemented buffer management, async operations, and packet encoding/decoding. - Introduced structured error handling and device registration features. - Updated `Cargo.toml` with new dependencies and enabled feature flags for `serde` and `log`. - Enhanced logging macros with configurable options (`defmt` or `log`). - Organized codebase into modules (buffer, components, IO, publish, etc.) for better maintainability.
This commit is contained in:
173
Software/MainBoard/rust/src/mcutie_3_0_0/publish.rs
Normal file
173
Software/MainBoard/rust/src/mcutie_3_0_0/publish.rs
Normal file
@@ -0,0 +1,173 @@
|
||||
use core::{fmt::Display, future::Future, ops::Deref};
|
||||
|
||||
use embedded_io::Write;
|
||||
use mqttrs::QoS;
|
||||
|
||||
use crate::{io::publish, Error, Payload, Topic, TopicString};
|
||||
|
||||
/// A message that can be published to an MQTT broker.
|
||||
pub trait Publishable {
|
||||
/// Write this message's topic into the supplied buffer.
|
||||
fn write_topic(&self, buffer: &mut TopicString) -> Result<(), Error>;
|
||||
|
||||
/// Write this message's payload into the supplied buffer.
|
||||
fn write_payload(&self, buffer: &mut Payload) -> Result<(), Error>;
|
||||
|
||||
/// Get this message's QoS level.
|
||||
fn qos(&self) -> QoS {
|
||||
QoS::AtMostOnce
|
||||
}
|
||||
|
||||
/// Whether the broker should retain this message.
|
||||
fn retain(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Publishes this message to the broker. If the stack has not yet been
|
||||
/// initialized this is likely to panic.
|
||||
fn publish(&self) -> impl Future<Output = Result<(), Error>> {
|
||||
async {
|
||||
let mut topic = TopicString::new();
|
||||
self.write_topic(&mut topic)?;
|
||||
|
||||
let mut payload = Payload::new();
|
||||
self.write_payload(&mut payload)?;
|
||||
|
||||
publish(&topic, &payload, self.qos(), self.retain()).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Publishable`] with a raw byte payload.
|
||||
pub struct PublishBytes<'a, T, B: AsRef<[u8]>> {
|
||||
pub(crate) topic: &'a Topic<T>,
|
||||
pub(crate) data: B,
|
||||
pub(crate) qos: QoS,
|
||||
pub(crate) retain: bool,
|
||||
}
|
||||
|
||||
impl<T, B: AsRef<[u8]>> PublishBytes<'_, T, B> {
|
||||
/// Sets the QoS level for this message.
|
||||
pub fn qos(mut self, qos: QoS) -> Self {
|
||||
self.qos = qos;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets whether the broker should retain this message.
|
||||
pub fn retain(mut self, retain: bool) -> Self {
|
||||
self.retain = retain;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Deref<Target = str> + 'a, B: AsRef<[u8]>> Publishable for PublishBytes<'a, T, B> {
|
||||
fn write_topic(&self, buffer: &mut TopicString) -> Result<(), Error> {
|
||||
self.topic.to_string(buffer)
|
||||
}
|
||||
|
||||
fn write_payload(&self, buffer: &mut Payload) -> Result<(), Error> {
|
||||
buffer
|
||||
.write_all(self.data.as_ref())
|
||||
.map_err(|_| Error::TooLarge)
|
||||
}
|
||||
|
||||
fn qos(&self) -> QoS {
|
||||
self.qos
|
||||
}
|
||||
|
||||
fn retain(&self) -> bool {
|
||||
self.retain
|
||||
}
|
||||
|
||||
async fn publish(&self) -> Result<(), Error> {
|
||||
let mut topic = TopicString::new();
|
||||
self.write_topic(&mut topic)?;
|
||||
|
||||
publish(&topic, self.data.as_ref(), self.qos(), self.retain()).await
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Publishable`] with a payload that implements [`Display`].
|
||||
pub struct PublishDisplay<'a, T, D: Display> {
|
||||
pub(crate) topic: &'a Topic<T>,
|
||||
pub(crate) data: D,
|
||||
pub(crate) qos: QoS,
|
||||
pub(crate) retain: bool,
|
||||
}
|
||||
|
||||
impl<T, D: Display> PublishDisplay<'_, T, D> {
|
||||
/// Sets the QoS level for this message.
|
||||
pub fn qos(mut self, qos: QoS) -> Self {
|
||||
self.qos = qos;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets whether the broker should retain this message.
|
||||
pub fn retain(mut self, retain: bool) -> Self {
|
||||
self.retain = retain;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Deref<Target = str> + 'a, D: Display> Publishable for PublishDisplay<'a, T, D> {
|
||||
fn write_topic(&self, buffer: &mut TopicString) -> Result<(), Error> {
|
||||
self.topic.to_string(buffer)
|
||||
}
|
||||
|
||||
fn write_payload(&self, buffer: &mut Payload) -> Result<(), Error> {
|
||||
write!(buffer, "{}", self.data).map_err(|_| Error::TooLarge)
|
||||
}
|
||||
|
||||
fn qos(&self) -> QoS {
|
||||
self.qos
|
||||
}
|
||||
|
||||
fn retain(&self) -> bool {
|
||||
self.retain
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
/// A [`Publishable`] with that serializes a JSON payload.
|
||||
pub struct PublishJson<'a, T, D: serde::Serialize> {
|
||||
pub(crate) topic: &'a Topic<T>,
|
||||
pub(crate) data: D,
|
||||
pub(crate) qos: QoS,
|
||||
pub(crate) retain: bool,
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<T, D: serde::Serialize> PublishJson<'_, T, D> {
|
||||
/// Sets the QoS level for this message.
|
||||
pub fn qos(mut self, qos: QoS) -> Self {
|
||||
self.qos = qos;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets whether the broker should retain this message.
|
||||
pub fn retain(mut self, retain: bool) -> Self {
|
||||
self.retain = retain;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'a, T: Deref<Target = str> + 'a, D: serde::Serialize> Publishable for PublishJson<'a, T, D> {
|
||||
fn write_topic(&self, buffer: &mut TopicString) -> Result<(), Error> {
|
||||
self.topic.to_string(buffer)
|
||||
}
|
||||
|
||||
fn write_payload(&self, buffer: &mut Payload) -> Result<(), Error> {
|
||||
buffer
|
||||
.serialize_json(&self.data)
|
||||
.map_err(|_| Error::TooLarge)
|
||||
}
|
||||
|
||||
fn qos(&self) -> QoS {
|
||||
self.qos
|
||||
}
|
||||
|
||||
fn retain(&self) -> bool {
|
||||
self.retain
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user