Skip to content

Commit 82a478e

Browse files
authored
Fix MQTT debug info for same topic (#34952)
1 parent 72e7bee commit 82a478e

File tree

2 files changed

+109
-9
lines changed

2 files changed

+109
-9
lines changed

homeassistant/components/mqtt/debug_info.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def _log_message(msg):
2323
debug_info = hass.data[DATA_MQTT_DEBUG_INFO]
2424
messages = debug_info["entities"][entity_id]["subscriptions"][
2525
msg.subscribed_topic
26-
]
26+
]["messages"]
2727
if msg not in messages:
2828
messages.append(msg)
2929

@@ -50,16 +50,27 @@ def add_subscription(hass, message_callback, subscription):
5050
entity_info = debug_info["entities"].setdefault(
5151
entity_id, {"subscriptions": {}, "discovery_data": {}}
5252
)
53-
entity_info["subscriptions"][subscription] = deque([], STORED_MESSAGES)
53+
if subscription not in entity_info["subscriptions"]:
54+
entity_info["subscriptions"][subscription] = {
55+
"count": 0,
56+
"messages": deque([], STORED_MESSAGES),
57+
}
58+
entity_info["subscriptions"][subscription]["count"] += 1
5459

5560

5661
def remove_subscription(hass, message_callback, subscription):
57-
"""Remove debug data for subscription."""
62+
"""Remove debug data for subscription if it exists."""
5863
entity_id = getattr(message_callback, "__entity_id", None)
5964
if entity_id and entity_id in hass.data[DATA_MQTT_DEBUG_INFO]["entities"]:
60-
hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["subscriptions"].pop(
65+
hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["subscriptions"][
6166
subscription
62-
)
67+
]["count"] -= 1
68+
if not hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["subscriptions"][
69+
subscription
70+
]["count"]:
71+
hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["subscriptions"].pop(
72+
subscription
73+
)
6374

6475

6576
def add_entity_discovery_data(hass, discovery_data, entity_id):
@@ -127,10 +138,10 @@ async def info_for_device(hass, device_id):
127138
"topic": topic,
128139
"messages": [
129140
{"payload": msg.payload, "time": msg.timestamp, "topic": msg.topic}
130-
for msg in list(messages)
141+
for msg in list(subscription["messages"])
131142
],
132143
}
133-
for topic, messages in entity_info["subscriptions"].items()
144+
for topic, subscription in entity_info["subscriptions"].items()
134145
]
135146
discovery_data = {
136147
"topic": entity_info["discovery_data"].get(ATTR_DISCOVERY_TOPIC, ""),

tests/components/mqtt/test_init.py

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,42 @@ async def test_mqtt_ws_remove_discovered_device_twice(
956956
assert response["error"]["code"] == websocket_api.const.ERR_NOT_FOUND
957957

958958

959+
async def test_mqtt_ws_remove_discovered_device_same_topic(
960+
hass, device_reg, hass_ws_client, mqtt_mock
961+
):
962+
"""Test MQTT websocket device removal."""
963+
config_entry = MockConfigEntry(domain=mqtt.DOMAIN)
964+
config_entry.add_to_hass(hass)
965+
await async_start(hass, "homeassistant", {}, config_entry)
966+
967+
data = (
968+
'{ "device":{"identifiers":["0AFFD2"]},'
969+
' "state_topic": "foobar/sensor",'
970+
' "availability_topic": "foobar/sensor",'
971+
' "unique_id": "unique" }'
972+
)
973+
974+
async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data)
975+
await hass.async_block_till_done()
976+
977+
device_entry = device_reg.async_get_device({("mqtt", "0AFFD2")}, set())
978+
assert device_entry is not None
979+
980+
client = await hass_ws_client(hass)
981+
await client.send_json(
982+
{"id": 5, "type": "mqtt/device/remove", "device_id": device_entry.id}
983+
)
984+
response = await client.receive_json()
985+
assert response["success"]
986+
987+
await client.send_json(
988+
{"id": 6, "type": "mqtt/device/remove", "device_id": device_entry.id}
989+
)
990+
response = await client.receive_json()
991+
assert not response["success"]
992+
assert response["error"]["code"] == websocket_api.const.ERR_NOT_FOUND
993+
994+
959995
async def test_mqtt_ws_remove_non_mqtt_device(
960996
hass, device_reg, hass_ws_client, mqtt_mock
961997
):
@@ -1302,7 +1338,60 @@ async def test_debug_info_filter_same(hass, mqtt_mock):
13021338
assert {
13031339
"topic": "sensor/#",
13041340
"messages": [
1305-
{"topic": "sensor/abc", "payload": "123", "time": dt1},
1306-
{"topic": "sensor/abc", "payload": "123", "time": dt2},
1341+
{"payload": "123", "time": dt1, "topic": "sensor/abc"},
1342+
{"payload": "123", "time": dt2, "topic": "sensor/abc"},
13071343
],
13081344
} == debug_info_data["entities"][0]["subscriptions"][0]
1345+
1346+
1347+
async def test_debug_info_same_topic(hass, mqtt_mock):
1348+
"""Test debug info."""
1349+
config = {
1350+
"device": {"identifiers": ["helloworld"]},
1351+
"platform": "mqtt",
1352+
"name": "test",
1353+
"state_topic": "sensor/status",
1354+
"availability_topic": "sensor/status",
1355+
"unique_id": "veryunique",
1356+
}
1357+
1358+
entry = MockConfigEntry(domain=mqtt.DOMAIN)
1359+
entry.add_to_hass(hass)
1360+
await async_start(hass, "homeassistant", {}, entry)
1361+
registry = await hass.helpers.device_registry.async_get_registry()
1362+
1363+
data = json.dumps(config)
1364+
async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data)
1365+
await hass.async_block_till_done()
1366+
1367+
device = registry.async_get_device({("mqtt", "helloworld")}, set())
1368+
assert device is not None
1369+
1370+
debug_info_data = await debug_info.info_for_device(hass, device.id)
1371+
assert len(debug_info_data["entities"][0]["subscriptions"]) >= 1
1372+
assert {"topic": "sensor/status", "messages": []} in debug_info_data["entities"][0][
1373+
"subscriptions"
1374+
]
1375+
1376+
start_dt = datetime(2019, 1, 1, 0, 0, 0)
1377+
with patch("homeassistant.util.dt.utcnow") as dt_utcnow:
1378+
dt_utcnow.return_value = start_dt
1379+
async_fire_mqtt_message(hass, "sensor/status", "123", qos=0, retain=False)
1380+
1381+
debug_info_data = await debug_info.info_for_device(hass, device.id)
1382+
assert len(debug_info_data["entities"][0]["subscriptions"]) == 1
1383+
assert {
1384+
"payload": "123",
1385+
"time": start_dt,
1386+
"topic": "sensor/status",
1387+
} in debug_info_data["entities"][0]["subscriptions"][0]["messages"]
1388+
1389+
config["availability_topic"] = "sensor/availability"
1390+
data = json.dumps(config)
1391+
async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data)
1392+
await hass.async_block_till_done()
1393+
1394+
start_dt = datetime(2019, 1, 1, 0, 0, 0)
1395+
with patch("homeassistant.util.dt.utcnow") as dt_utcnow:
1396+
dt_utcnow.return_value = start_dt
1397+
async_fire_mqtt_message(hass, "sensor/status", "123", qos=0, retain=False)

0 commit comments

Comments
 (0)