mirror of https://github.com/home-assistant/core
349 lines
12 KiB
Python
349 lines
12 KiB
Python
"""Support for a ScreenLogic Sensor."""
|
|
|
|
from collections.abc import Callable
|
|
from copy import copy
|
|
import dataclasses
|
|
import logging
|
|
|
|
from screenlogicpy.const.data import ATTR, DEVICE, GROUP, VALUE
|
|
from screenlogicpy.const.msg import CODE
|
|
from screenlogicpy.device_const.chemistry import DOSE_STATE
|
|
from screenlogicpy.device_const.pump import PUMP_TYPE
|
|
from screenlogicpy.device_const.system import EQUIPMENT_FLAG
|
|
|
|
from homeassistant.components.sensor import (
|
|
DOMAIN as SENSOR_DOMAIN,
|
|
SensorDeviceClass,
|
|
SensorEntity,
|
|
SensorEntityDescription,
|
|
SensorStateClass,
|
|
)
|
|
from homeassistant.const import EntityCategory
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
|
|
from .coordinator import ScreenlogicDataUpdateCoordinator
|
|
from .entity import (
|
|
ScreenLogicEntity,
|
|
ScreenLogicEntityDescription,
|
|
ScreenLogicPushEntity,
|
|
ScreenLogicPushEntityDescription,
|
|
)
|
|
from .types import ScreenLogicConfigEntry
|
|
from .util import cleanup_excluded_entity, get_ha_unit
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
@dataclasses.dataclass(frozen=True, kw_only=True)
|
|
class ScreenLogicSensorDescription(
|
|
SensorEntityDescription, ScreenLogicEntityDescription
|
|
):
|
|
"""Describes a ScreenLogic sensor."""
|
|
|
|
value_mod: Callable[[int | str], int | str] | None = None
|
|
|
|
|
|
@dataclasses.dataclass(frozen=True, kw_only=True)
|
|
class ScreenLogicPushSensorDescription(
|
|
ScreenLogicSensorDescription, ScreenLogicPushEntityDescription
|
|
):
|
|
"""Describes a ScreenLogic push sensor."""
|
|
|
|
|
|
SUPPORTED_CORE_SENSORS = [
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.STATUS_CHANGED,
|
|
data_root=(DEVICE.CONTROLLER, GROUP.SENSOR),
|
|
key=VALUE.AIR_TEMPERATURE,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
]
|
|
|
|
SUPPORTED_PUMP_SENSORS = [
|
|
ScreenLogicSensorDescription(
|
|
data_root=(DEVICE.PUMP,),
|
|
key=VALUE.WATTS_NOW,
|
|
device_class=SensorDeviceClass.POWER,
|
|
),
|
|
ScreenLogicSensorDescription(
|
|
data_root=(DEVICE.PUMP,),
|
|
key=VALUE.GPM_NOW,
|
|
enabled_lambda=lambda type: type != PUMP_TYPE.INTELLIFLO_VS,
|
|
),
|
|
ScreenLogicSensorDescription(
|
|
data_root=(DEVICE.PUMP,),
|
|
key=VALUE.RPM_NOW,
|
|
enabled_lambda=lambda type: type != PUMP_TYPE.INTELLIFLO_VF,
|
|
),
|
|
]
|
|
|
|
SUPPORTED_INTELLICHEM_SENSORS = [
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.STATUS_CHANGED,
|
|
data_root=(DEVICE.CONTROLLER, GROUP.SENSOR),
|
|
key=VALUE.ORP,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.STATUS_CHANGED,
|
|
data_root=(DEVICE.CONTROLLER, GROUP.SENSOR),
|
|
key=VALUE.PH,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.SENSOR),
|
|
key=VALUE.ORP_NOW,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.SENSOR),
|
|
key=VALUE.PH_NOW,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.SENSOR),
|
|
key=VALUE.ORP_SUPPLY_LEVEL,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
value_mod=lambda val: int(val) - 1,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.SENSOR),
|
|
key=VALUE.PH_SUPPLY_LEVEL,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
value_mod=lambda val: int(val) - 1,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.SENSOR),
|
|
key=VALUE.PH_PROBE_WATER_TEMP,
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.SENSOR),
|
|
key=VALUE.SATURATION,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.CONFIGURATION),
|
|
key=VALUE.CALCIUM_HARDNESS,
|
|
entity_registry_enabled_default=False, # Superseded by number entity
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.CONFIGURATION),
|
|
key=VALUE.CYA,
|
|
entity_registry_enabled_default=False, # Superseded by number entity
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.CONFIGURATION),
|
|
key=VALUE.ORP_SETPOINT,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.CONFIGURATION),
|
|
key=VALUE.PH_SETPOINT,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.CONFIGURATION),
|
|
key=VALUE.TOTAL_ALKALINITY,
|
|
entity_registry_enabled_default=False, # Superseded by number entity
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.CONFIGURATION),
|
|
key=VALUE.SALT_TDS_PPM,
|
|
entity_registry_enabled_default=False, # Superseded by number entity
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.DOSE_STATUS),
|
|
key=VALUE.ORP_DOSING_STATE,
|
|
device_class=SensorDeviceClass.ENUM,
|
|
options=["Dosing", "Mixing", "Monitoring"],
|
|
value_mod=lambda val: DOSE_STATE(val).title,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.DOSE_STATUS),
|
|
key=VALUE.ORP_LAST_DOSE_TIME,
|
|
device_class=SensorDeviceClass.DURATION,
|
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.DOSE_STATUS),
|
|
key=VALUE.ORP_LAST_DOSE_VOLUME,
|
|
device_class=SensorDeviceClass.VOLUME,
|
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.DOSE_STATUS),
|
|
key=VALUE.PH_DOSING_STATE,
|
|
device_class=SensorDeviceClass.ENUM,
|
|
options=["Dosing", "Mixing", "Monitoring"],
|
|
value_mod=lambda val: DOSE_STATE(val).title,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.DOSE_STATUS),
|
|
key=VALUE.PH_LAST_DOSE_TIME,
|
|
device_class=SensorDeviceClass.DURATION,
|
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
|
),
|
|
ScreenLogicPushSensorDescription(
|
|
subscription_code=CODE.CHEMISTRY_CHANGED,
|
|
data_root=(DEVICE.INTELLICHEM, GROUP.DOSE_STATUS),
|
|
key=VALUE.PH_LAST_DOSE_VOLUME,
|
|
device_class=SensorDeviceClass.VOLUME,
|
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
|
),
|
|
]
|
|
|
|
SUPPORTED_SCG_SENSORS = [
|
|
ScreenLogicSensorDescription(
|
|
data_root=(DEVICE.SCG, GROUP.SENSOR),
|
|
key=VALUE.SALT_PPM,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
ScreenLogicSensorDescription(
|
|
data_root=(DEVICE.SCG, GROUP.CONFIGURATION),
|
|
key=VALUE.SUPER_CHLOR_TIMER,
|
|
),
|
|
]
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
config_entry: ScreenLogicConfigEntry,
|
|
async_add_entities: AddEntitiesCallback,
|
|
) -> None:
|
|
"""Set up entry."""
|
|
coordinator = config_entry.runtime_data
|
|
gateway = coordinator.gateway
|
|
|
|
entities: list[ScreenLogicSensor] = [
|
|
ScreenLogicPushSensor(coordinator, core_sensor_description)
|
|
for core_sensor_description in SUPPORTED_CORE_SENSORS
|
|
if (
|
|
gateway.get_data(
|
|
*core_sensor_description.data_root, core_sensor_description.key
|
|
)
|
|
is not None
|
|
)
|
|
]
|
|
|
|
for pump_index, pump_data in gateway.get_data(DEVICE.PUMP).items():
|
|
if not pump_data or not pump_data.get(VALUE.DATA):
|
|
continue
|
|
pump_type = pump_data[VALUE.TYPE]
|
|
for proto_pump_sensor_description in SUPPORTED_PUMP_SENSORS:
|
|
if not pump_data.get(proto_pump_sensor_description.key):
|
|
continue
|
|
entities.append(
|
|
ScreenLogicPumpSensor(
|
|
coordinator,
|
|
copy(proto_pump_sensor_description),
|
|
pump_index,
|
|
pump_type,
|
|
)
|
|
)
|
|
|
|
chem_sensor_description: ScreenLogicPushSensorDescription
|
|
for chem_sensor_description in SUPPORTED_INTELLICHEM_SENSORS:
|
|
chem_sensor_data_path = (
|
|
*chem_sensor_description.data_root,
|
|
chem_sensor_description.key,
|
|
)
|
|
if EQUIPMENT_FLAG.INTELLICHEM not in gateway.equipment_flags:
|
|
cleanup_excluded_entity(coordinator, SENSOR_DOMAIN, chem_sensor_data_path)
|
|
continue
|
|
if gateway.get_data(*chem_sensor_data_path):
|
|
chem_sensor_description = dataclasses.replace(
|
|
chem_sensor_description, entity_category=EntityCategory.DIAGNOSTIC
|
|
)
|
|
entities.append(ScreenLogicPushSensor(coordinator, chem_sensor_description))
|
|
|
|
scg_sensor_description: ScreenLogicSensorDescription
|
|
for scg_sensor_description in SUPPORTED_SCG_SENSORS:
|
|
scg_sensor_data_path = (
|
|
*scg_sensor_description.data_root,
|
|
scg_sensor_description.key,
|
|
)
|
|
if EQUIPMENT_FLAG.CHLORINATOR not in gateway.equipment_flags:
|
|
cleanup_excluded_entity(coordinator, SENSOR_DOMAIN, scg_sensor_data_path)
|
|
continue
|
|
if gateway.get_data(*scg_sensor_data_path):
|
|
scg_sensor_description = dataclasses.replace(
|
|
scg_sensor_description, entity_category=EntityCategory.DIAGNOSTIC
|
|
)
|
|
entities.append(ScreenLogicSensor(coordinator, scg_sensor_description))
|
|
|
|
async_add_entities(entities)
|
|
|
|
|
|
class ScreenLogicSensor(ScreenLogicEntity, SensorEntity):
|
|
"""Representation of a ScreenLogic sensor entity."""
|
|
|
|
entity_description: ScreenLogicSensorDescription
|
|
_attr_has_entity_name = True
|
|
|
|
def __init__(
|
|
self,
|
|
coordinator: ScreenlogicDataUpdateCoordinator,
|
|
entity_description: ScreenLogicSensorDescription,
|
|
) -> None:
|
|
"""Initialize of the entity."""
|
|
super().__init__(coordinator, entity_description)
|
|
self._attr_native_unit_of_measurement = get_ha_unit(
|
|
self.entity_data.get(ATTR.UNIT)
|
|
)
|
|
|
|
@property
|
|
def native_value(self) -> str | int | float:
|
|
"""State of the sensor."""
|
|
val = self.entity_data[ATTR.VALUE]
|
|
value_mod = self.entity_description.value_mod
|
|
return value_mod(val) if value_mod else val
|
|
|
|
|
|
class ScreenLogicPushSensor(ScreenLogicSensor, ScreenLogicPushEntity):
|
|
"""Representation of a ScreenLogic push sensor entity."""
|
|
|
|
entity_description: ScreenLogicPushSensorDescription
|
|
|
|
|
|
class ScreenLogicPumpSensor(ScreenLogicSensor):
|
|
"""Representation of a ScreenLogic pump sensor."""
|
|
|
|
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
|
_attr_state_class = SensorStateClass.MEASUREMENT
|
|
|
|
def __init__(
|
|
self,
|
|
coordinator: ScreenlogicDataUpdateCoordinator,
|
|
entity_description: ScreenLogicSensorDescription,
|
|
pump_index: int,
|
|
pump_type: int,
|
|
) -> None:
|
|
"""Initialize of the entity."""
|
|
entity_description = dataclasses.replace(
|
|
entity_description, data_root=(DEVICE.PUMP, pump_index)
|
|
)
|
|
super().__init__(coordinator, entity_description)
|
|
if entity_description.enabled_lambda:
|
|
self._attr_entity_registry_enabled_default = (
|
|
entity_description.enabled_lambda(pump_type)
|
|
)
|