mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 17:57:11 +00:00
Improve MQTT debug info for subscriptions with wildcard (#33752)
This commit is contained in:
parent
3697ea7b27
commit
ddef681dd2
@ -21,8 +21,10 @@ def log_messages(hass: HomeAssistantType, entity_id: str) -> MessageCallbackType
|
|||||||
def _log_message(msg):
|
def _log_message(msg):
|
||||||
"""Log message."""
|
"""Log message."""
|
||||||
debug_info = hass.data[DATA_MQTT_DEBUG_INFO]
|
debug_info = hass.data[DATA_MQTT_DEBUG_INFO]
|
||||||
messages = debug_info["entities"][entity_id]["topics"][msg.subscribed_topic]
|
messages = debug_info["entities"][entity_id]["subscriptions"][
|
||||||
messages.append(msg.payload)
|
msg.subscribed_topic
|
||||||
|
]
|
||||||
|
messages.append((msg.payload, msg.topic))
|
||||||
|
|
||||||
def _decorator(msg_callback: MessageCallbackType):
|
def _decorator(msg_callback: MessageCallbackType):
|
||||||
@wraps(msg_callback)
|
@wraps(msg_callback)
|
||||||
@ -37,24 +39,26 @@ def log_messages(hass: HomeAssistantType, entity_id: str) -> MessageCallbackType
|
|||||||
return _decorator
|
return _decorator
|
||||||
|
|
||||||
|
|
||||||
def add_topic(hass, message_callback, topic):
|
def add_subscription(hass, message_callback, subscription):
|
||||||
"""Prepare debug data for topic."""
|
"""Prepare debug data for subscription."""
|
||||||
entity_id = getattr(message_callback, "__entity_id", None)
|
entity_id = getattr(message_callback, "__entity_id", None)
|
||||||
if entity_id:
|
if entity_id:
|
||||||
debug_info = hass.data.setdefault(
|
debug_info = hass.data.setdefault(
|
||||||
DATA_MQTT_DEBUG_INFO, {"entities": {}, "triggers": {}}
|
DATA_MQTT_DEBUG_INFO, {"entities": {}, "triggers": {}}
|
||||||
)
|
)
|
||||||
entity_info = debug_info["entities"].setdefault(
|
entity_info = debug_info["entities"].setdefault(
|
||||||
entity_id, {"topics": {}, "discovery_data": {}}
|
entity_id, {"subscriptions": {}, "discovery_data": {}}
|
||||||
)
|
)
|
||||||
entity_info["topics"][topic] = deque([], STORED_MESSAGES)
|
entity_info["subscriptions"][subscription] = deque([], STORED_MESSAGES)
|
||||||
|
|
||||||
|
|
||||||
def remove_topic(hass, message_callback, topic):
|
def remove_subscription(hass, message_callback, subscription):
|
||||||
"""Remove debug data for topic."""
|
"""Remove debug data for subscription."""
|
||||||
entity_id = getattr(message_callback, "__entity_id", None)
|
entity_id = getattr(message_callback, "__entity_id", None)
|
||||||
if entity_id and entity_id in hass.data[DATA_MQTT_DEBUG_INFO]["entities"]:
|
if entity_id and entity_id in hass.data[DATA_MQTT_DEBUG_INFO]["entities"]:
|
||||||
hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["topics"].pop(topic)
|
hass.data[DATA_MQTT_DEBUG_INFO]["entities"][entity_id]["subscriptions"].pop(
|
||||||
|
subscription
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def add_entity_discovery_data(hass, discovery_data, entity_id):
|
def add_entity_discovery_data(hass, discovery_data, entity_id):
|
||||||
@ -63,7 +67,7 @@ def add_entity_discovery_data(hass, discovery_data, entity_id):
|
|||||||
DATA_MQTT_DEBUG_INFO, {"entities": {}, "triggers": {}}
|
DATA_MQTT_DEBUG_INFO, {"entities": {}, "triggers": {}}
|
||||||
)
|
)
|
||||||
entity_info = debug_info["entities"].setdefault(
|
entity_info = debug_info["entities"].setdefault(
|
||||||
entity_id, {"topics": {}, "discovery_data": {}}
|
entity_id, {"subscriptions": {}, "discovery_data": {}}
|
||||||
)
|
)
|
||||||
entity_info["discovery_data"] = discovery_data
|
entity_info["discovery_data"] = discovery_data
|
||||||
|
|
||||||
@ -117,9 +121,14 @@ async def info_for_device(hass, device_id):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
entity_info = mqtt_debug_info["entities"][entry.entity_id]
|
entity_info = mqtt_debug_info["entities"][entry.entity_id]
|
||||||
topics = [
|
subscriptions = [
|
||||||
{"topic": topic, "messages": list(messages)}
|
{
|
||||||
for topic, messages in entity_info["topics"].items()
|
"topic": topic,
|
||||||
|
"messages": [
|
||||||
|
{"payload": msg[0], "topic": msg[1]} for msg in list(messages)
|
||||||
|
],
|
||||||
|
}
|
||||||
|
for topic, messages in entity_info["subscriptions"].items()
|
||||||
]
|
]
|
||||||
discovery_data = {
|
discovery_data = {
|
||||||
"topic": entity_info["discovery_data"].get(ATTR_DISCOVERY_TOPIC, ""),
|
"topic": entity_info["discovery_data"].get(ATTR_DISCOVERY_TOPIC, ""),
|
||||||
@ -128,7 +137,7 @@ async def info_for_device(hass, device_id):
|
|||||||
mqtt_info["entities"].append(
|
mqtt_info["entities"].append(
|
||||||
{
|
{
|
||||||
"entity_id": entry.entity_id,
|
"entity_id": entry.entity_id,
|
||||||
"topics": topics,
|
"subscriptions": subscriptions,
|
||||||
"discovery_data": discovery_data,
|
"discovery_data": discovery_data,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -34,14 +34,16 @@ class EntitySubscription:
|
|||||||
if other is not None and other.unsubscribe_callback is not None:
|
if other is not None and other.unsubscribe_callback is not None:
|
||||||
other.unsubscribe_callback()
|
other.unsubscribe_callback()
|
||||||
# Clear debug data if it exists
|
# Clear debug data if it exists
|
||||||
debug_info.remove_topic(self.hass, other.message_callback, other.topic)
|
debug_info.remove_subscription(
|
||||||
|
self.hass, other.message_callback, other.topic
|
||||||
|
)
|
||||||
|
|
||||||
if self.topic is None:
|
if self.topic is None:
|
||||||
# We were asked to remove the subscription or not to create it
|
# We were asked to remove the subscription or not to create it
|
||||||
return
|
return
|
||||||
|
|
||||||
# Prepare debug data
|
# Prepare debug data
|
||||||
debug_info.add_topic(self.hass, self.message_callback, self.topic)
|
debug_info.add_subscription(self.hass, self.message_callback, self.topic)
|
||||||
|
|
||||||
self.unsubscribe_callback = await mqtt.async_subscribe(
|
self.unsubscribe_callback = await mqtt.async_subscribe(
|
||||||
hass, self.topic, self.message_callback, self.qos, self.encoding
|
hass, self.topic, self.message_callback, self.qos, self.encoding
|
||||||
@ -96,7 +98,9 @@ async def async_subscribe_topics(
|
|||||||
if remaining.unsubscribe_callback is not None:
|
if remaining.unsubscribe_callback is not None:
|
||||||
remaining.unsubscribe_callback()
|
remaining.unsubscribe_callback()
|
||||||
# Clear debug data if it exists
|
# Clear debug data if it exists
|
||||||
debug_info.remove_topic(hass, remaining.message_callback, remaining.topic)
|
debug_info.remove_subscription(
|
||||||
|
hass, remaining.message_callback, remaining.topic
|
||||||
|
)
|
||||||
|
|
||||||
return new_state
|
return new_state
|
||||||
|
|
||||||
|
@ -551,9 +551,9 @@ async def help_test_entity_debug_info(hass, mqtt_mock, domain, config):
|
|||||||
== f"homeassistant/{domain}/bla/config"
|
== f"homeassistant/{domain}/bla/config"
|
||||||
)
|
)
|
||||||
assert debug_info_data["entities"][0]["discovery_data"]["payload"] == config
|
assert debug_info_data["entities"][0]["discovery_data"]["payload"] == config
|
||||||
assert len(debug_info_data["entities"][0]["topics"]) == 1
|
assert len(debug_info_data["entities"][0]["subscriptions"]) == 1
|
||||||
assert {"topic": "test-topic", "messages": []} in debug_info_data["entities"][0][
|
assert {"topic": "test-topic", "messages": []} in debug_info_data["entities"][0][
|
||||||
"topics"
|
"subscriptions"
|
||||||
]
|
]
|
||||||
assert len(debug_info_data["triggers"]) == 0
|
assert len(debug_info_data["triggers"]) == 0
|
||||||
|
|
||||||
@ -581,24 +581,27 @@ async def help_test_entity_debug_info_max_messages(hass, mqtt_mock, domain, conf
|
|||||||
assert device is not None
|
assert device is not None
|
||||||
|
|
||||||
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
||||||
assert len(debug_info_data["entities"][0]["topics"]) == 1
|
assert len(debug_info_data["entities"][0]["subscriptions"]) == 1
|
||||||
assert {"topic": "test-topic", "messages": []} in debug_info_data["entities"][0][
|
assert {"topic": "test-topic", "messages": []} in debug_info_data["entities"][0][
|
||||||
"topics"
|
"subscriptions"
|
||||||
]
|
]
|
||||||
|
|
||||||
for i in range(0, debug_info.STORED_MESSAGES + 1):
|
for i in range(0, debug_info.STORED_MESSAGES + 1):
|
||||||
async_fire_mqtt_message(hass, "test-topic", f"{i}")
|
async_fire_mqtt_message(hass, "test-topic", f"{i}")
|
||||||
|
|
||||||
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
||||||
assert len(debug_info_data["entities"][0]["topics"]) == 1
|
assert len(debug_info_data["entities"][0]["subscriptions"]) == 1
|
||||||
assert (
|
assert (
|
||||||
len(debug_info_data["entities"][0]["topics"][0]["messages"])
|
len(debug_info_data["entities"][0]["subscriptions"][0]["messages"])
|
||||||
== debug_info.STORED_MESSAGES
|
== debug_info.STORED_MESSAGES
|
||||||
)
|
)
|
||||||
messages = [f"{i}" for i in range(1, debug_info.STORED_MESSAGES + 1)]
|
messages = [
|
||||||
|
{"topic": "test-topic", "payload": f"{i}"}
|
||||||
|
for i in range(1, debug_info.STORED_MESSAGES + 1)
|
||||||
|
]
|
||||||
assert {"topic": "test-topic", "messages": messages} in debug_info_data["entities"][
|
assert {"topic": "test-topic", "messages": messages} in debug_info_data["entities"][
|
||||||
0
|
0
|
||||||
]["topics"]
|
]["subscriptions"]
|
||||||
|
|
||||||
|
|
||||||
async def help_test_entity_debug_info_message(
|
async def help_test_entity_debug_info_message(
|
||||||
@ -634,16 +637,19 @@ async def help_test_entity_debug_info_message(
|
|||||||
assert device is not None
|
assert device is not None
|
||||||
|
|
||||||
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
||||||
assert len(debug_info_data["entities"][0]["topics"]) >= 1
|
assert len(debug_info_data["entities"][0]["subscriptions"]) >= 1
|
||||||
assert {"topic": topic, "messages": []} in debug_info_data["entities"][0]["topics"]
|
assert {"topic": topic, "messages": []} in debug_info_data["entities"][0][
|
||||||
|
"subscriptions"
|
||||||
|
]
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, topic, payload)
|
async_fire_mqtt_message(hass, topic, payload)
|
||||||
|
|
||||||
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
||||||
assert len(debug_info_data["entities"][0]["topics"]) >= 1
|
assert len(debug_info_data["entities"][0]["subscriptions"]) >= 1
|
||||||
assert {"topic": topic, "messages": [payload]} in debug_info_data["entities"][0][
|
assert {
|
||||||
"topics"
|
"topic": topic,
|
||||||
]
|
"messages": [{"topic": topic, "payload": payload}],
|
||||||
|
} in debug_info_data["entities"][0]["subscriptions"]
|
||||||
|
|
||||||
|
|
||||||
async def help_test_entity_debug_info_remove(hass, mqtt_mock, domain, config):
|
async def help_test_entity_debug_info_remove(hass, mqtt_mock, domain, config):
|
||||||
@ -675,9 +681,9 @@ async def help_test_entity_debug_info_remove(hass, mqtt_mock, domain, config):
|
|||||||
== f"homeassistant/{domain}/bla/config"
|
== f"homeassistant/{domain}/bla/config"
|
||||||
)
|
)
|
||||||
assert debug_info_data["entities"][0]["discovery_data"]["payload"] == config
|
assert debug_info_data["entities"][0]["discovery_data"]["payload"] == config
|
||||||
assert len(debug_info_data["entities"][0]["topics"]) == 1
|
assert len(debug_info_data["entities"][0]["subscriptions"]) == 1
|
||||||
assert {"topic": "test-topic", "messages": []} in debug_info_data["entities"][0][
|
assert {"topic": "test-topic", "messages": []} in debug_info_data["entities"][0][
|
||||||
"topics"
|
"subscriptions"
|
||||||
]
|
]
|
||||||
assert len(debug_info_data["triggers"]) == 0
|
assert len(debug_info_data["triggers"]) == 0
|
||||||
assert debug_info_data["entities"][0]["entity_id"] == f"{domain}.test"
|
assert debug_info_data["entities"][0]["entity_id"] == f"{domain}.test"
|
||||||
@ -723,9 +729,9 @@ async def help_test_entity_debug_info_update_entity_id(hass, mqtt_mock, domain,
|
|||||||
)
|
)
|
||||||
assert debug_info_data["entities"][0]["discovery_data"]["payload"] == config
|
assert debug_info_data["entities"][0]["discovery_data"]["payload"] == config
|
||||||
assert debug_info_data["entities"][0]["entity_id"] == f"{domain}.test"
|
assert debug_info_data["entities"][0]["entity_id"] == f"{domain}.test"
|
||||||
assert len(debug_info_data["entities"][0]["topics"]) == 1
|
assert len(debug_info_data["entities"][0]["subscriptions"]) == 1
|
||||||
assert {"topic": "test-topic", "messages": []} in debug_info_data["entities"][0][
|
assert {"topic": "test-topic", "messages": []} in debug_info_data["entities"][0][
|
||||||
"topics"
|
"subscriptions"
|
||||||
]
|
]
|
||||||
assert len(debug_info_data["triggers"]) == 0
|
assert len(debug_info_data["triggers"]) == 0
|
||||||
|
|
||||||
@ -741,9 +747,9 @@ async def help_test_entity_debug_info_update_entity_id(hass, mqtt_mock, domain,
|
|||||||
)
|
)
|
||||||
assert debug_info_data["entities"][0]["discovery_data"]["payload"] == config
|
assert debug_info_data["entities"][0]["discovery_data"]["payload"] == config
|
||||||
assert debug_info_data["entities"][0]["entity_id"] == f"{domain}.milk"
|
assert debug_info_data["entities"][0]["entity_id"] == f"{domain}.milk"
|
||||||
assert len(debug_info_data["entities"][0]["topics"]) == 1
|
assert len(debug_info_data["entities"][0]["subscriptions"]) == 1
|
||||||
assert {"topic": "test-topic", "messages": []} in debug_info_data["entities"][0][
|
assert {"topic": "test-topic", "messages": []} in debug_info_data["entities"][0][
|
||||||
"topics"
|
"subscriptions"
|
||||||
]
|
]
|
||||||
assert len(debug_info_data["triggers"]) == 0
|
assert len(debug_info_data["triggers"]) == 0
|
||||||
assert (
|
assert (
|
||||||
|
@ -1030,7 +1030,7 @@ async def test_mqtt_ws_get_device_debug_info(
|
|||||||
"entities": [
|
"entities": [
|
||||||
{
|
{
|
||||||
"entity_id": "sensor.mqtt_sensor",
|
"entity_id": "sensor.mqtt_sensor",
|
||||||
"topics": [{"topic": "foobar/sensor", "messages": []}],
|
"subscriptions": [{"topic": "foobar/sensor", "messages": []}],
|
||||||
"discovery_data": {
|
"discovery_data": {
|
||||||
"payload": config,
|
"payload": config,
|
||||||
"topic": "homeassistant/sensor/bla/config",
|
"topic": "homeassistant/sensor/bla/config",
|
||||||
@ -1110,10 +1110,10 @@ async def test_debug_info_multiple_devices(hass, mqtt_mock):
|
|||||||
assert len(debug_info_data["entities"]) == 1
|
assert len(debug_info_data["entities"]) == 1
|
||||||
assert len(debug_info_data["triggers"]) == 0
|
assert len(debug_info_data["triggers"]) == 0
|
||||||
discovery_data = debug_info_data["entities"][0]["discovery_data"]
|
discovery_data = debug_info_data["entities"][0]["discovery_data"]
|
||||||
assert len(debug_info_data["entities"][0]["topics"]) == 1
|
assert len(debug_info_data["entities"][0]["subscriptions"]) == 1
|
||||||
topic = d["config"]["state_topic"]
|
topic = d["config"]["state_topic"]
|
||||||
assert {"topic": topic, "messages": []} in debug_info_data["entities"][0][
|
assert {"topic": topic, "messages": []} in debug_info_data["entities"][0][
|
||||||
"topics"
|
"subscriptions"
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
assert len(debug_info_data["entities"]) == 0
|
assert len(debug_info_data["entities"]) == 0
|
||||||
@ -1199,7 +1199,7 @@ async def test_debug_info_multiple_entities_triggers(hass, mqtt_mock):
|
|||||||
discovery_data = [e["discovery_data"] for e in debug_info_data["entities"]]
|
discovery_data = [e["discovery_data"] for e in debug_info_data["entities"]]
|
||||||
topic = c["config"]["state_topic"]
|
topic = c["config"]["state_topic"]
|
||||||
assert {"topic": topic, "messages": []} in [
|
assert {"topic": topic, "messages": []} in [
|
||||||
t for e in debug_info_data["entities"] for t in e["topics"]
|
t for e in debug_info_data["entities"] for t in e["subscriptions"]
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
discovery_data = [e["discovery_data"] for e in debug_info_data["triggers"]]
|
discovery_data = [e["discovery_data"] for e in debug_info_data["triggers"]]
|
||||||
@ -1260,15 +1260,16 @@ async def test_debug_info_wildcard(hass, mqtt_mock):
|
|||||||
assert device is not None
|
assert device is not None
|
||||||
|
|
||||||
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
||||||
assert len(debug_info_data["entities"][0]["topics"]) >= 1
|
assert len(debug_info_data["entities"][0]["subscriptions"]) >= 1
|
||||||
assert {"topic": "sensor/#", "messages": []} in debug_info_data["entities"][0][
|
assert {"topic": "sensor/#", "messages": []} in debug_info_data["entities"][0][
|
||||||
"topics"
|
"subscriptions"
|
||||||
]
|
]
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, "sensor/abc", "123")
|
async_fire_mqtt_message(hass, "sensor/abc", "123")
|
||||||
|
|
||||||
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
debug_info_data = await debug_info.info_for_device(hass, device.id)
|
||||||
assert len(debug_info_data["entities"][0]["topics"]) >= 1
|
assert len(debug_info_data["entities"][0]["subscriptions"]) >= 1
|
||||||
assert {"topic": "sensor/#", "messages": ["123"]} in debug_info_data["entities"][0][
|
assert {
|
||||||
"topics"
|
"topic": "sensor/#",
|
||||||
]
|
"messages": [{"topic": "sensor/abc", "payload": "123"}],
|
||||||
|
} in debug_info_data["entities"][0]["subscriptions"]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user