Fix MQTT device discovery when using node_id (#142784)

* Fix device discovery when using node_id

* tests

---------

Co-authored-by: jbouwh <jan@jbsoft.nl>
Co-authored-by: Jan Bouwhuis <jbouwh@users.noreply.github.com>
This commit is contained in:
Dionisis Toulatos 2025-04-12 20:30:06 +03:00 committed by GitHub
parent d218ac85f7
commit 3489ea30dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 166 additions and 8 deletions

View File

@ -254,7 +254,7 @@ def _generate_device_config(
comp_config = config[CONF_COMPONENTS] comp_config = config[CONF_COMPONENTS]
for platform, discover_id in mqtt_data.discovery_already_discovered: for platform, discover_id in mqtt_data.discovery_already_discovered:
ids = discover_id.split(" ") ids = discover_id.split(" ")
component_node_id = ids.pop(0) component_node_id = f"{ids.pop(1)} {ids.pop(0)}" if len(ids) > 2 else ids.pop(0)
component_object_id = " ".join(ids) component_object_id = " ".join(ids)
if not ids: if not ids:
continue continue

View File

@ -388,23 +388,181 @@ async def test_only_valid_components(
assert not mock_dispatcher_send.called assert not mock_dispatcher_send.called
async def test_correct_config_discovery( @pytest.mark.parametrize(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator ("discovery_topic", "discovery_hash"),
[
("homeassistant/binary_sensor/bla/config", ("binary_sensor", "bla")),
("homeassistant/binary_sensor/node/bla/config", ("binary_sensor", "node bla")),
],
ids=["without_node", "with_node"],
)
async def test_correct_config_discovery_component(
hass: HomeAssistant,
mqtt_mock_entry: MqttMockHAClientGenerator,
device_registry: dr.DeviceRegistry,
discovery_topic: str,
discovery_hash: tuple[str, str],
) -> None: ) -> None:
"""Test sending in correct JSON.""" """Test sending in correct JSON."""
await mqtt_mock_entry() await mqtt_mock_entry()
config_init = {
"name": "Beer",
"state_topic": "test-topic",
"unique_id": "bla001",
"device": {"identifiers": "0AFFD2", "name": "test_device1"},
"o": {"name": "foobar"},
}
async_fire_mqtt_message( async_fire_mqtt_message(
hass, hass,
"homeassistant/binary_sensor/bla/config", discovery_topic,
'{ "name": "Beer", "state_topic": "test-topic" }', json.dumps(config_init),
) )
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get("binary_sensor.beer") state = hass.states.get("binary_sensor.test_device1_beer")
assert state is not None assert state is not None
assert state.name == "Beer" assert state.name == "test_device1 Beer"
assert ("binary_sensor", "bla") in hass.data["mqtt"].discovery_already_discovered assert discovery_hash in hass.data["mqtt"].discovery_already_discovered
device_entry = device_registry.async_get_device(identifiers={("mqtt", "0AFFD2")})
assert device_entry is not None
assert device_entry.name == "test_device1"
# Update the device and component
config_update = {
"name": "Milk",
"state_topic": "test-topic",
"unique_id": "bla001",
"device": {"identifiers": "0AFFD2", "name": "test_device2"},
"o": {"name": "foobar"},
}
async_fire_mqtt_message(
hass,
discovery_topic,
json.dumps(config_update),
)
await hass.async_block_till_done()
state = hass.states.get("binary_sensor.test_device1_beer")
assert state is not None
assert state.name == "test_device2 Milk"
assert discovery_hash in hass.data["mqtt"].discovery_already_discovered
device_entry = device_registry.async_get_device(identifiers={("mqtt", "0AFFD2")})
assert device_entry is not None
assert device_entry.name == "test_device2"
# Remove the device and component
async_fire_mqtt_message(
hass,
discovery_topic,
"",
)
await hass.async_block_till_done()
state = hass.states.get("binary_sensor.test_device1_beer")
assert state is None
device_entry = device_registry.async_get_device(identifiers={("mqtt", "0AFFD2")})
assert device_entry is None
@pytest.mark.parametrize(
("discovery_topic", "discovery_hash"),
[
("homeassistant/device/some_id/config", ("binary_sensor", "some_id bla")),
(
"homeassistant/device/node_id/some_id/config",
("binary_sensor", "some_id node_id bla"),
),
],
ids=["without_node", "with_node"],
)
async def test_correct_config_discovery_device(
hass: HomeAssistant,
mqtt_mock_entry: MqttMockHAClientGenerator,
device_registry: dr.DeviceRegistry,
discovery_topic: str,
discovery_hash: tuple[str, str],
) -> None:
"""Test sending in correct JSON."""
await mqtt_mock_entry()
config_init = {
"cmps": {
"bla": {
"platform": "binary_sensor",
"name": "Beer",
"state_topic": "test-topic",
"unique_id": "bla001",
},
},
"device": {"identifiers": "0AFFD2", "name": "test_device1"},
"o": {"name": "foobar"},
}
async_fire_mqtt_message(
hass,
discovery_topic,
json.dumps(config_init),
)
await hass.async_block_till_done()
state = hass.states.get("binary_sensor.test_device1_beer")
assert state is not None
assert state.name == "test_device1 Beer"
assert discovery_hash in hass.data["mqtt"].discovery_already_discovered
device_entry = device_registry.async_get_device(identifiers={("mqtt", "0AFFD2")})
assert device_entry is not None
assert device_entry.name == "test_device1"
# Update the device and component
config_update = {
"cmps": {
"bla": {
"platform": "binary_sensor",
"name": "Milk",
"state_topic": "test-topic",
"unique_id": "bla001",
},
},
"device": {"identifiers": "0AFFD2", "name": "test_device2"},
"o": {"name": "foobar"},
}
async_fire_mqtt_message(
hass,
discovery_topic,
json.dumps(config_update),
)
await hass.async_block_till_done()
state = hass.states.get("binary_sensor.test_device1_beer")
assert state is not None
assert state.name == "test_device2 Milk"
assert discovery_hash in hass.data["mqtt"].discovery_already_discovered
device_entry = device_registry.async_get_device(identifiers={("mqtt", "0AFFD2")})
assert device_entry is not None
assert device_entry.name == "test_device2"
# Remove the device and component
async_fire_mqtt_message(
hass,
discovery_topic,
"",
)
await hass.async_block_till_done()
state = hass.states.get("binary_sensor.test_device1_beer")
assert state is None
device_entry = device_registry.async_get_device(identifiers={("mqtt", "0AFFD2")})
assert device_entry is None
@pytest.mark.parametrize( @pytest.mark.parametrize(