From c15407717753d66cd07082aad90669ea0586be09 Mon Sep 17 00:00:00 2001 From: Charles Garwood Date: Tue, 8 Aug 2023 14:03:02 -0400 Subject: [PATCH] Add Encharge binary sensors to Enphase integration (#98039) * Add Encharge binary sensors to Enphase integration * Code review minor cleanup * Add to coveragerc --- .coveragerc | 1 + .../components/enphase_envoy/binary_sensor.py | 141 ++++++++++++++++++ .../components/enphase_envoy/const.py | 2 +- .../components/enphase_envoy/strings.json | 11 ++ 4 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 homeassistant/components/enphase_envoy/binary_sensor.py diff --git a/.coveragerc b/.coveragerc index 2e35001ee14..cb9ca19c5b2 100644 --- a/.coveragerc +++ b/.coveragerc @@ -302,6 +302,7 @@ omit = homeassistant/components/enocean/sensor.py homeassistant/components/enocean/switch.py homeassistant/components/enphase_envoy/__init__.py + homeassistant/components/enphase_envoy/binary_sensor.py homeassistant/components/enphase_envoy/coordinator.py homeassistant/components/enphase_envoy/sensor.py homeassistant/components/entur_public_transport/* diff --git a/homeassistant/components/enphase_envoy/binary_sensor.py b/homeassistant/components/enphase_envoy/binary_sensor.py new file mode 100644 index 00000000000..af57a4da6af --- /dev/null +++ b/homeassistant/components/enphase_envoy/binary_sensor.py @@ -0,0 +1,141 @@ +"""Support for Enphase Envoy solar energy monitor.""" +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass +import logging + +from pyenphase import ( + EnvoyData, + EnvoyEncharge, +) + +from homeassistant.components.binary_sensor import ( + BinarySensorDeviceClass, + BinarySensorEntity, + BinarySensorEntityDescription, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import EntityCategory +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity import DeviceInfo +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import ( + CoordinatorEntity, +) + +from .const import DOMAIN +from .coordinator import EnphaseUpdateCoordinator + +_LOGGER = logging.getLogger(__name__) + + +@dataclass +class EnvoyEnchargeRequiredKeysMixin: + """Mixin for required keys.""" + + value_fn: Callable[[EnvoyEncharge], bool] + + +@dataclass +class EnvoyEnchargeBinarySensorEntityDescription( + BinarySensorEntityDescription, EnvoyEnchargeRequiredKeysMixin +): + """Describes an Envoy Encharge binary sensor entity.""" + + +ENCHARGE_SENSORS = ( + EnvoyEnchargeBinarySensorEntityDescription( + key="communicating", + translation_key="communicating", + device_class=BinarySensorDeviceClass.CONNECTIVITY, + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda encharge: encharge.communicating, + ), + EnvoyEnchargeBinarySensorEntityDescription( + key="dc_switch", + translation_key="dc_switch", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda encharge: not encharge.dc_switch_off, + ), + EnvoyEnchargeBinarySensorEntityDescription( + key="operating", + translation_key="operating", + entity_category=EntityCategory.DIAGNOSTIC, + value_fn=lambda encharge: encharge.operating, + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + config_entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up envoy binary sensor platform.""" + coordinator: EnphaseUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] + envoy_data = coordinator.envoy.data + assert envoy_data is not None + envoy_serial_num = config_entry.unique_id + assert envoy_serial_num is not None + entities: list[BinarySensorEntity] = [] + if envoy_data.encharge_inventory: + entities.extend( + EnvoyEnchargeBinarySensorEntity(coordinator, description, encharge) + for description in ENCHARGE_SENSORS + for encharge in envoy_data.encharge_inventory + ) + + async_add_entities(entities) + + +class EnvoyEnchargeBinarySensorEntity( + CoordinatorEntity[EnphaseUpdateCoordinator], BinarySensorEntity +): + """Defines a base envoy binary_sensor entity.""" + + _attr_has_entity_name = True + entity_description: EnvoyEnchargeBinarySensorEntityDescription + + def __init__( + self, + coordinator: EnphaseUpdateCoordinator, + description: EnvoyEnchargeBinarySensorEntityDescription, + serial_number: str, + ) -> None: + """Init the Encharge base entity.""" + self.entity_description = description + self.coordinator = coordinator + assert serial_number is not None + + self.envoy_serial_num = coordinator.envoy.serial_number + assert self.envoy_serial_num is not None + + self._serial_number = serial_number + self._attr_unique_id = f"{serial_number}_{description.key}" + encharge_inventory = self.data.encharge_inventory + assert encharge_inventory is not None + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, serial_number)}, + manufacturer="Enphase", + model="Encharge", + name=f"Encharge {serial_number}", + sw_version=str(encharge_inventory[self._serial_number].firmware_version), + via_device=(DOMAIN, self.envoy_serial_num), + ) + + super().__init__(coordinator) + + @property + def data(self) -> EnvoyData: + """Return envoy data.""" + data = self.coordinator.envoy.data + assert data is not None + return data + + @property + def is_on(self) -> bool: + """Return the state of the Encharge binary_sensor.""" + encharge_inventory = self.data.encharge_inventory + assert encharge_inventory is not None + return self.entity_description.value_fn(encharge_inventory[self._serial_number]) diff --git a/homeassistant/components/enphase_envoy/const.py b/homeassistant/components/enphase_envoy/const.py index 029453660fd..662662aa8be 100644 --- a/homeassistant/components/enphase_envoy/const.py +++ b/homeassistant/components/enphase_envoy/const.py @@ -8,6 +8,6 @@ from homeassistant.const import Platform DOMAIN = "enphase_envoy" -PLATFORMS = [Platform.SENSOR] +PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR] INVALID_AUTH_ERRORS = (EnvoyAuthenticationError, EnvoyAuthenticationRequired) diff --git a/homeassistant/components/enphase_envoy/strings.json b/homeassistant/components/enphase_envoy/strings.json index d503dacb2d8..46ec7d9607f 100644 --- a/homeassistant/components/enphase_envoy/strings.json +++ b/homeassistant/components/enphase_envoy/strings.json @@ -22,6 +22,17 @@ } }, "entity": { + "binary_sensor": { + "communicating": { + "name": "Communicating" + }, + "dc_switch": { + "name": "DC Switch" + }, + "operating": { + "name": "Operating" + } + }, "sensor": { "last_reported": { "name": "Last reported"