mirror of
https://github.com/elisspace/core.git
synced 2026-09-30 22:39:55 +00:00
Clear MQTT discovery topic when a disabled entity is removed (#77757)
* Cleanup discovery on entity removal * Add test * Cleanup and test * Test with clearing payload not unique id * Address comments * Tests cover and typing * Just pass hass * reuse code * Follow up comments revert changes to cover tests * Add test unique_id has priority over disabled * Update homeassistant/components/mqtt/__init__.py Co-authored-by: Erik Montnemery <erik@montnemery.com> Co-authored-by: Erik Montnemery <erik@montnemery.com>
This commit is contained in:
committed by
Paulus Schoutsen
co-authored by
Erik Montnemery
parent
d670df74cb
commit
21f6b50f7c
@@ -1,4 +1,5 @@
|
||||
"""The tests for the MQTT discovery."""
|
||||
import copy
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
@@ -23,6 +24,8 @@ from homeassistant.const import (
|
||||
import homeassistant.core as ha
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .test_common import help_test_unload_config_entry
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
async_capture_events,
|
||||
@@ -1356,3 +1359,170 @@ async def test_mqtt_discovery_unsubscribe_once(
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
mqtt_client_mock.unsubscribe.assert_called_once_with("comp/discovery/#")
|
||||
|
||||
|
||||
@patch("homeassistant.components.mqtt.PLATFORMS", [Platform.SENSOR])
|
||||
async def test_clear_config_topic_disabled_entity(
|
||||
hass, mqtt_mock_entry_no_yaml_config, device_reg, caplog
|
||||
):
|
||||
"""Test the discovery topic is removed when a disabled entity is removed."""
|
||||
mqtt_mock = await mqtt_mock_entry_no_yaml_config()
|
||||
# discover an entity that is not enabled by default
|
||||
config = {
|
||||
"name": "sbfspot_12345",
|
||||
"state_topic": "homeassistant_test/sensor/sbfspot_0/sbfspot_12345/",
|
||||
"unique_id": "sbfspot_12345",
|
||||
"enabled_by_default": False,
|
||||
"device": {
|
||||
"identifiers": ["sbfspot_12345"],
|
||||
"name": "sbfspot_12345",
|
||||
"sw_version": "1.0",
|
||||
"connections": [["mac", "12:34:56:AB:CD:EF"]],
|
||||
},
|
||||
}
|
||||
async_fire_mqtt_message(
|
||||
hass,
|
||||
"homeassistant/sensor/sbfspot_0/sbfspot_12345/config",
|
||||
json.dumps(config),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
# discover an entity that is not unique (part 1), will be added
|
||||
config_not_unique1 = copy.deepcopy(config)
|
||||
config_not_unique1["name"] = "sbfspot_12345_1"
|
||||
config_not_unique1["unique_id"] = "not_unique"
|
||||
config_not_unique1.pop("enabled_by_default")
|
||||
async_fire_mqtt_message(
|
||||
hass,
|
||||
"homeassistant/sensor/sbfspot_0/sbfspot_12345_1/config",
|
||||
json.dumps(config_not_unique1),
|
||||
)
|
||||
# discover an entity that is not unique (part 2), will not be added
|
||||
config_not_unique2 = copy.deepcopy(config_not_unique1)
|
||||
config_not_unique2["name"] = "sbfspot_12345_2"
|
||||
async_fire_mqtt_message(
|
||||
hass,
|
||||
"homeassistant/sensor/sbfspot_0/sbfspot_12345_2/config",
|
||||
json.dumps(config_not_unique2),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert "Platform mqtt does not generate unique IDs" in caplog.text
|
||||
|
||||
assert hass.states.get("sensor.sbfspot_12345") is None # disabled
|
||||
assert hass.states.get("sensor.sbfspot_12345_1") is not None # enabled
|
||||
assert hass.states.get("sensor.sbfspot_12345_2") is None # not unique
|
||||
|
||||
# Verify device is created
|
||||
device_entry = device_reg.async_get_device(set(), {("mac", "12:34:56:AB:CD:EF")})
|
||||
assert device_entry is not None
|
||||
|
||||
# Remove the device from the registry
|
||||
device_reg.async_remove_device(device_entry.id)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Assert all valid discovery topics are cleared
|
||||
assert mqtt_mock.async_publish.call_count == 2
|
||||
assert (
|
||||
call("homeassistant/sensor/sbfspot_0/sbfspot_12345/config", "", 0, True)
|
||||
in mqtt_mock.async_publish.mock_calls
|
||||
)
|
||||
assert (
|
||||
call("homeassistant/sensor/sbfspot_0/sbfspot_12345_1/config", "", 0, True)
|
||||
in mqtt_mock.async_publish.mock_calls
|
||||
)
|
||||
|
||||
|
||||
@patch("homeassistant.components.mqtt.PLATFORMS", [Platform.SENSOR])
|
||||
async def test_clean_up_registry_monitoring(
|
||||
hass, mqtt_mock_entry_no_yaml_config, device_reg, tmp_path
|
||||
):
|
||||
"""Test registry monitoring hook is removed after a reload."""
|
||||
await mqtt_mock_entry_no_yaml_config()
|
||||
hooks: dict = hass.data[mqtt.const.DATA_MQTT_DISCOVERY_REGISTRY_HOOKS]
|
||||
# discover an entity that is not enabled by default
|
||||
config1 = {
|
||||
"name": "sbfspot_12345",
|
||||
"state_topic": "homeassistant_test/sensor/sbfspot_0/sbfspot_12345/",
|
||||
"unique_id": "sbfspot_12345",
|
||||
"enabled_by_default": False,
|
||||
"device": {
|
||||
"identifiers": ["sbfspot_12345"],
|
||||
"name": "sbfspot_12345",
|
||||
"sw_version": "1.0",
|
||||
"connections": [["mac", "12:34:56:AB:CD:EF"]],
|
||||
},
|
||||
}
|
||||
# Publish it config
|
||||
# Since it is not enabled_by_default the sensor will not be loaded
|
||||
# it should register a hook for monitoring the entiry registry
|
||||
async_fire_mqtt_message(
|
||||
hass,
|
||||
"homeassistant/sensor/sbfspot_0/sbfspot_12345/config",
|
||||
json.dumps(config1),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hooks) == 1
|
||||
|
||||
# Publish it again no new monitor should be started
|
||||
async_fire_mqtt_message(
|
||||
hass,
|
||||
"homeassistant/sensor/sbfspot_0/sbfspot_12345/config",
|
||||
json.dumps(config1),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hooks) == 1
|
||||
|
||||
# Verify device is created
|
||||
device_entry = device_reg.async_get_device(set(), {("mac", "12:34:56:AB:CD:EF")})
|
||||
assert device_entry is not None
|
||||
|
||||
# Enload the entry
|
||||
# The monitoring should be cleared
|
||||
await help_test_unload_config_entry(hass, tmp_path, {})
|
||||
assert len(hooks) == 0
|
||||
|
||||
|
||||
@patch("homeassistant.components.mqtt.PLATFORMS", [Platform.SENSOR])
|
||||
async def test_unique_id_collission_has_priority(
|
||||
hass, mqtt_mock_entry_no_yaml_config, entity_reg
|
||||
):
|
||||
"""Test tehe unique_id collision detection has priority over registry disabled items."""
|
||||
await mqtt_mock_entry_no_yaml_config()
|
||||
config = {
|
||||
"name": "sbfspot_12345",
|
||||
"state_topic": "homeassistant_test/sensor/sbfspot_0/sbfspot_12345/",
|
||||
"unique_id": "sbfspot_12345",
|
||||
"enabled_by_default": False,
|
||||
"device": {
|
||||
"identifiers": ["sbfspot_12345"],
|
||||
"name": "sbfspot_12345",
|
||||
"sw_version": "1.0",
|
||||
"connections": [["mac", "12:34:56:AB:CD:EF"]],
|
||||
},
|
||||
}
|
||||
# discover an entity that is not unique and disabled by default (part 1), will be added
|
||||
config_not_unique1 = copy.deepcopy(config)
|
||||
config_not_unique1["name"] = "sbfspot_12345_1"
|
||||
config_not_unique1["unique_id"] = "not_unique"
|
||||
async_fire_mqtt_message(
|
||||
hass,
|
||||
"homeassistant/sensor/sbfspot_0/sbfspot_12345_1/config",
|
||||
json.dumps(config_not_unique1),
|
||||
)
|
||||
# discover an entity that is not unique (part 2), will not be added, and the registry entry is cleared
|
||||
config_not_unique2 = copy.deepcopy(config_not_unique1)
|
||||
config_not_unique2["name"] = "sbfspot_12345_2"
|
||||
async_fire_mqtt_message(
|
||||
hass,
|
||||
"homeassistant/sensor/sbfspot_0/sbfspot_12345_2/config",
|
||||
json.dumps(config_not_unique2),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get("sensor.sbfspot_12345_1") is None # not enabled
|
||||
assert hass.states.get("sensor.sbfspot_12345_2") is None # not unique
|
||||
|
||||
# Verify the first entity is created
|
||||
assert entity_reg.async_get("sensor.sbfspot_12345_1") is not None
|
||||
# Verify the second entity is not created because it is not unique
|
||||
assert entity_reg.async_get("sensor.sbfspot_12345_2") is None
|
||||
|
||||
Reference in New Issue
Block a user