diff options
| author | diogo464 <[email protected]> | 2026-01-19 20:10:35 +0000 |
|---|---|---|
| committer | diogo464 <[email protected]> | 2026-01-19 20:10:36 +0000 |
| commit | aa47d88882d9bd6c7753315c8fe1b9b2e9b21fa7 (patch) | |
| tree | 12c9e9031a04c169a8218c4028a78ebff036d8f5 | |
| parent | 27779ecf0d7c00ae0acb650c0d75d28edcc3aa89 (diff) | |
fix: prefix discovery unique_id with device id
right now we use the entity id as the unique_id in the entity discovery
payload but we should have been prefixing it with the device_id like
with did for the topics to avoid generating collisions.
for example if we have devices 'relay_0' and 'relay_1' and they both
have a button entity with id 'trigger' then the topics will be
correctly generated using the id 'relay_0_trigger' and
'relay_1_trigger' but the unique id field in the discovery payload
is being set as 'trigger' for both entities which causes this type
of error to show up on the home assistant logs:
2026-01-19 19:52:07.539 ERROR (MainThread) [homeassistant.components.button] Platform mqtt does not generate unique IDs. ID open already exists - ignoring button.porta_frente_abri │
│ 2026-01-19 19:52:07.611 ERROR (MainThread) [homeassistant.components.sensor] Platform mqtt does not generate unique IDs. ID wifi-rssi already exists - ignoring sensor.porta_frente │
│ 2026-01-19 19:56:08.013 ERROR (MainThread) [homeassistant.components.button] Platform mqtt does not generate unique IDs. ID open already exists - ignoring button.porta_frente_abri │
│ 2026-01-19 19:56:08.067 ERROR (MainThread) [homeassistant.components.sensor] Platform mqtt does not generate unique IDs. ID wifi-rssi already exists - ignoring sensor.porta_frente |
| -rw-r--r-- | src/lib.rs | 38 |
1 files changed, 31 insertions, 7 deletions
| @@ -181,11 +181,33 @@ struct DeviceDiscovery<'a> { | |||
| 181 | model: &'a str, | 181 | model: &'a str, |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | #[derive(Debug, Clone, Copy)] | ||
| 185 | #[cfg_attr(feature = "defmt", derive(Format))] | ||
| 186 | struct EntityIdDiscovery<'a> { | ||
| 187 | device_id: &'a str, | ||
| 188 | entity_id: &'a str, | ||
| 189 | } | ||
| 190 | |||
| 191 | impl<'a> core::fmt::Display for EntityIdDiscovery<'a> { | ||
| 192 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
| 193 | write!(f, "{}_{}", self.device_id, self.entity_id) | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | impl<'a> Serialize for EntityIdDiscovery<'a> { | ||
| 198 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||
| 199 | where | ||
| 200 | S: serde::Serializer, | ||
| 201 | { | ||
| 202 | serializer.collect_str(self) | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 184 | #[derive(Debug, Serialize)] | 206 | #[derive(Debug, Serialize)] |
| 185 | #[cfg_attr(feature = "defmt", derive(Format))] | 207 | #[cfg_attr(feature = "defmt", derive(Format))] |
| 186 | struct EntityDiscovery<'a> { | 208 | struct EntityDiscovery<'a> { |
| 187 | #[serde(rename = "unique_id")] | 209 | #[serde(rename = "unique_id")] |
| 188 | id: &'a str, | 210 | id: EntityIdDiscovery<'a>, |
| 189 | 211 | ||
| 190 | #[serde(skip_serializing_if = "Option::is_none")] | 212 | #[serde(skip_serializing_if = "Option::is_none")] |
| 191 | name: Option<&'a str>, | 213 | name: Option<&'a str>, |
| @@ -1006,7 +1028,10 @@ fn generate_entity_discovery( | |||
| 1006 | }; | 1028 | }; |
| 1007 | 1029 | ||
| 1008 | let discovery = EntityDiscovery { | 1030 | let discovery = EntityDiscovery { |
| 1009 | id: entity_config.id, | 1031 | id: EntityIdDiscovery { |
| 1032 | device_id: device_config.device_id, | ||
| 1033 | entity_id: entity_config.id, | ||
| 1034 | }, | ||
| 1010 | name: entity_config.name, | 1035 | name: entity_config.name, |
| 1011 | device_class: entity_config.device_class, | 1036 | device_class: entity_config.device_class, |
| 1012 | state_topic: Some(buffers.state_topic.as_str()), | 1037 | state_topic: Some(buffers.state_topic.as_str()), |
| @@ -1332,11 +1357,10 @@ pub async fn run<T: Transport>(device: &mut Device<'_>, transport: &mut T) -> Re | |||
| 1332 | 1357 | ||
| 1333 | let mut read_buffer = [0u8; 128]; | 1358 | let mut read_buffer = [0u8; 128]; |
| 1334 | let data_len = publish.data_len; | 1359 | let data_len = publish.data_len; |
| 1335 | let receive_data = | 1360 | let receive_data = match mqtt_receive_data(&mut client, data_len, &mut read_buffer).await { |
| 1336 | match mqtt_receive_data(&mut client, data_len, &mut read_buffer).await { | 1361 | Ok(data) => data, |
| 1337 | Ok(data) => data, | 1362 | Err(_) => continue 'outer_loop, |
| 1338 | Err(_) => continue 'outer_loop, | 1363 | }; |
| 1339 | }; | ||
| 1340 | 1364 | ||
| 1341 | let command = match str::from_utf8(receive_data) { | 1365 | let command = match str::from_utf8(receive_data) { |
| 1342 | Ok(command) => command, | 1366 | Ok(command) => command, |
