Align MQTT discovery with v1 format and HA specification

This commit fixes the MQTT discovery payload structure to match the working
v1 implementation and comply with Home Assistant's MQTT discovery specification.

Key changes:
- Add "type" field to discovery payload (sensor/switch)
- Update discovery topic format: homeassistant/{component}/{node_id}/{entity_name}/config
- Fix entity naming: {metric}_{device} instead of descriptive names
- Separate state topics for sensors vs switches:
  * Sensors: pilot/{device}/{metric} (no /state suffix)
  * Switches: pilot/{device}/{metric}/state (with /state suffix)
- Add per-entity availability topics: pilot/{device}/{metric}/available
- Add publish_switch_state() function for proper switch state publishing

Discovery topic examples:
- homeassistant/sensor/asus/cpu_usage_asus/config
- homeassistant/switch/asus/shutdown_asus/config

State topic examples:
- pilot/asus/cpu_usage (sensor)
- pilot/asus/shutdown/state (switch)

This matches the Dell 5520 v1 configuration that works correctly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-30 08:14:44 +01:00
parent df871ddf6e
commit 60b622c6be
3 changed files with 36 additions and 16 deletions
+14 -9
View File
@@ -19,6 +19,8 @@ struct DeviceInfo {
#[derive(Serialize)]
struct EntityConfig<'a> {
name: &'a str,
#[serde(rename = "type")]
entity_type: &'a str,
unique_id: String,
state_topic: String,
availability_topic: String,
@@ -52,7 +54,6 @@ pub async fn publish_all(client: &AsyncClient, cfg: &Config) -> Result<()> {
suggested_area: cfg.device.suggested_area.clone(),
};
let availability = format!("{}/availability", base);
let sensors = vec![
("cpu_usage", "CPU Usage", Some("%"), None, Some("mdi:chip")),
@@ -65,11 +66,13 @@ pub async fn publish_all(client: &AsyncClient, cfg: &Config) -> Result<()> {
];
for (key, name, unit, class, icon) in sensors {
let entity_name = format!("{}_{}", key, cfg.device.name);
let entity = EntityConfig {
name,
name: &entity_name,
entity_type: "sensor",
unique_id: format!("{}_{}", cfg.device.name, key),
state_topic: format!("{}/state/{}", base, key),
availability_topic: availability.clone(),
state_topic: format!("{}/{}", base, key),
availability_topic: format!("{}/{}/available", base, key),
payload_available: "online",
payload_not_available: "offline",
device: DeviceInfo { ..device.clone() },
@@ -80,7 +83,7 @@ pub async fn publish_all(client: &AsyncClient, cfg: &Config) -> Result<()> {
device_class: class,
icon,
};
let topic = format!("{}/sensor/{}/{}_{}", prefix, cfg.device.name, cfg.device.name, key);
let topic = format!("{}/sensor/{}/{}/config", prefix, cfg.device.name, entity_name);
publish_discovery(client, &topic, &entity).await?;
}
@@ -92,11 +95,13 @@ pub async fn publish_all(client: &AsyncClient, cfg: &Config) -> Result<()> {
];
for (key, name, cmd) in switches {
let entity_name = format!("{}_{}", key, cfg.device.name);
let entity = EntityConfig {
name,
name: &entity_name,
entity_type: "switch",
unique_id: format!("{}_{}", cfg.device.name, key),
state_topic: format!("{}/state/{}", base, key),
availability_topic: availability.clone(),
state_topic: format!("{}/{}/state", base, key),
availability_topic: format!("{}/{}/available", base, key),
payload_available: "online",
payload_not_available: "offline",
device: DeviceInfo { ..device.clone() },
@@ -107,7 +112,7 @@ pub async fn publish_all(client: &AsyncClient, cfg: &Config) -> Result<()> {
device_class: Some("switch"),
icon: Some("mdi:power"),
};
let topic = format!("{}/switch/{}/{}_{}", prefix, cfg.device.name, cfg.device.name, key);
let topic = format!("{}/switch/{}/{}/config", prefix, cfg.device.name, entity_name);
publish_discovery(client, &topic, &entity).await?;
}