binary_sensor.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. from __future__ import annotations
  2. from datetime import timedelta
  3. from homeassistant.components.binary_sensor import BinarySensorEntity
  4. from homeassistant.config_entries import ConfigEntry
  5. from homeassistant.core import HomeAssistant
  6. from homeassistant.helpers.device_registry import DeviceInfo
  7. from homeassistant.helpers.entity_platform import AddEntitiesCallback
  8. from homeassistant.helpers.update_coordinator import CoordinatorEntity
  9. from homeassistant.util import dt as dt_util
  10. from .const import (
  11. CONF_REFRESH_INTERVAL,
  12. CONF_ROOM_NAME,
  13. CONF_SYNC_MODE,
  14. DEFAULT_REFRESH_INTERVAL,
  15. DOMAIN,
  16. SYNC_MODE_MANUAL,
  17. )
  18. from .coordinator import CoordinatorData, RoomCalCoordinator
  19. async def async_setup_entry(
  20. hass: HomeAssistant,
  21. entry: ConfigEntry,
  22. async_add_entities: AddEntitiesCallback,
  23. ) -> None:
  24. coordinator: RoomCalCoordinator = hass.data[DOMAIN][entry.entry_id]["coordinator"]
  25. device_name = f"{entry.data.get(CONF_ROOM_NAME, entry.title)} Room State"
  26. device_info = DeviceInfo(
  27. identifiers={(DOMAIN, f"{entry.entry_id}_room_state")},
  28. name=device_name,
  29. )
  30. async_add_entities([StaleSensor(coordinator, entry, device_info)])
  31. class StaleSensor(CoordinatorEntity[RoomCalCoordinator], BinarySensorEntity):
  32. _attr_has_entity_name = True
  33. _attr_name = "Stale"
  34. _attr_icon = "mdi:clock-alert-outline"
  35. def __init__(
  36. self,
  37. coordinator: RoomCalCoordinator,
  38. entry: ConfigEntry,
  39. device_info: DeviceInfo,
  40. ) -> None:
  41. super().__init__(coordinator)
  42. self._entry = entry
  43. self._attr_unique_id = f"{entry.entry_id}_stale"
  44. self._attr_device_info = device_info
  45. @property
  46. def is_on(self) -> bool | None:
  47. if self._entry.options.get(CONF_SYNC_MODE, SYNC_MODE_MANUAL) == SYNC_MODE_MANUAL:
  48. return None
  49. interval = self._entry.options.get(CONF_REFRESH_INTERVAL, DEFAULT_REFRESH_INTERVAL)
  50. threshold = timedelta(minutes=interval * 2)
  51. now = dt_util.utcnow()
  52. data: CoordinatorData = self.coordinator.data
  53. for ts in (data.current_last_refresh, data.next_last_refresh):
  54. if ts is None or (now - ts) > threshold:
  55. return True
  56. return False