core/homeassistant/components/broadlink/heartbeat.py

62 lines
2.0 KiB
Python

"""Heartbeats for Broadlink devices."""
import datetime as dt
import logging
import broadlink as blk
from homeassistant.const import CONF_HOST
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
from homeassistant.helpers import event
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
class BroadlinkHeartbeat:
"""Manages heartbeats in the Broadlink integration.
Some devices reboot when they cannot reach the cloud. This mechanism
feeds their watchdog timers so they can be used offline.
"""
HEARTBEAT_INTERVAL = dt.timedelta(minutes=2)
def __init__(self, hass: HomeAssistant) -> None:
"""Initialize the heartbeat."""
self._hass = hass
self._unsubscribe: CALLBACK_TYPE | None = None
async def async_setup(self) -> None:
"""Set up the heartbeat."""
if self._unsubscribe is None:
await self.async_heartbeat(dt.datetime.now())
self._unsubscribe = event.async_track_time_interval(
self._hass, self.async_heartbeat, self.HEARTBEAT_INTERVAL
)
async def async_unload(self) -> None:
"""Unload the heartbeat."""
if self._unsubscribe is not None:
self._unsubscribe()
self._unsubscribe = None
async def async_heartbeat(self, _: dt.datetime) -> None:
"""Send packets to feed watchdog timers."""
hass = self._hass
config_entries = hass.config_entries.async_entries(DOMAIN)
hosts: set[str] = {entry.data[CONF_HOST] for entry in config_entries}
await hass.async_add_executor_job(self.heartbeat, hosts)
@staticmethod
def heartbeat(hosts: set[str]) -> None:
"""Send packets to feed watchdog timers."""
for host in hosts:
try:
blk.ping(host)
except OSError as err:
_LOGGER.debug("Failed to send heartbeat to %s: %s", host, err)
else:
_LOGGER.debug("Heartbeat sent to %s", host)