diff --git a/.coveragerc b/.coveragerc index 4f161e7b5e1..6987e985467 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1171,6 +1171,7 @@ omit = homeassistant/components/velbus/switch.py homeassistant/components/velux/* homeassistant/components/venstar/__init__.py + homeassistant/components/venstar/binary_sensor.py homeassistant/components/venstar/climate.py homeassistant/components/verisure/__init__.py homeassistant/components/verisure/alarm_control_panel.py diff --git a/homeassistant/components/venstar/__init__.py b/homeassistant/components/venstar/__init__.py index 69bc1bf188c..8c46df66a91 100644 --- a/homeassistant/components/venstar/__init__.py +++ b/homeassistant/components/venstar/__init__.py @@ -19,7 +19,7 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import _LOGGER, DOMAIN, VENSTAR_TIMEOUT -PLATFORMS = ["climate"] +PLATFORMS = ["climate", "binary_sensor"] async def async_setup_entry(hass, config): @@ -96,6 +96,16 @@ class VenstarDataUpdateCoordinator(update_coordinator.DataUpdateCoordinator): raise update_coordinator.UpdateFailed( f"Exception during Venstar sensor update: {ex}" ) from ex + + # older venstars sometimes cannot handle rapid sequential connections + await asyncio.sleep(3) + + try: + await self.hass.async_add_executor_job(self.client.update_alerts) + except (OSError, RequestException) as ex: + raise update_coordinator.UpdateFailed( + f"Exception during Venstar alert update: {ex}" + ) from ex return None diff --git a/homeassistant/components/venstar/binary_sensor.py b/homeassistant/components/venstar/binary_sensor.py new file mode 100644 index 00000000000..d7b1a69c4cb --- /dev/null +++ b/homeassistant/components/venstar/binary_sensor.py @@ -0,0 +1,53 @@ +"""Alarm sensors for the Venstar Thermostat.""" +from homeassistant.components.binary_sensor import ( + DEVICE_CLASS_PROBLEM, + BinarySensorEntity, +) + +from . import VenstarEntity +from .const import DOMAIN + + +async def async_setup_entry(hass, config_entry, async_add_entities) -> None: + """Set up Vensar device binary_sensors based on a config entry.""" + coordinator = hass.data[DOMAIN][config_entry.entry_id] + + if coordinator.client.alerts is None: + return + sensors = [ + VenstarBinarySensor(coordinator, config_entry, alert["name"]) + for alert in coordinator.client.alerts + ] + + async_add_entities(sensors, True) + + +class VenstarBinarySensor(VenstarEntity, BinarySensorEntity): + """Represent a Venstar alert.""" + + _attr_device_class = DEVICE_CLASS_PROBLEM + + def __init__(self, coordinator, config, alert): + """Initialize the alert.""" + super().__init__(coordinator, config) + self.alert = alert + self._config = config + self._unique_id = f"{self._config.entry_id}_{self.alert.replace(' ', '_')}" + self._name = f"{self._client.name} {self.alert}" + + @property + def unique_id(self): + """Return the unique id.""" + return self._unique_id + + @property + def name(self): + """Return the name of the device.""" + return self._name + + @property + def is_on(self): + """Return true if the binary sensor is on.""" + for alert in self._client.alerts: + if alert["name"] == self.alert: + return alert["active"] diff --git a/tests/components/venstar/test_init.py b/tests/components/venstar/test_init.py index 03739f19616..08dae732466 100644 --- a/tests/components/venstar/test_init.py +++ b/tests/components/venstar/test_init.py @@ -33,6 +33,9 @@ async def test_setup_entry(hass: HomeAssistant): ), patch( "homeassistant.components.venstar.VenstarColorTouch.update_info", new=VenstarColorTouchMock.update_info, + ), patch( + "homeassistant.components.venstar.VenstarColorTouch.update_alerts", + new=VenstarColorTouchMock.update_alerts, ): await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() @@ -64,6 +67,9 @@ async def test_setup_entry_exception(hass: HomeAssistant): ), patch( "homeassistant.components.venstar.VenstarColorTouch.update_info", new=VenstarColorTouchMock.broken_update_info, + ), patch( + "homeassistant.components.venstar.VenstarColorTouch.update_alerts", + new=VenstarColorTouchMock.update_alerts, ): await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done()