From 7de4801bfa58a1fa52c1f467cf964b56c271a5dd Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 2 Jan 2022 10:36:14 -1000 Subject: [PATCH] Add support for oncue connectivity binary sensor (#63232) --- homeassistant/components/oncue/__init__.py | 2 +- .../components/oncue/binary_sensor.py | 58 +++++++++++++++++++ homeassistant/components/oncue/entity.py | 46 +++++++++++++++ homeassistant/components/oncue/sensor.py | 30 +++------- tests/components/oncue/test_binary_sensor.py | 35 +++++++++++ tests/components/oncue/test_sensor.py | 4 +- 6 files changed, 149 insertions(+), 26 deletions(-) create mode 100644 homeassistant/components/oncue/binary_sensor.py create mode 100644 homeassistant/components/oncue/entity.py create mode 100644 tests/components/oncue/test_binary_sensor.py diff --git a/homeassistant/components/oncue/__init__.py b/homeassistant/components/oncue/__init__.py index 150d8c7f01d..24a2ec24c7d 100644 --- a/homeassistant/components/oncue/__init__.py +++ b/homeassistant/components/oncue/__init__.py @@ -15,7 +15,7 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from .const import CONNECTION_EXCEPTIONS, DOMAIN -PLATFORMS: list[str] = [Platform.SENSOR] +PLATFORMS: list[str] = [Platform.BINARY_SENSOR, Platform.SENSOR] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/oncue/binary_sensor.py b/homeassistant/components/oncue/binary_sensor.py new file mode 100644 index 00000000000..8ea637377b0 --- /dev/null +++ b/homeassistant/components/oncue/binary_sensor.py @@ -0,0 +1,58 @@ +"""Support for Oncue binary sensors.""" +from __future__ import annotations + +from aiooncue import OncueDevice + +from homeassistant.components.binary_sensor import ( + BinarySensorDeviceClass, + BinarySensorEntity, + BinarySensorEntityDescription, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity import EntityCategory +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator + +from .const import DOMAIN +from .entity import OncueEntity + +SENSOR_TYPES: tuple[BinarySensorEntityDescription, ...] = ( + BinarySensorEntityDescription( + key="NetworkConnectionEstablished", + entity_category=EntityCategory.DIAGNOSTIC, + device_class=BinarySensorDeviceClass.CONNECTIVITY, + ), +) + +SENSOR_MAP = {description.key: description for description in SENSOR_TYPES} + + +async def async_setup_entry( + hass: HomeAssistant, + config_entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up sensors.""" + coordinator: DataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] + entities: list[OncueBinarySensorEntity] = [] + devices: dict[str, OncueDevice] = coordinator.data + for device_id, device in devices.items(): + entities.extend( + OncueBinarySensorEntity( + coordinator, device_id, device, sensor, SENSOR_MAP[key] + ) + for key, sensor in device.sensors.items() + if key in SENSOR_MAP + ) + + async_add_entities(entities) + + +class OncueBinarySensorEntity(OncueEntity, BinarySensorEntity): + """Representation of an Oncue binary sensor.""" + + @property + def is_on(self) -> bool: + """Return the binary sensor state.""" + return self._oncue_value == "true" diff --git a/homeassistant/components/oncue/entity.py b/homeassistant/components/oncue/entity.py new file mode 100644 index 00000000000..ea0d4e14f1f --- /dev/null +++ b/homeassistant/components/oncue/entity.py @@ -0,0 +1,46 @@ +"""Support for Oncue sensors.""" +from __future__ import annotations + +from aiooncue import OncueDevice, OncueSensor + +from homeassistant.helpers.entity import DeviceInfo, Entity, EntityDescription +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, + DataUpdateCoordinator, +) + +from .const import DOMAIN + + +class OncueEntity(CoordinatorEntity, Entity): + """Representation of an Oncue entity.""" + + def __init__( + self, + coordinator: DataUpdateCoordinator, + device_id: str, + device: OncueDevice, + sensor: OncueSensor, + description: EntityDescription, + ) -> None: + """Initialize the sensor.""" + super().__init__(coordinator) + self.entity_description = description + self._device_id = device_id + self._attr_unique_id = f"{device_id}_{description.key}" + self._attr_name = f"{device.name} {sensor.display_name}" + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, device_id)}, + name=device.name, + hw_version=device.hardware_version, + sw_version=device.sensors["FirmwareVersion"].display_value, + model=device.sensors["GensetModelNumberSelect"].display_value, + manufacturer="Kohler", + ) + + @property + def _oncue_value(self) -> str: + """Return the sensor value.""" + device: OncueDevice = self.coordinator.data[self._device_id] + sensor: OncueSensor = device.sensors[self.entity_description.key] + return sensor.value diff --git a/homeassistant/components/oncue/sensor.py b/homeassistant/components/oncue/sensor.py index 28991e93c27..53f6c4647e6 100644 --- a/homeassistant/components/oncue/sensor.py +++ b/homeassistant/components/oncue/sensor.py @@ -20,14 +20,12 @@ from homeassistant.const import ( TEMP_FAHRENHEIT, ) from homeassistant.core import HomeAssistant -from homeassistant.helpers.entity import DeviceInfo, EntityCategory +from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.update_coordinator import ( - CoordinatorEntity, - DataUpdateCoordinator, -) +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from .const import DOMAIN +from .entity import OncueEntity SENSOR_TYPES: tuple[SensorEntityDescription, ...] = ( SensorEntityDescription( @@ -155,7 +153,7 @@ async def async_setup_entry( async_add_entities(entities) -class OncueSensorEntity(CoordinatorEntity, SensorEntity): +class OncueSensorEntity(OncueEntity, SensorEntity): """Representation of an Oncue sensor.""" def __init__( @@ -167,27 +165,13 @@ class OncueSensorEntity(CoordinatorEntity, SensorEntity): description: SensorEntityDescription, ) -> None: """Initialize the sensor.""" - super().__init__(coordinator) - self.entity_description = description - self._device_id = device_id - self._attr_unique_id = f"{device_id}_{description.key}" - self._attr_name = f"{device.name} {sensor.display_name}" + super().__init__(coordinator, device_id, device, sensor, description) if not description.native_unit_of_measurement and sensor.unit is not None: self._attr_native_unit_of_measurement = UNIT_MAPPINGS.get( sensor.unit, sensor.unit ) - self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, device_id)}, - name=device.name, - hw_version=device.hardware_version, - sw_version=device.sensors["FirmwareVersion"].display_value, - model=device.sensors["GensetModelNumberSelect"].display_value, - manufacturer="Kohler", - ) @property - def native_value(self) -> str | None: + def native_value(self) -> str: """Return the sensors state.""" - device: OncueDevice = self.coordinator.data[self._device_id] - sensor: OncueSensor = device.sensors[self.entity_description.key] - return sensor.value + return self._oncue_value diff --git a/tests/components/oncue/test_binary_sensor.py b/tests/components/oncue/test_binary_sensor.py new file mode 100644 index 00000000000..020b914c76b --- /dev/null +++ b/tests/components/oncue/test_binary_sensor.py @@ -0,0 +1,35 @@ +"""Tests for the oncue binary_sensor.""" +from __future__ import annotations + +from homeassistant.components import oncue +from homeassistant.components.oncue.const import DOMAIN +from homeassistant.config_entries import ConfigEntryState +from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, STATE_ON +from homeassistant.core import HomeAssistant +from homeassistant.setup import async_setup_component + +from . import _patch_login_and_data + +from tests.common import MockConfigEntry + + +async def test_binary_sensors(hass: HomeAssistant) -> None: + """Test that the binary sensors are setup with the expected values.""" + config_entry = MockConfigEntry( + domain=DOMAIN, + data={CONF_USERNAME: "any", CONF_PASSWORD: "any"}, + unique_id="any", + ) + config_entry.add_to_hass(hass) + with _patch_login_and_data(): + await async_setup_component(hass, oncue.DOMAIN, {oncue.DOMAIN: {}}) + await hass.async_block_till_done() + assert config_entry.state == ConfigEntryState.LOADED + + assert len(hass.states.async_all("binary_sensor")) == 1 + assert ( + hass.states.get( + "binary_sensor.my_generator_network_connection_established" + ).state + == STATE_ON + ) diff --git a/tests/components/oncue/test_sensor.py b/tests/components/oncue/test_sensor.py index 3f5ee060ff3..f24f0ae628e 100644 --- a/tests/components/oncue/test_sensor.py +++ b/tests/components/oncue/test_sensor.py @@ -1,4 +1,4 @@ -"""Tests for the oncue component.""" +"""Tests for the oncue sensor.""" from __future__ import annotations from homeassistant.components import oncue @@ -26,7 +26,7 @@ async def test_sensors(hass: HomeAssistant) -> None: await hass.async_block_till_done() assert config_entry.state == ConfigEntryState.LOADED - assert len(hass.states.async_all()) == 18 + assert len(hass.states.async_all("sensor")) == 18 assert hass.states.get("sensor.my_generator_latest_firmware").state == "2.0.6" assert hass.states.get("sensor.my_generator_engine_speed").state == "0"