Files
core/homeassistant/components/sofar/binary_sensor.py
T

126 lines
3.8 KiB
Python

"""Support for Sofar binary sensors."""
from collections.abc import Callable
from dataclasses import dataclass
from enum import IntFlag
from typing import override
from sofar_modbus.modern.device import SofarInverter
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."""
flags_fn: Callable[[SofarInverter], IntFlag | None]
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,
flags_fn=lambda device: device.active_power_control.power_control,
flag=PowerControlFlags.ACTIVE_POWER,
),
)
async def async_setup_entry(
hass: HomeAssistant,
entry: SofarConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up the Sofar 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:
return any(
fault.category is self.entity_description.category
for fault in self.coordinator.device.state.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 | None:
flags = self.entity_description.flags_fn(self.coordinator.device)
return None if flags is None else self.entity_description.flag in flags