diff --git a/homeassistant/helpers/event.py b/homeassistant/helpers/event.py index ef077a1c70e..464d8df6e0b 100644 --- a/homeassistant/helpers/event.py +++ b/homeassistant/helpers/event.py @@ -236,6 +236,9 @@ def async_track_state_change_event( care about the state change events so we can do a fast dict lookup to route events. """ + entity_ids = _async_string_to_lower_list(entity_ids) + if not entity_ids: + return _remove_empty_listener entity_callbacks = hass.data.setdefault(TRACK_STATE_CHANGE_CALLBACKS, {}) @@ -263,8 +266,6 @@ def async_track_state_change_event( job = HassJob(action) - entity_ids = _async_string_to_lower_list(entity_ids) - for entity_id in entity_ids: entity_callbacks.setdefault(entity_id, []).append(job) @@ -282,6 +283,11 @@ def async_track_state_change_event( return remove_listener +@callback +def _remove_empty_listener() -> None: + """Remove a listener that does nothing.""" + + @callback def _async_remove_indexed_listeners( hass: HomeAssistant, @@ -314,6 +320,9 @@ def async_track_entity_registry_updated_event( Similar to async_track_state_change_event. """ + entity_ids = _async_string_to_lower_list(entity_ids) + if not entity_ids: + return _remove_empty_listener entity_callbacks = hass.data.setdefault(TRACK_ENTITY_REGISTRY_UPDATED_CALLBACKS, {}) @@ -342,8 +351,6 @@ def async_track_entity_registry_updated_event( job = HassJob(action) - entity_ids = _async_string_to_lower_list(entity_ids) - for entity_id in entity_ids: entity_callbacks.setdefault(entity_id, []).append(job) @@ -388,6 +395,9 @@ def async_track_state_added_domain( action: Callable[[Event], Any], ) -> Callable[[], None]: """Track state change events when an entity is added to domains.""" + domains = _async_string_to_lower_list(domains) + if not domains: + return _remove_empty_listener domain_callbacks = hass.data.setdefault(TRACK_STATE_ADDED_DOMAIN_CALLBACKS, {}) @@ -407,8 +417,6 @@ def async_track_state_added_domain( job = HassJob(action) - domains = _async_string_to_lower_list(domains) - for domain in domains: domain_callbacks.setdefault(domain, []).append(job) @@ -433,6 +441,9 @@ def async_track_state_removed_domain( action: Callable[[Event], Any], ) -> Callable[[], None]: """Track state change events when an entity is removed from domains.""" + domains = _async_string_to_lower_list(domains) + if not domains: + return _remove_empty_listener domain_callbacks = hass.data.setdefault(TRACK_STATE_REMOVED_DOMAIN_CALLBACKS, {}) @@ -452,8 +463,6 @@ def async_track_state_removed_domain( job = HassJob(action) - domains = _async_string_to_lower_list(domains) - for domain in domains: domain_callbacks.setdefault(domain, []).append(job) diff --git a/tests/helpers/test_event.py b/tests/helpers/test_event.py index 5c3a6c1a71d..f63abfa2ed2 100644 --- a/tests/helpers/test_event.py +++ b/tests/helpers/test_event.py @@ -486,6 +486,19 @@ async def test_async_track_state_change_event(hass): unsub_throws() +async def test_async_track_state_change_event_with_empty_list(hass): + """Test async_track_state_change_event passing an empty list of entities.""" + unsub_single = async_track_state_change_event( + hass, [], ha.callback(lambda event: None) + ) + unsub_single2 = async_track_state_change_event( + hass, [], ha.callback(lambda event: None) + ) + + unsub_single2() + unsub_single() + + async def test_async_track_state_added_domain(hass): """Test async_track_state_added_domain.""" single_entity_id_tracker = [] @@ -568,6 +581,32 @@ async def test_async_track_state_added_domain(hass): unsub_throws() +async def test_async_track_state_added_domain_with_empty_list(hass): + """Test async_track_state_added_domain passing an empty list of domains.""" + unsub_single = async_track_state_added_domain( + hass, [], ha.callback(lambda event: None) + ) + unsub_single2 = async_track_state_added_domain( + hass, [], ha.callback(lambda event: None) + ) + + unsub_single2() + unsub_single() + + +async def test_async_track_state_removed_domain_with_empty_list(hass): + """Test async_track_state_removed_domain passing an empty list of domains.""" + unsub_single = async_track_state_removed_domain( + hass, [], ha.callback(lambda event: None) + ) + unsub_single2 = async_track_state_removed_domain( + hass, [], ha.callback(lambda event: None) + ) + + unsub_single2() + unsub_single() + + async def test_async_track_state_removed_domain(hass): """Test async_track_state_removed_domain.""" single_entity_id_tracker = [] @@ -2876,3 +2915,16 @@ async def test_async_track_entity_registry_updated_event_with_a_callback_that_th unsub2() assert event_data[0] == {"action": "create", "entity_id": "switch.puppy_feeder"} + + +async def test_async_track_entity_registry_updated_event_with_empty_list(hass): + """Test async_track_entity_registry_updated_event passing an empty list of entities.""" + unsub_single = hass.helpers.event.async_track_entity_registry_updated_event( + [], ha.callback(lambda event: None) + ) + unsub_single2 = hass.helpers.event.async_track_entity_registry_updated_event( + [], ha.callback(lambda event: None) + ) + + unsub_single2() + unsub_single()