diff --git a/homeassistant/components/deconz/logbook.py b/homeassistant/components/deconz/logbook.py index 65ed7f8e31d..42620cf3df6 100644 --- a/homeassistant/components/deconz/logbook.py +++ b/homeassistant/components/deconz/logbook.py @@ -4,7 +4,7 @@ from __future__ import annotations from collections.abc import Callable from homeassistant.components.logbook import LOGBOOK_ENTRY_MESSAGE, LOGBOOK_ENTRY_NAME -from homeassistant.const import ATTR_DEVICE_ID, CONF_EVENT +from homeassistant.const import ATTR_DEVICE_ID, CONF_EVENT, CONF_ID from homeassistant.core import Event, HomeAssistant, callback import homeassistant.helpers.device_registry as dr @@ -130,27 +130,34 @@ def async_describe_events( @callback def async_describe_deconz_alarm_event(event: Event) -> dict[str, str]: """Describe deCONZ logbook alarm event.""" - device = device_registry.devices[event.data[ATTR_DEVICE_ID]] - deconz_alarm_event = _get_deconz_event_from_device(hass, device) + if device := device_registry.devices.get(event.data[ATTR_DEVICE_ID]): + deconz_alarm_event = _get_deconz_event_from_device(hass, device) + name = deconz_alarm_event.device.name + else: + name = event.data[CONF_ID] data = event.data[CONF_EVENT] return { - LOGBOOK_ENTRY_NAME: f"{deconz_alarm_event.device.name}", + LOGBOOK_ENTRY_NAME: name, LOGBOOK_ENTRY_MESSAGE: f"fired event '{data}'", } @callback def async_describe_deconz_event(event: Event) -> dict[str, str]: """Describe deCONZ logbook event.""" - device = device_registry.devices[event.data[ATTR_DEVICE_ID]] - deconz_event = _get_deconz_event_from_device(hass, device) + if device := device_registry.devices.get(event.data[ATTR_DEVICE_ID]): + deconz_event = _get_deconz_event_from_device(hass, device) + name = deconz_event.device.name + else: + deconz_event = None + name = event.data[CONF_ID] action = None interface = None data = event.data.get(CONF_EVENT) or event.data.get(CONF_GESTURE, "") - if data and deconz_event.device.model_id in REMOTES: + if data and deconz_event and deconz_event.device.model_id in REMOTES: action, interface = _get_device_event_description( deconz_event.device.model_id, data ) @@ -158,26 +165,26 @@ def async_describe_events( # Unknown event if not data: return { - LOGBOOK_ENTRY_NAME: f"{deconz_event.device.name}", + LOGBOOK_ENTRY_NAME: name, LOGBOOK_ENTRY_MESSAGE: "fired an unknown event", } # No device event match if not action: return { - LOGBOOK_ENTRY_NAME: f"{deconz_event.device.name}", + LOGBOOK_ENTRY_NAME: name, LOGBOOK_ENTRY_MESSAGE: f"fired event '{data}'", } # Gesture event if not interface: return { - LOGBOOK_ENTRY_NAME: f"{deconz_event.device.name}", + LOGBOOK_ENTRY_NAME: name, LOGBOOK_ENTRY_MESSAGE: f"fired event '{ACTIONS[action]}'", } return { - LOGBOOK_ENTRY_NAME: f"{deconz_event.device.name}", + LOGBOOK_ENTRY_NAME: name, LOGBOOK_ENTRY_MESSAGE: f"'{ACTIONS[action]}' event for '{INTERFACES[interface]}' was fired", } diff --git a/tests/components/deconz/test_logbook.py b/tests/components/deconz/test_logbook.py index 1680854302b..6a2c244207c 100644 --- a/tests/components/deconz/test_logbook.py +++ b/tests/components/deconz/test_logbook.py @@ -66,6 +66,9 @@ async def test_humanifying_deconz_alarm_event(hass, aioclient_mock): identifiers={(DECONZ_DOMAIN, keypad_serial)} ) + removed_device_event_id = "removed_device" + removed_device_serial = "00:00:00:00:00:00:00:05" + hass.config.components.add("recorder") assert await async_setup_component(hass, "logbook", {}) @@ -82,6 +85,17 @@ async def test_humanifying_deconz_alarm_event(hass, aioclient_mock): CONF_UNIQUE_ID: keypad_serial, }, ), + # Event of a removed device + MockRow( + CONF_DECONZ_ALARM_EVENT, + { + CONF_CODE: 1234, + CONF_DEVICE_ID: "ff99ff99ff99ff99ff99ff99ff99ff99", + CONF_EVENT: STATE_ALARM_ARMED_AWAY, + CONF_ID: removed_device_event_id, + CONF_UNIQUE_ID: removed_device_serial, + }, + ), ], ) @@ -89,6 +103,10 @@ async def test_humanifying_deconz_alarm_event(hass, aioclient_mock): assert events[0]["domain"] == "deconz" assert events[0]["message"] == "fired event 'armed_away'" + assert events[1]["name"] == "removed_device" + assert events[1]["domain"] == "deconz" + assert events[1]["message"] == "fired event 'armed_away'" + async def test_humanifying_deconz_event(hass, aioclient_mock): """Test humanifying deCONZ event.""" @@ -155,6 +173,9 @@ async def test_humanifying_deconz_event(hass, aioclient_mock): identifiers={(DECONZ_DOMAIN, faulty_serial)} ) + removed_device_event_id = "removed_device" + removed_device_serial = "00:00:00:00:00:00:00:05" + hass.config.components.add("recorder") assert await async_setup_component(hass, "logbook", {}) @@ -211,6 +232,16 @@ async def test_humanifying_deconz_event(hass, aioclient_mock): CONF_UNIQUE_ID: faulty_serial, }, ), + # Event of a removed device + MockRow( + CONF_DECONZ_EVENT, + { + CONF_DEVICE_ID: "ff99ff99ff99ff99ff99ff99ff99ff99", + CONF_EVENT: 2000, + CONF_ID: removed_device_event_id, + CONF_UNIQUE_ID: removed_device_serial, + }, + ), ], ) @@ -233,3 +264,7 @@ async def test_humanifying_deconz_event(hass, aioclient_mock): assert events[4]["name"] == "Faulty event" assert events[4]["domain"] == "deconz" assert events[4]["message"] == "fired an unknown event" + + assert events[5]["name"] == "removed_device" + assert events[5]["domain"] == "deconz" + assert events[5]["message"] == "fired event '2000'"