- 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. fix legacy dependecencies and compatiblity with mcutie vendored lib fix shit i hate this
174 lines
4.6 KiB
Rust
174 lines
4.6 KiB
Rust
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
|
|
}
|
|
}
|