diff --git a/homeassistant/helpers/event.py b/homeassistant/helpers/event.py index 46c36205cee..a5f433b0e23 100644 --- a/homeassistant/helpers/event.py +++ b/homeassistant/helpers/event.py @@ -1,6 +1,7 @@ """Helpers for listening to events.""" from datetime import datetime, timedelta import functools as ft +import logging from typing import Any, Awaitable, Callable, Dict, Iterable, Optional, Union import attr @@ -24,6 +25,8 @@ from homeassistant.util.async_ import run_callback_threadsafe TRACK_STATE_CHANGE_CALLBACKS = "track_state_change_callbacks" TRACK_STATE_CHANGE_LISTENER = "track_state_change_listener" +_LOGGER = logging.getLogger(__name__) + # PyLint does not like the use of threaded_listener_factory # pylint: disable=invalid-name @@ -146,7 +149,12 @@ def async_track_state_change_event( return for action in entity_callbacks[entity_id]: - hass.async_run_job(action, event) + try: + hass.async_run_job(action, event) + except Exception: # pylint: disable=broad-except + _LOGGER.exception( + "Error while processing state changed for %s", entity_id + ) hass.data[TRACK_STATE_CHANGE_LISTENER] = hass.bus.async_listen( EVENT_STATE_CHANGED, _async_state_change_dispatcher diff --git a/tests/helpers/test_event.py b/tests/helpers/test_event.py index 95a093d59ab..2d5ee9a9a73 100644 --- a/tests/helpers/test_event.py +++ b/tests/helpers/test_event.py @@ -183,12 +183,19 @@ async def test_async_track_state_change_event(hass): multiple_entity_id_tracker.append((old_state, new_state)) + @ha.callback + def callback_that_throws(event): + raise ValueError + unsub_single = async_track_state_change_event( hass, ["light.Bowl"], single_run_callback ) unsub_multi = async_track_state_change_event( hass, ["light.Bowl", "switch.kitchen"], multiple_run_callback ) + unsub_throws = async_track_state_change_event( + hass, ["light.Bowl", "switch.kitchen"], callback_that_throws + ) # Adding state to state machine hass.states.async_set("light.Bowl", "on") @@ -247,6 +254,7 @@ async def test_async_track_state_change_event(hass): assert len(multiple_entity_id_tracker) == 7 unsub_multi() + unsub_throws() async def test_track_template(hass): @@ -429,6 +437,7 @@ async def test_track_same_state_simple_trigger_check_funct(hass): # Adding state to state machine hass.states.async_set("light.Bowl", "on") await hass.async_block_till_done() + await hass.async_block_till_done() assert len(callback_runs) == 0 assert check_func[-1][2].state == "on" assert check_func[-1][0] == "light.bowl"