hamqtt 0.1.10

This crate is meant to be an easy to go Home Assistant MQTT implementation
Documentation
//! # Home Assistant MQTT Discovery Payloads
//!
//! This module provides Rust data structures and utility methods for
//! generating MQTT discovery payloads compatible with Home Assistant's
//! MQTT integration.
extern crate alloc;
use alloc::vec::Vec;
use core::fmt::Write;
use heapless::String;
use serde::{Deserialize, Serialize};
/// Represents a physical or logical device in Home Assistant MQTT discovery.
///
/// This struct contains identification and manufacturer details
/// about the device that one or more sensor components belong to.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Device<'a> {
    /// List of unique identifiers for the device.
    /// These are used by Home Assistant to recognize the device uniquely.
    #[serde(rename = "ids")]
    pub identifiers: Vec<&'a str>,

    /// The name of the device (e.g., "Living Room Sensor").
    pub name: &'a str,

    /// Optional model name or number of the device.
    #[serde(rename = "mdl", skip_serializing_if = "Option::is_none")]
    pub model: Option<&'a str>,

    /// Optional manufacturer name of the device.
    #[serde(rename = "mf", skip_serializing_if = "Option::is_none")]
    pub manufacturer: Option<&'a str>,
}

/// Represents a sensor component (entity) for Home Assistant MQTT discovery.
///
/// This struct describes the MQTT discovery configuration payload
/// for a sensor such as temperature, humidity, etc.
#[derive(Serialize, Deserialize, Debug)]
pub struct Component<'a> {
    /// Friendly name of the sensor component.
    pub name: &'a str,

    /// MQTT topic where the sensor publishes its state (sensor readings).
    #[serde(rename = "stat_t")]
    pub state_topic: &'a str,

    /// Optional unit of measurement, e.g. "°C" or "%".
    #[serde(rename = "unit_of_meas", skip_serializing_if = "Option::is_none")]
    pub unit_of_measurement: Option<&'a str>,

    /// Optional device class, indicating the type of sensor.
    /// See https://www.home-assistant.io/integrations/homeassistant/#device-class
    #[serde(rename = "dev_cla", skip_serializing_if = "Option::is_none")]
    pub device_class: Option<&'a str>,

    /// Unique ID of the sensor entity.
    ///
    /// This should be unique across all sensors in Home Assistant to
    /// avoid collisions and enable entity management.
    #[serde(rename = "uniq_id")]
    pub unique_id: &'a str,

    /// Optional Jinja2 template for parsing the MQTT message payload.
    ///
    /// This is used when the sensor payload needs transformation before
    /// Home Assistant can understand it.
    #[serde(rename = "val_tpl", skip_serializing_if = "Option::is_none")]
    pub value_template: Option<&'a str>,

    /// Optional device information to associate this sensor with a device.
    ///
    /// Embeds the `Device` struct describing the physical device that
    /// this sensor component belongs to.
    #[serde(rename = "dev", skip_serializing_if = "Option::is_none")]
    pub device: Option<Device<'a>>,
}

impl<'a> Component<'a> {
    /// Returns the MQTT discovery topic where this component's config
    /// should be published for Home Assistant auto-discovery.
    ///
    /// # Example
    ///
    /// For `unique_id = "livingroom_temp_12"`,
    /// returns `"homeassistant/sensor/livingroom_temp_12/config"`.
    pub fn get_discovery_topic(&self) -> String<256> {
        let mut s: String<256> = String::new();
        write!(s, "homeassistant/sensor/{}/config", self.unique_id).unwrap();
        s
    }
}

// TODO: this could be implemented in the future
// impl Device<'_> {
//     pub fn get_discovery_topic(&self) -> String {
//         let list = vec![self.discovery_prefix, "device", self.unique_id, "config"];
//         list.join("/")
//     }
//     pub fn get_state_topic(&self) -> String {
//         let list = vec![self.discovery_prefix, "device", self.unique_id];
//         list.join("/")
//     }
// }