diff --git a/.coveragerc b/.coveragerc index 6c40a3e043d..b394d77c267 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1693,8 +1693,10 @@ omit = homeassistant/components/myuplink/__init__.py homeassistant/components/myuplink/api.py homeassistant/components/myuplink/application_credentials.py + homeassistant/components/myuplink/binary_sensor.py homeassistant/components/myuplink/coordinator.py homeassistant/components/myuplink/entity.py + homeassistant/components/myuplink/helpers.py homeassistant/components/myuplink/sensor.py diff --git a/homeassistant/components/myuplink/__init__.py b/homeassistant/components/myuplink/__init__.py index 9f8de402b1f..ec98fdf47c0 100644 --- a/homeassistant/components/myuplink/__init__.py +++ b/homeassistant/components/myuplink/__init__.py @@ -16,7 +16,11 @@ from .api import AsyncConfigEntryAuth from .const import DOMAIN from .coordinator import MyUplinkDataCoordinator -PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.UPDATE] +PLATFORMS: list[Platform] = [ + Platform.BINARY_SENSOR, + Platform.SENSOR, + Platform.UPDATE, +] async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: diff --git a/homeassistant/components/myuplink/binary_sensor.py b/homeassistant/components/myuplink/binary_sensor.py new file mode 100644 index 00000000000..b5ade88a002 --- /dev/null +++ b/homeassistant/components/myuplink/binary_sensor.py @@ -0,0 +1,100 @@ +"""Binary sensors for myUplink.""" + +from myuplink import DevicePoint + +from homeassistant.components.binary_sensor import ( + BinarySensorEntity, + BinarySensorEntityDescription, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddEntitiesCallback + +from . import MyUplinkDataCoordinator +from .const import DOMAIN +from .entity import MyUplinkEntity +from .helpers import find_matching_platform + +CATEGORY_BASED_DESCRIPTIONS: dict[str, dict[str, BinarySensorEntityDescription]] = { + "NIBEF": { + "43161": BinarySensorEntityDescription( + key="elect_add", + icon="mdi:electric-switch", + ), + }, +} + + +def get_description(device_point: DevicePoint) -> BinarySensorEntityDescription | None: + """Get description for a device point. + + Priorities: + 1. Category specific prefix e.g "NIBEF" + 2. Default to None + """ + prefix, _, _ = device_point.category.partition(" ") + description = CATEGORY_BASED_DESCRIPTIONS.get(prefix, {}).get( + device_point.parameter_id + ) + + return description + + +async def async_setup_entry( + hass: HomeAssistant, + config_entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up myUplink binary_sensor.""" + entities: list[BinarySensorEntity] = [] + coordinator: MyUplinkDataCoordinator = hass.data[DOMAIN][config_entry.entry_id] + + # Setup device point sensors + for device_id, point_data in coordinator.data.points.items(): + for point_id, device_point in point_data.items(): + if find_matching_platform(device_point) == Platform.BINARY_SENSOR: + description = get_description(device_point) + + entities.append( + MyUplinkDevicePointBinarySensor( + coordinator=coordinator, + device_id=device_id, + device_point=device_point, + entity_description=description, + unique_id_suffix=point_id, + ) + ) + async_add_entities(entities) + + +class MyUplinkDevicePointBinarySensor(MyUplinkEntity, BinarySensorEntity): + """Representation of a myUplink device point binary sensor.""" + + def __init__( + self, + coordinator: MyUplinkDataCoordinator, + device_id: str, + device_point: DevicePoint, + entity_description: BinarySensorEntityDescription | None, + unique_id_suffix: str, + ) -> None: + """Initialize the binary_sensor.""" + super().__init__( + coordinator=coordinator, + device_id=device_id, + unique_id_suffix=unique_id_suffix, + ) + + # Internal properties + self.point_id = device_point.parameter_id + self._attr_name = device_point.parameter_name + + if entity_description is not None: + self.entity_description = entity_description + + @property + def is_on(self) -> bool: + """Binary sensor state value.""" + device_point = self.coordinator.data.points[self.device_id][self.point_id] + return int(device_point.value) != 0 diff --git a/homeassistant/components/myuplink/helpers.py b/homeassistant/components/myuplink/helpers.py new file mode 100644 index 00000000000..86fbab52cae --- /dev/null +++ b/homeassistant/components/myuplink/helpers.py @@ -0,0 +1,21 @@ +"""Helper collection for myuplink.""" + +from myuplink import DevicePoint + +from homeassistant.const import Platform + + +def find_matching_platform(device_point: DevicePoint) -> Platform: + """Find entity platform for a DevicePoint.""" + if ( + len(device_point.enum_values) == 2 + and device_point.enum_values[0]["value"] == "0" + and device_point.enum_values[1]["value"] == "1" + ): + if device_point.writable: + # Change to Platform.SWITCH when platform is implemented + # return Platform.SWITCH + return Platform.SENSOR + return Platform.BINARY_SENSOR + + return Platform.SENSOR diff --git a/homeassistant/components/myuplink/sensor.py b/homeassistant/components/myuplink/sensor.py index 731153b49bb..752fab13448 100644 --- a/homeassistant/components/myuplink/sensor.py +++ b/homeassistant/components/myuplink/sensor.py @@ -10,6 +10,7 @@ from homeassistant.components.sensor import ( ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( + Platform, UnitOfElectricCurrent, UnitOfEnergy, UnitOfFrequency, @@ -26,6 +27,7 @@ from homeassistant.helpers.typing import StateType from . import MyUplinkDataCoordinator from .const import DOMAIN from .entity import MyUplinkEntity +from .helpers import find_matching_platform DEVICE_POINT_UNIT_DESCRIPTIONS: dict[str, SensorEntityDescription] = { "°C": SensorEntityDescription( @@ -153,32 +155,33 @@ async def async_setup_entry( # Setup device point sensors for device_id, point_data in coordinator.data.points.items(): for point_id, device_point in point_data.items(): - description = get_description(device_point) - entity_class = MyUplinkDevicePointSensor - if ( - description is not None - and description.device_class == SensorDeviceClass.ENUM - ): + if find_matching_platform(device_point) == Platform.SENSOR: + description = get_description(device_point) + entity_class = MyUplinkDevicePointSensor + if ( + description is not None + and description.device_class == SensorDeviceClass.ENUM + ): + entities.append( + MyUplinkEnumRawSensor( + coordinator=coordinator, + device_id=device_id, + device_point=device_point, + entity_description=description, + unique_id_suffix=f"{point_id}-raw", + ) + ) + entity_class = MyUplinkEnumSensor + entities.append( - MyUplinkEnumRawSensor( + entity_class( coordinator=coordinator, device_id=device_id, device_point=device_point, entity_description=description, - unique_id_suffix=f"{point_id}-raw", + unique_id_suffix=point_id, ) ) - entity_class = MyUplinkEnumSensor - - entities.append( - entity_class( - coordinator=coordinator, - device_id=device_id, - device_point=device_point, - entity_description=description, - unique_id_suffix=point_id, - ) - ) async_add_entities(entities)