From 02ef7d445d8a723fe57712f37ca9c27595c5d1a2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 25 Mar 2023 04:11:14 -1000 Subject: [PATCH] Allow passing an optional name to async_track_time_interval (#90244) * Allow passing an optional name to async_track_time_interval This is the same idea as passing a name to asyncio.create_task which makes it easier to track down bugs * more * short * still cannot find it * add a few more * test --- .../components/analytics/__init__.py | 4 +++- homeassistant/components/august/subscriber.py | 2 +- .../components/bluetooth/base_scanner.py | 10 +++++++-- homeassistant/components/bluetooth/manager.py | 1 + homeassistant/components/bond/entity.py | 5 ++++- homeassistant/components/camera/__init__.py | 4 +++- .../components/device_tracker/legacy.py | 7 +++++- homeassistant/components/dhcp/__init__.py | 2 +- .../homekit_controller/connection.py | 6 ++++- homeassistant/components/recorder/core.py | 15 ++++++++++--- homeassistant/components/ssdp/__init__.py | 2 +- homeassistant/helpers/entity_platform.py | 1 + homeassistant/helpers/event.py | 10 ++++++--- homeassistant/helpers/restore_state.py | 5 ++++- tests/helpers/test_event.py | 22 +++++++++++++++++++ 15 files changed, 79 insertions(+), 17 deletions(-) diff --git a/homeassistant/components/analytics/__init__.py b/homeassistant/components/analytics/__init__.py index ad53fb03113..7bf55480eb1 100644 --- a/homeassistant/components/analytics/__init__.py +++ b/homeassistant/components/analytics/__init__.py @@ -27,7 +27,9 @@ async def async_setup(hass: HomeAssistant, _: ConfigType) -> bool: async_call_later(hass, 900, analytics.send_analytics) # Send every day - async_track_time_interval(hass, analytics.send_analytics, INTERVAL) + async_track_time_interval( + hass, analytics.send_analytics, INTERVAL, "analytics daily" + ) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, start_schedule) diff --git a/homeassistant/components/august/subscriber.py b/homeassistant/components/august/subscriber.py index 5223b8b4a38..e0982fe9fb2 100644 --- a/homeassistant/components/august/subscriber.py +++ b/homeassistant/components/august/subscriber.py @@ -38,7 +38,7 @@ class AugustSubscriberMixin: def _async_setup_listeners(self): """Create interval and stop listeners.""" self._unsub_interval = async_track_time_interval( - self._hass, self._async_refresh, self._update_interval + self._hass, self._async_refresh, self._update_interval, "august refresh" ) @callback diff --git a/homeassistant/components/bluetooth/base_scanner.py b/homeassistant/components/bluetooth/base_scanner.py index 1c16639d613..f1ffd6ecf58 100644 --- a/homeassistant/components/bluetooth/base_scanner.py +++ b/homeassistant/components/bluetooth/base_scanner.py @@ -98,7 +98,10 @@ class BaseHaScanner(ABC): self._start_time = self._last_detection = MONOTONIC_TIME() if not self._cancel_watchdog: self._cancel_watchdog = async_track_time_interval( - self.hass, self._async_scanner_watchdog, SCANNER_WATCHDOG_INTERVAL + self.hass, + self._async_scanner_watchdog, + SCANNER_WATCHDOG_INTERVAL, + f"{self.name} Bluetooth scanner watchdog", ) @hass_callback @@ -224,7 +227,10 @@ class BaseHaRemoteScanner(BaseHaScanner): self._async_expire_devices(dt_util.utcnow()) cancel_track = async_track_time_interval( - self.hass, self._async_expire_devices, timedelta(seconds=30) + self.hass, + self._async_expire_devices, + timedelta(seconds=30), + f"{self.name} Bluetooth scanner device expire", ) cancel_stop = self.hass.bus.async_listen( EVENT_HOMEASSISTANT_STOP, self._async_save_history diff --git a/homeassistant/components/bluetooth/manager.py b/homeassistant/components/bluetooth/manager.py index bc210516562..7932520b454 100644 --- a/homeassistant/components/bluetooth/manager.py +++ b/homeassistant/components/bluetooth/manager.py @@ -276,6 +276,7 @@ class BluetoothManager: self.hass, self._async_check_unavailable, timedelta(seconds=UNAVAILABLE_TRACK_SECONDS), + "Bluetooth manager unavailable tracking", ) @hass_callback diff --git a/homeassistant/components/bond/entity.py b/homeassistant/components/bond/entity.py index 8c9fef6bd7f..d00646d6ff4 100644 --- a/homeassistant/components/bond/entity.py +++ b/homeassistant/components/bond/entity.py @@ -174,7 +174,10 @@ class BondEntity(Entity): self._bpup_subs.subscribe(self._device_id, self._async_bpup_callback) self.async_on_remove( async_track_time_interval( - self.hass, self._async_update_if_bpup_not_alive, _FALLBACK_SCAN_INTERVAL + self.hass, + self._async_update_if_bpup_not_alive, + _FALLBACK_SCAN_INTERVAL, + f"Bond {self.entity_id} fallback polling", ) ) diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py index e368779e944..673009268c1 100644 --- a/homeassistant/components/camera/__init__.py +++ b/homeassistant/components/camera/__init__.py @@ -379,7 +379,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: entity.async_update_token() entity.async_write_ha_state() - unsub = async_track_time_interval(hass, update_tokens, TOKEN_CHANGE_INTERVAL) + unsub = async_track_time_interval( + hass, update_tokens, TOKEN_CHANGE_INTERVAL, "Camera update tokens" + ) @callback def unsub_track_time_interval(_event: Event) -> None: diff --git a/homeassistant/components/device_tracker/legacy.py b/homeassistant/components/device_tracker/legacy.py index bc792ee8920..af70939ee6b 100644 --- a/homeassistant/components/device_tracker/legacy.py +++ b/homeassistant/components/device_tracker/legacy.py @@ -423,7 +423,12 @@ def async_setup_scanner_platform( hass.async_create_task(async_see_device(**kwargs)) - async_track_time_interval(hass, async_device_tracker_scan, interval) + async_track_time_interval( + hass, + async_device_tracker_scan, + interval, + f"device_tracker {platform} legacy scan", + ) hass.async_create_task(async_device_tracker_scan(None)) diff --git a/homeassistant/components/dhcp/__init__.py b/homeassistant/components/dhcp/__init__.py index 74dd1f66abf..ea5a5fb79ad 100644 --- a/homeassistant/components/dhcp/__init__.py +++ b/homeassistant/components/dhcp/__init__.py @@ -260,7 +260,7 @@ class NetworkWatcher(WatcherBase): """Start scanning for new devices on the network.""" self._discover_hosts = DiscoverHosts() self._unsub = async_track_time_interval( - self.hass, self.async_start_discover, SCAN_INTERVAL + self.hass, self.async_start_discover, SCAN_INTERVAL, "DHCP network watcher" ) self.async_start_discover() diff --git a/homeassistant/components/homekit_controller/connection.py b/homeassistant/components/homekit_controller/connection.py index 4814e7833cf..9e56c7c24ee 100644 --- a/homeassistant/components/homekit_controller/connection.py +++ b/homeassistant/components/homekit_controller/connection.py @@ -272,6 +272,7 @@ class HKDevice: self.hass, self.async_update_available_state, timedelta(seconds=BLE_AVAILABILITY_CHECK_INTERVAL), + f"HomeKit Controller {self.unique_id} BLE availability check poll", ) ) # BLE devices always get an RSSI sensor as well @@ -286,7 +287,10 @@ class HKDevice: # in the log about concurrent polling. self.config_entry.async_on_unload( async_track_time_interval( - self.hass, self.async_request_update, self.pairing.poll_interval + self.hass, + self.async_request_update, + self.pairing.poll_interval, + f"HomeKit Controller {self.unique_id} availability check poll", ) ) diff --git a/homeassistant/components/recorder/core.py b/homeassistant/components/recorder/core.py index 3b92698c83d..fbc929b17d1 100644 --- a/homeassistant/components/recorder/core.py +++ b/homeassistant/components/recorder/core.py @@ -296,7 +296,10 @@ class Recorder(threading.Thread): run_immediately=True, ) self._queue_watcher = async_track_time_interval( - self.hass, self._async_check_queue, timedelta(minutes=10) + self.hass, + self._async_check_queue, + timedelta(minutes=10), + "Recorder queue watcher", ) @callback @@ -596,13 +599,19 @@ class Recorder(threading.Thread): # to prevent errors from unexpected disconnects if self.dialect_name != SupportedDialect.SQLITE: self._keep_alive_listener = async_track_time_interval( - self.hass, self._async_keep_alive, timedelta(seconds=KEEPALIVE_TIME) + self.hass, + self._async_keep_alive, + timedelta(seconds=KEEPALIVE_TIME), + "Recorder keep alive", ) # If the commit interval is not 0, we need to commit periodically if self.commit_interval: self._commit_listener = async_track_time_interval( - self.hass, self._async_commit, timedelta(seconds=self.commit_interval) + self.hass, + self._async_commit, + timedelta(seconds=self.commit_interval), + "Recorder commit", ) # Run nightly tasks at 4:12am diff --git a/homeassistant/components/ssdp/__init__.py b/homeassistant/components/ssdp/__init__.py index b7e28f27045..b7ed28885cb 100644 --- a/homeassistant/components/ssdp/__init__.py +++ b/homeassistant/components/ssdp/__init__.py @@ -401,7 +401,7 @@ class Scanner: self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.async_stop) self._cancel_scan = async_track_time_interval( - self.hass, self.async_scan, SCAN_INTERVAL + self.hass, self.async_scan, SCAN_INTERVAL, "SSDP scanner" ) # Trigger the initial-scan. diff --git a/homeassistant/helpers/entity_platform.py b/homeassistant/helpers/entity_platform.py index 6687af6a27d..7b7b809404f 100644 --- a/homeassistant/helpers/entity_platform.py +++ b/homeassistant/helpers/entity_platform.py @@ -479,6 +479,7 @@ class EntityPlatform: self.hass, self._update_entity_states, self.scan_interval, + f"EntityPlatform poll {self.domain}.{self.platform_name}", ) def _entity_id_already_exists(self, entity_id: str) -> tuple[bool, bool]: diff --git a/homeassistant/helpers/event.py b/homeassistant/helpers/event.py index 3ac715426e3..a456e12fa13 100644 --- a/homeassistant/helpers/event.py +++ b/homeassistant/helpers/event.py @@ -1397,6 +1397,7 @@ def async_track_time_interval( hass: HomeAssistant, action: Callable[[datetime], Coroutine[Any, Any, None] | None], interval: timedelta, + name: str | None = None, ) -> CALLBACK_TYPE: """Add a listener that fires repetitively at every timedelta interval.""" remove: CALLBACK_TYPE @@ -1419,9 +1420,12 @@ def async_track_time_interval( ) hass.async_run_hass_job(job, now) - interval_listener_job = HassJob( - interval_listener, f"track time interval listener {interval}" - ) + if name: + job_name = f"{name}: track time interval {interval}" + else: + job_name = f"track time interval {interval}" + + interval_listener_job = HassJob(interval_listener, job_name) remove = async_track_point_in_utc_time(hass, interval_listener_job, next_interval()) def remove_listener() -> None: diff --git a/homeassistant/helpers/restore_state.py b/homeassistant/helpers/restore_state.py index 0263bd28682..e35a66ada8d 100644 --- a/homeassistant/helpers/restore_state.py +++ b/homeassistant/helpers/restore_state.py @@ -216,7 +216,10 @@ class RestoreStateData: # Dump states periodically cancel_interval = async_track_time_interval( - self.hass, _async_dump_states, STATE_DUMP_INTERVAL + self.hass, + _async_dump_states, + STATE_DUMP_INTERVAL, + "RestoreStateData dump states", ) async def _async_dump_states_at_stop(*_: Any) -> None: diff --git a/tests/helpers/test_event.py b/tests/helpers/test_event.py index 211663babc8..7e84d634eff 100644 --- a/tests/helpers/test_event.py +++ b/tests/helpers/test_event.py @@ -3438,6 +3438,28 @@ async def test_track_time_interval(hass: HomeAssistant) -> None: assert len(specific_runs) == 2 +async def test_track_time_interval_name(hass: HomeAssistant) -> None: + """Test tracking time interval name. + + This test is to ensure that when a name is passed to async_track_time_interval, + that the name can be found in the TimerHandle when stringified. + """ + specific_runs = [] + unique_string = "xZ13" + unsub = async_track_time_interval( + hass, + callback(lambda x: specific_runs.append(x)), + timedelta(seconds=10), + unique_string, + ) + scheduled = getattr(hass.loop, "_scheduled") + assert any(handle for handle in scheduled if unique_string in str(handle)) + unsub() + + assert all(handle for handle in scheduled if unique_string not in str(handle)) + await hass.async_block_till_done() + + async def test_track_sunrise(hass: HomeAssistant) -> None: """Test track the sunrise.""" latitude = 32.87336