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:
@@ -19,6 +19,8 @@ struct DeviceInfo {
|
|||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct EntityConfig<'a> {
|
struct EntityConfig<'a> {
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
entity_type: &'a str,
|
||||||
unique_id: String,
|
unique_id: String,
|
||||||
state_topic: String,
|
state_topic: String,
|
||||||
availability_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(),
|
suggested_area: cfg.device.suggested_area.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let availability = format!("{}/availability", base);
|
|
||||||
|
|
||||||
let sensors = vec![
|
let sensors = vec![
|
||||||
("cpu_usage", "CPU Usage", Some("%"), None, Some("mdi:chip")),
|
("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 {
|
for (key, name, unit, class, icon) in sensors {
|
||||||
|
let entity_name = format!("{}_{}", key, cfg.device.name);
|
||||||
let entity = EntityConfig {
|
let entity = EntityConfig {
|
||||||
name,
|
name: &entity_name,
|
||||||
|
entity_type: "sensor",
|
||||||
unique_id: format!("{}_{}", cfg.device.name, key),
|
unique_id: format!("{}_{}", cfg.device.name, key),
|
||||||
state_topic: format!("{}/state/{}", base, key),
|
state_topic: format!("{}/{}", base, key),
|
||||||
availability_topic: availability.clone(),
|
availability_topic: format!("{}/{}/available", base, key),
|
||||||
payload_available: "online",
|
payload_available: "online",
|
||||||
payload_not_available: "offline",
|
payload_not_available: "offline",
|
||||||
device: DeviceInfo { ..device.clone() },
|
device: DeviceInfo { ..device.clone() },
|
||||||
@@ -80,7 +83,7 @@ pub async fn publish_all(client: &AsyncClient, cfg: &Config) -> Result<()> {
|
|||||||
device_class: class,
|
device_class: class,
|
||||||
icon,
|
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?;
|
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 {
|
for (key, name, cmd) in switches {
|
||||||
|
let entity_name = format!("{}_{}", key, cfg.device.name);
|
||||||
let entity = EntityConfig {
|
let entity = EntityConfig {
|
||||||
name,
|
name: &entity_name,
|
||||||
|
entity_type: "switch",
|
||||||
unique_id: format!("{}_{}", cfg.device.name, key),
|
unique_id: format!("{}_{}", cfg.device.name, key),
|
||||||
state_topic: format!("{}/state/{}", base, key),
|
state_topic: format!("{}/{}/state", base, key),
|
||||||
availability_topic: availability.clone(),
|
availability_topic: format!("{}/{}/available", base, key),
|
||||||
payload_available: "online",
|
payload_available: "online",
|
||||||
payload_not_available: "offline",
|
payload_not_available: "offline",
|
||||||
device: DeviceInfo { ..device.clone() },
|
device: DeviceInfo { ..device.clone() },
|
||||||
@@ -107,7 +112,7 @@ pub async fn publish_all(client: &AsyncClient, cfg: &Config) -> Result<()> {
|
|||||||
device_class: Some("switch"),
|
device_class: Some("switch"),
|
||||||
icon: Some("mdi:power"),
|
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?;
|
publish_discovery(client, &topic, &entity).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,14 +97,14 @@ pub async fn publish_capabilities(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publie une valeur de capteur ou d'etat systeme.
|
// Publie une valeur de capteur (sensors: sans /state à la fin).
|
||||||
pub async fn publish_state(
|
pub async fn publish_state(
|
||||||
client: &AsyncClient,
|
client: &AsyncClient,
|
||||||
cfg: &Config,
|
cfg: &Config,
|
||||||
name: &str,
|
name: &str,
|
||||||
value: &str,
|
value: &str,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let topic = format!("{}/state/{}", base_device_topic(cfg), name);
|
let topic = format!("{}/{}", base_device_topic(cfg), name);
|
||||||
client
|
client
|
||||||
.publish(topic, qos(cfg), cfg.mqtt.retain_states, value)
|
.publish(topic, qos(cfg), cfg.mqtt.retain_states, value)
|
||||||
.await
|
.await
|
||||||
@@ -112,6 +112,21 @@ pub async fn publish_state(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Publie l'état d'un switch (avec /state à la fin).
|
||||||
|
pub async fn publish_switch_state(
|
||||||
|
client: &AsyncClient,
|
||||||
|
cfg: &Config,
|
||||||
|
name: &str,
|
||||||
|
value: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
let topic = format!("{}/{}/state", base_device_topic(cfg), name);
|
||||||
|
client
|
||||||
|
.publish(topic, qos(cfg), cfg.mqtt.retain_states, value)
|
||||||
|
.await
|
||||||
|
.context("publish switch state")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// S'abonne aux commandes standard (cmd/<action>/set).
|
// S'abonne aux commandes standard (cmd/<action>/set).
|
||||||
pub async fn subscribe_commands(client: &AsyncClient, cfg: &Config) -> Result<()> {
|
pub async fn subscribe_commands(client: &AsyncClient, cfg: &Config) -> Result<()> {
|
||||||
let topic = format!("{}/cmd/+/set", base_device_topic(cfg));
|
let topic = format!("{}/cmd/+/set", base_device_topic(cfg));
|
||||||
|
|||||||
@@ -310,10 +310,10 @@ async fn handle_command(
|
|||||||
|
|
||||||
// Publie l'etat initial des switches HA (par defaut ON).
|
// Publie l'etat initial des switches HA (par defaut ON).
|
||||||
async fn publish_initial_command_states(client: &rumqttc::AsyncClient, cfg: &Config) {
|
async fn publish_initial_command_states(client: &rumqttc::AsyncClient, cfg: &Config) {
|
||||||
let _ = mqtt::publish_state(client, cfg, "shutdown", "ON").await;
|
let _ = mqtt::publish_switch_state(client, cfg, "shutdown", "ON").await;
|
||||||
let _ = mqtt::publish_state(client, cfg, "reboot", "ON").await;
|
let _ = mqtt::publish_switch_state(client, cfg, "reboot", "ON").await;
|
||||||
let _ = mqtt::publish_state(client, cfg, "sleep", "ON").await;
|
let _ = mqtt::publish_switch_state(client, cfg, "sleep", "ON").await;
|
||||||
let _ = mqtt::publish_state(client, cfg, "screen", "ON").await;
|
let _ = mqtt::publish_switch_state(client, cfg, "screen", "ON").await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publie l'etat d'une commande pour Home Assistant.
|
// Publie l'etat d'une commande pour Home Assistant.
|
||||||
@@ -328,5 +328,5 @@ async fn publish_command_state(
|
|||||||
CommandValue::Off => "OFF",
|
CommandValue::Off => "OFF",
|
||||||
};
|
};
|
||||||
let name = commands::action_name(action);
|
let name = commands::action_name(action);
|
||||||
mqtt::publish_state(client, cfg, name, state).await
|
mqtt::publish_switch_state(client, cfg, name, state).await
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user