Files

126 lines
3.8 KiB
Python

"""Support for Sofar binary sensors."""
from dataclasses import dataclass
from enum import IntFlag
from typing import override
from sofar_modbus.modern.enums import PowerControlFlags
from sofar_modbus.modern.faults import FaultCategory
from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .coordinator import SofarConfigEntry
from .entity import SofarEntity, SofarEntityDescription
PARALLEL_UPDATES = 0
_DISABLED_BY_DEFAULT = frozenset(
{
FaultCategory.ARC_FAULT,
FaultCategory.COMBINER_BOX,
FaultCategory.INPUT_FUSE,
FaultCategory.STRING_FUSE,
}
)
@dataclass(frozen=True, kw_only=True)
class SofarFaultBinarySensorDescription(
SofarEntityDescription, BinarySensorEntityDescription
):
"""Describe a Sofar fault-category binary sensor."""
category: FaultCategory
FAULT_SENSOR_DESCRIPTIONS: tuple[SofarFaultBinarySensorDescription, ...] = tuple(
SofarFaultBinarySensorDescription(
key=f"fault_{category.value}",
component="state",
translation_key=f"fault_{category.value}",
device_class=BinarySensorDeviceClass.PROBLEM,
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=category not in _DISABLED_BY_DEFAULT,
category=category,
)
for category in FaultCategory
)
@dataclass(frozen=True, kw_only=True)
class SofarFlagBinarySensorDescription(
SofarEntityDescription, BinarySensorEntityDescription
):
"""Describe a Sofar binary sensor backed by one flags-register bit."""
attribute: str
flag: IntFlag
FLAG_SENSOR_DESCRIPTIONS: tuple[SofarFlagBinarySensorDescription, ...] = (
SofarFlagBinarySensorDescription(
key="active_power_limit_enabled",
component="active_power_control",
translation_key="active_power_limit_enabled",
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
attribute="power_control",
flag=PowerControlFlags.ACTIVE_POWER,
),
)
async def async_setup_entry(
hass: HomeAssistant,
entry: SofarConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Sofar Inverter Modbus binary sensor platform."""
runtime_data = entry.runtime_data
served = runtime_data.served_components
async_add_entities(
SofarFaultBinarySensor(runtime_data, description)
for description in FAULT_SENSOR_DESCRIPTIONS
if description.component in served
)
async_add_entities(
SofarFlagBinarySensor(runtime_data, description)
for description in FLAG_SENSOR_DESCRIPTIONS
if description.component in served
)
class SofarFaultBinarySensor(SofarEntity, BinarySensorEntity):
"""Reports whether any fault in one subsystem is currently active."""
entity_description: SofarFaultBinarySensorDescription
@property
@override
def is_on(self) -> bool:
component = getattr(self.coordinator.device, self.entity_description.component)
return any(
fault.category is self.entity_description.category
for fault in component.active_faults
)
class SofarFlagBinarySensor(SofarEntity, BinarySensorEntity):
"""Reports whether one bit of a flags register is set."""
entity_description: SofarFlagBinarySensorDescription
@property
@override
def is_on(self) -> bool:
component = getattr(self.coordinator.device, self.entity_description.component)
flags = getattr(component, self.entity_description.attribute)
return self.entity_description.flag in flags