mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +00:00
Explicitly define ScreenLogic entity descriptions (#100173)
This commit is contained in:
parent
2ae07096d2
commit
77007ef091
@ -129,9 +129,12 @@ async def _async_migrate_entries(
|
||||
new_key,
|
||||
)
|
||||
continue
|
||||
assert device is not None and (
|
||||
device != "pump" or (device == "pump" and source_index is not None)
|
||||
)
|
||||
if device == "pump" and source_index is None:
|
||||
_LOGGER.debug(
|
||||
"Unable to parse 'source_index' from existing unique_id for pump entity '%s'",
|
||||
source_key,
|
||||
)
|
||||
continue
|
||||
new_unique_id = (
|
||||
f"{source_mac}_{generate_unique_id(device, source_index, new_key)}"
|
||||
)
|
||||
@ -152,7 +155,6 @@ async def _async_migrate_entries(
|
||||
updates["new_unique_id"] = new_unique_id
|
||||
|
||||
if (old_name := migrations.get("old_name")) is not None:
|
||||
assert old_name
|
||||
new_name = migrations["new_name"]
|
||||
if (s_old_name := slugify(old_name)) in entry.entity_id:
|
||||
new_entity_id = entry.entity_id.replace(s_old_name, slugify(new_name))
|
||||
|
@ -1,9 +1,12 @@
|
||||
"""Support for a ScreenLogic Binary Sensor."""
|
||||
from copy import copy
|
||||
from dataclasses import dataclass
|
||||
import logging
|
||||
|
||||
from screenlogicpy.const.common import DEVICE_TYPE, ON_OFF
|
||||
from screenlogicpy.const.common import ON_OFF
|
||||
from screenlogicpy.const.data import ATTR, DEVICE, GROUP, VALUE
|
||||
from screenlogicpy.const.msg import CODE
|
||||
from screenlogicpy.device_const.system import EQUIPMENT_FLAG
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
DOMAIN,
|
||||
@ -12,85 +15,157 @@ from homeassistant.components.binary_sensor import (
|
||||
BinarySensorEntityDescription,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN as SL_DOMAIN, ScreenLogicDataPath
|
||||
from .const import DOMAIN as SL_DOMAIN
|
||||
from .coordinator import ScreenlogicDataUpdateCoordinator
|
||||
from .data import (
|
||||
DEVICE_INCLUSION_RULES,
|
||||
DEVICE_SUBSCRIPTION,
|
||||
SupportedValueParameters,
|
||||
build_base_entity_description,
|
||||
iterate_expand_group_wildcard,
|
||||
preprocess_supported_values,
|
||||
)
|
||||
from .entity import (
|
||||
ScreenlogicEntity,
|
||||
ScreenLogicEntityDescription,
|
||||
ScreenLogicPushEntity,
|
||||
ScreenLogicPushEntityDescription,
|
||||
)
|
||||
from .util import cleanup_excluded_entity, generate_unique_id
|
||||
from .util import cleanup_excluded_entity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class SupportedBinarySensorValueParameters(SupportedValueParameters):
|
||||
"""Supported predefined data for a ScreenLogic binary sensor entity."""
|
||||
|
||||
device_class: BinarySensorDeviceClass | None = None
|
||||
class ScreenLogicBinarySensorDescription(
|
||||
BinarySensorEntityDescription, ScreenLogicEntityDescription
|
||||
):
|
||||
"""A class that describes ScreenLogic binary sensor eneites."""
|
||||
|
||||
|
||||
SUPPORTED_DATA: list[
|
||||
tuple[ScreenLogicDataPath, SupportedValueParameters]
|
||||
] = preprocess_supported_values(
|
||||
{
|
||||
DEVICE.CONTROLLER: {
|
||||
GROUP.SENSOR: {
|
||||
VALUE.ACTIVE_ALERT: SupportedBinarySensorValueParameters(),
|
||||
VALUE.CLEANER_DELAY: SupportedBinarySensorValueParameters(),
|
||||
VALUE.FREEZE_MODE: SupportedBinarySensorValueParameters(),
|
||||
VALUE.POOL_DELAY: SupportedBinarySensorValueParameters(),
|
||||
VALUE.SPA_DELAY: SupportedBinarySensorValueParameters(),
|
||||
},
|
||||
},
|
||||
DEVICE.PUMP: {
|
||||
"*": {
|
||||
VALUE.STATE: SupportedBinarySensorValueParameters(),
|
||||
},
|
||||
},
|
||||
DEVICE.INTELLICHEM: {
|
||||
GROUP.ALARM: {
|
||||
VALUE.FLOW_ALARM: SupportedBinarySensorValueParameters(),
|
||||
VALUE.ORP_HIGH_ALARM: SupportedBinarySensorValueParameters(),
|
||||
VALUE.ORP_LOW_ALARM: SupportedBinarySensorValueParameters(),
|
||||
VALUE.ORP_SUPPLY_ALARM: SupportedBinarySensorValueParameters(),
|
||||
VALUE.PH_HIGH_ALARM: SupportedBinarySensorValueParameters(),
|
||||
VALUE.PH_LOW_ALARM: SupportedBinarySensorValueParameters(),
|
||||
VALUE.PH_SUPPLY_ALARM: SupportedBinarySensorValueParameters(),
|
||||
VALUE.PROBE_FAULT_ALARM: SupportedBinarySensorValueParameters(),
|
||||
},
|
||||
GROUP.ALERT: {
|
||||
VALUE.ORP_LIMIT: SupportedBinarySensorValueParameters(),
|
||||
VALUE.PH_LIMIT: SupportedBinarySensorValueParameters(),
|
||||
VALUE.PH_LOCKOUT: SupportedBinarySensorValueParameters(),
|
||||
},
|
||||
GROUP.WATER_BALANCE: {
|
||||
VALUE.CORROSIVE: SupportedBinarySensorValueParameters(),
|
||||
VALUE.SCALING: SupportedBinarySensorValueParameters(),
|
||||
},
|
||||
},
|
||||
DEVICE.SCG: {
|
||||
GROUP.SENSOR: {
|
||||
VALUE.STATE: SupportedBinarySensorValueParameters(),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
@dataclass
|
||||
class ScreenLogicPushBinarySensorDescription(
|
||||
ScreenLogicBinarySensorDescription, ScreenLogicPushEntityDescription
|
||||
):
|
||||
"""Describes a ScreenLogicPushBinarySensor."""
|
||||
|
||||
SL_DEVICE_TYPE_TO_HA_DEVICE_CLASS = {DEVICE_TYPE.ALARM: BinarySensorDeviceClass.PROBLEM}
|
||||
|
||||
SUPPORTED_CORE_SENSORS = [
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.STATUS_CHANGED,
|
||||
data_root=(DEVICE.CONTROLLER, GROUP.SENSOR),
|
||||
key=VALUE.ACTIVE_ALERT,
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.STATUS_CHANGED,
|
||||
data_root=(DEVICE.CONTROLLER, GROUP.SENSOR),
|
||||
key=VALUE.CLEANER_DELAY,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.STATUS_CHANGED,
|
||||
data_root=(DEVICE.CONTROLLER, GROUP.SENSOR),
|
||||
key=VALUE.FREEZE_MODE,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.STATUS_CHANGED,
|
||||
data_root=(DEVICE.CONTROLLER, GROUP.SENSOR),
|
||||
key=VALUE.POOL_DELAY,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.STATUS_CHANGED,
|
||||
data_root=(DEVICE.CONTROLLER, GROUP.SENSOR),
|
||||
key=VALUE.SPA_DELAY,
|
||||
),
|
||||
]
|
||||
|
||||
SUPPORTED_PUMP_SENSORS = [
|
||||
ScreenLogicBinarySensorDescription(
|
||||
data_root=(DEVICE.PUMP,),
|
||||
key=VALUE.STATE,
|
||||
)
|
||||
]
|
||||
|
||||
SUPPORTED_INTELLICHEM_SENSORS = [
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.ALARM),
|
||||
key=VALUE.FLOW_ALARM,
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.ALARM),
|
||||
key=VALUE.ORP_HIGH_ALARM,
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.ALARM),
|
||||
key=VALUE.ORP_LOW_ALARM,
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.ALARM),
|
||||
key=VALUE.ORP_SUPPLY_ALARM,
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.ALARM),
|
||||
key=VALUE.PH_HIGH_ALARM,
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.ALARM),
|
||||
key=VALUE.PH_LOW_ALARM,
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.ALARM),
|
||||
key=VALUE.PH_SUPPLY_ALARM,
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.ALARM),
|
||||
key=VALUE.PROBE_FAULT_ALARM,
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.ALERT),
|
||||
key=VALUE.ORP_LIMIT,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.ALERT),
|
||||
key=VALUE.PH_LIMIT,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.ALERT),
|
||||
key=VALUE.PH_LOCKOUT,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.WATER_BALANCE),
|
||||
key=VALUE.CORROSIVE,
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
),
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.WATER_BALANCE),
|
||||
key=VALUE.SCALING,
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
),
|
||||
]
|
||||
|
||||
SUPPORTED_SCG_SENSORS = [
|
||||
ScreenLogicBinarySensorDescription(
|
||||
data_root=(DEVICE.SCG, GROUP.SENSOR),
|
||||
key=VALUE.STATE,
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
@ -104,72 +179,65 @@ async def async_setup_entry(
|
||||
config_entry.entry_id
|
||||
]
|
||||
gateway = coordinator.gateway
|
||||
data_path: ScreenLogicDataPath
|
||||
value_params: SupportedBinarySensorValueParameters
|
||||
for data_path, value_params in iterate_expand_group_wildcard(
|
||||
gateway, SUPPORTED_DATA
|
||||
):
|
||||
entity_key = generate_unique_id(*data_path)
|
||||
|
||||
device = data_path[0]
|
||||
|
||||
if not (DEVICE_INCLUSION_RULES.get(device) or value_params.included).test(
|
||||
gateway, data_path
|
||||
):
|
||||
cleanup_excluded_entity(coordinator, DOMAIN, entity_key)
|
||||
continue
|
||||
|
||||
try:
|
||||
value_data = gateway.get_data(*data_path, strict=True)
|
||||
except KeyError:
|
||||
_LOGGER.debug("Failed to find %s", data_path)
|
||||
continue
|
||||
|
||||
entity_description_kwargs = {
|
||||
**build_base_entity_description(
|
||||
gateway, entity_key, data_path, value_data, value_params
|
||||
),
|
||||
"device_class": SL_DEVICE_TYPE_TO_HA_DEVICE_CLASS.get(
|
||||
value_data.get(ATTR.DEVICE_TYPE)
|
||||
),
|
||||
}
|
||||
|
||||
for core_sensor_description in SUPPORTED_CORE_SENSORS:
|
||||
if (
|
||||
sub_code := (
|
||||
value_params.subscription_code or DEVICE_SUBSCRIPTION.get(device)
|
||||
gateway.get_data(
|
||||
*core_sensor_description.data_root, core_sensor_description.key
|
||||
)
|
||||
) is not None:
|
||||
is not None
|
||||
):
|
||||
entities.append(
|
||||
ScreenLogicPushBinarySensor(
|
||||
coordinator,
|
||||
ScreenLogicPushBinarySensorDescription(
|
||||
subscription_code=sub_code, **entity_description_kwargs
|
||||
),
|
||||
ScreenLogicPushBinarySensor(coordinator, core_sensor_description)
|
||||
)
|
||||
|
||||
for p_index, p_data in gateway.get_data(DEVICE.PUMP).items():
|
||||
if not p_data or not p_data.get(VALUE.DATA):
|
||||
continue
|
||||
for proto_pump_sensor_description in SUPPORTED_PUMP_SENSORS:
|
||||
entities.append(
|
||||
ScreenLogicPumpBinarySensor(
|
||||
coordinator, copy(proto_pump_sensor_description), p_index
|
||||
)
|
||||
)
|
||||
else:
|
||||
|
||||
chem_sensor_description: ScreenLogicPushBinarySensorDescription
|
||||
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, DOMAIN, chem_sensor_data_path)
|
||||
continue
|
||||
if gateway.get_data(*chem_sensor_data_path):
|
||||
entities.append(
|
||||
ScreenLogicBinarySensor(
|
||||
coordinator,
|
||||
ScreenLogicBinarySensorDescription(**entity_description_kwargs),
|
||||
)
|
||||
ScreenLogicPushBinarySensor(coordinator, chem_sensor_description)
|
||||
)
|
||||
|
||||
scg_sensor_description: ScreenLogicBinarySensorDescription
|
||||
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, DOMAIN, scg_sensor_data_path)
|
||||
continue
|
||||
if gateway.get_data(*scg_sensor_data_path):
|
||||
entities.append(
|
||||
ScreenLogicBinarySensor(coordinator, scg_sensor_description)
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScreenLogicBinarySensorDescription(
|
||||
BinarySensorEntityDescription, ScreenLogicEntityDescription
|
||||
):
|
||||
"""A class that describes ScreenLogic binary sensor eneites."""
|
||||
|
||||
|
||||
class ScreenLogicBinarySensor(ScreenlogicEntity, BinarySensorEntity):
|
||||
"""Base class for all ScreenLogic binary sensor entities."""
|
||||
"""Representation of a ScreenLogic binary sensor entity."""
|
||||
|
||||
entity_description: ScreenLogicBinarySensorDescription
|
||||
_attr_has_entity_name = True
|
||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
@ -177,14 +245,21 @@ class ScreenLogicBinarySensor(ScreenlogicEntity, BinarySensorEntity):
|
||||
return self.entity_data[ATTR.VALUE] == ON_OFF.ON
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScreenLogicPushBinarySensorDescription(
|
||||
ScreenLogicBinarySensorDescription, ScreenLogicPushEntityDescription
|
||||
):
|
||||
"""Describes a ScreenLogicPushBinarySensor."""
|
||||
|
||||
|
||||
class ScreenLogicPushBinarySensor(ScreenLogicPushEntity, ScreenLogicBinarySensor):
|
||||
"""Representation of a basic ScreenLogic sensor entity."""
|
||||
"""Representation of a ScreenLogic push binary sensor entity."""
|
||||
|
||||
entity_description: ScreenLogicPushBinarySensorDescription
|
||||
|
||||
|
||||
class ScreenLogicPumpBinarySensor(ScreenLogicBinarySensor):
|
||||
"""Representation of a ScreenLogic binary sensor entity for pump data."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: ScreenlogicDataUpdateCoordinator,
|
||||
entity_description: ScreenLogicBinarySensorDescription,
|
||||
pump_index: int,
|
||||
) -> None:
|
||||
"""Initialize of the entity."""
|
||||
entity_description.data_root = (DEVICE.PUMP, pump_index)
|
||||
super().__init__(coordinator, entity_description)
|
||||
|
@ -53,16 +53,14 @@ async def async_setup_entry(
|
||||
|
||||
gateway = coordinator.gateway
|
||||
|
||||
for body_index, body_data in gateway.get_data(DEVICE.BODY).items():
|
||||
body_path = (DEVICE.BODY, body_index)
|
||||
for body_index in gateway.get_data(DEVICE.BODY):
|
||||
entities.append(
|
||||
ScreenLogicClimate(
|
||||
coordinator,
|
||||
ScreenLogicClimateDescription(
|
||||
subscription_code=CODE.STATUS_CHANGED,
|
||||
data_path=body_path,
|
||||
data_root=(DEVICE.BODY,),
|
||||
key=body_index,
|
||||
name=body_data[VALUE.HEAT_STATE][ATTR.NAME],
|
||||
),
|
||||
)
|
||||
)
|
||||
@ -99,6 +97,7 @@ class ScreenLogicClimate(ScreenLogicPushEntity, ClimateEntity, RestoreEntity):
|
||||
|
||||
self._attr_min_temp = self.entity_data[ATTR.MIN_SETPOINT]
|
||||
self._attr_max_temp = self.entity_data[ATTR.MAX_SETPOINT]
|
||||
self._attr_name = self.entity_data[VALUE.HEAT_STATE][ATTR.NAME]
|
||||
self._last_preset = None
|
||||
|
||||
@property
|
||||
|
@ -1,189 +1,5 @@
|
||||
"""Support for configurable supported data values for the ScreenLogic integration."""
|
||||
from collections.abc import Callable, Generator
|
||||
from dataclasses import dataclass
|
||||
from enum import StrEnum
|
||||
from typing import Any
|
||||
|
||||
from screenlogicpy import ScreenLogicGateway
|
||||
from screenlogicpy.const.data import ATTR, DEVICE, VALUE
|
||||
from screenlogicpy.const.msg import CODE
|
||||
from screenlogicpy.device_const.system import EQUIPMENT_FLAG
|
||||
|
||||
from homeassistant.const import EntityCategory
|
||||
|
||||
from .const import SL_UNIT_TO_HA_UNIT, ScreenLogicDataPath
|
||||
|
||||
|
||||
class PathPart(StrEnum):
|
||||
"""Placeholders for local data_path values."""
|
||||
|
||||
DEVICE = "!device"
|
||||
KEY = "!key"
|
||||
INDEX = "!index"
|
||||
VALUE = "!sensor"
|
||||
|
||||
|
||||
ScreenLogicDataPathTemplate = tuple[PathPart | str | int, ...]
|
||||
|
||||
|
||||
class ScreenLogicRule:
|
||||
"""Represents a base default passing rule."""
|
||||
|
||||
def __init__(
|
||||
self, test: Callable[..., bool] = lambda gateway, data_path: True
|
||||
) -> None:
|
||||
"""Initialize a ScreenLogic rule."""
|
||||
self._test = test
|
||||
|
||||
def test(self, gateway: ScreenLogicGateway, data_path: ScreenLogicDataPath) -> bool:
|
||||
"""Method to check the rule."""
|
||||
return self._test(gateway, data_path)
|
||||
|
||||
|
||||
class ScreenLogicDataRule(ScreenLogicRule):
|
||||
"""Represents a data rule."""
|
||||
|
||||
def __init__(
|
||||
self, test: Callable[..., bool], test_path_template: tuple[PathPart, ...]
|
||||
) -> None:
|
||||
"""Initialize a ScreenLogic data rule."""
|
||||
self._test_path_template = test_path_template
|
||||
super().__init__(test)
|
||||
|
||||
def test(self, gateway: ScreenLogicGateway, data_path: ScreenLogicDataPath) -> bool:
|
||||
"""Check the rule against the gateway's data."""
|
||||
test_path = realize_path_template(self._test_path_template, data_path)
|
||||
return self._test(gateway.get_data(*test_path))
|
||||
|
||||
|
||||
class ScreenLogicEquipmentRule(ScreenLogicRule):
|
||||
"""Represents an equipment flag rule."""
|
||||
|
||||
def test(self, gateway: ScreenLogicGateway, data_path: ScreenLogicDataPath) -> bool:
|
||||
"""Check the rule against the gateway's equipment flags."""
|
||||
return self._test(gateway.equipment_flags)
|
||||
|
||||
|
||||
@dataclass
|
||||
class SupportedValueParameters:
|
||||
"""Base supported values for ScreenLogic Entities."""
|
||||
|
||||
enabled: ScreenLogicRule = ScreenLogicRule()
|
||||
included: ScreenLogicRule = ScreenLogicRule()
|
||||
subscription_code: int | None = None
|
||||
entity_category: EntityCategory | None = EntityCategory.DIAGNOSTIC
|
||||
|
||||
|
||||
SupportedValueDescriptions = dict[str, SupportedValueParameters]
|
||||
|
||||
SupportedGroupDescriptions = dict[int | str, SupportedValueDescriptions]
|
||||
|
||||
SupportedDeviceDescriptions = dict[str, SupportedGroupDescriptions]
|
||||
|
||||
|
||||
DEVICE_INCLUSION_RULES = {
|
||||
DEVICE.PUMP: ScreenLogicDataRule(
|
||||
lambda pump_data: pump_data[VALUE.DATA] != 0,
|
||||
(PathPart.DEVICE, PathPart.INDEX),
|
||||
),
|
||||
DEVICE.INTELLICHEM: ScreenLogicEquipmentRule(
|
||||
lambda flags: EQUIPMENT_FLAG.INTELLICHEM in flags,
|
||||
),
|
||||
DEVICE.SCG: ScreenLogicEquipmentRule(
|
||||
lambda flags: EQUIPMENT_FLAG.CHLORINATOR in flags,
|
||||
),
|
||||
}
|
||||
|
||||
DEVICE_SUBSCRIPTION = {
|
||||
DEVICE.CONTROLLER: CODE.STATUS_CHANGED,
|
||||
DEVICE.INTELLICHEM: CODE.CHEMISTRY_CHANGED,
|
||||
}
|
||||
|
||||
|
||||
# not run-time
|
||||
def get_ha_unit(entity_data: dict) -> StrEnum | str | None:
|
||||
"""Return a Home Assistant unit of measurement from a UNIT."""
|
||||
sl_unit = entity_data.get(ATTR.UNIT)
|
||||
return SL_UNIT_TO_HA_UNIT.get(sl_unit, sl_unit)
|
||||
|
||||
|
||||
# partial run-time
|
||||
def realize_path_template(
|
||||
template_path: ScreenLogicDataPathTemplate, data_path: ScreenLogicDataPath
|
||||
) -> ScreenLogicDataPath:
|
||||
"""Create a new data path using a template and an existing data path.
|
||||
|
||||
Construct new ScreenLogicDataPath from data_path using
|
||||
template_path to specify values from data_path.
|
||||
"""
|
||||
if not data_path or len(data_path) < 3:
|
||||
raise KeyError(
|
||||
f"Missing or invalid required parameter: 'data_path' for template path '{template_path}'"
|
||||
)
|
||||
device, group, data_key = data_path
|
||||
realized_path: list[str | int] = []
|
||||
for part in template_path:
|
||||
match part:
|
||||
case PathPart.DEVICE:
|
||||
realized_path.append(device)
|
||||
case PathPart.INDEX | PathPart.KEY:
|
||||
realized_path.append(group)
|
||||
case PathPart.VALUE:
|
||||
realized_path.append(data_key)
|
||||
case _:
|
||||
realized_path.append(part)
|
||||
|
||||
return tuple(realized_path)
|
||||
|
||||
|
||||
def preprocess_supported_values(
|
||||
supported_devices: SupportedDeviceDescriptions,
|
||||
) -> list[tuple[ScreenLogicDataPath, Any]]:
|
||||
"""Expand config dict into list of ScreenLogicDataPaths and settings."""
|
||||
processed: list[tuple[ScreenLogicDataPath, Any]] = []
|
||||
for device, device_groups in supported_devices.items():
|
||||
for group, group_values in device_groups.items():
|
||||
for value_key, value_params in group_values.items():
|
||||
value_data_path = (device, group, value_key)
|
||||
processed.append((value_data_path, value_params))
|
||||
return processed
|
||||
|
||||
|
||||
def iterate_expand_group_wildcard(
|
||||
gateway: ScreenLogicGateway,
|
||||
preprocessed_data: list[tuple[ScreenLogicDataPath, Any]],
|
||||
) -> Generator[tuple[ScreenLogicDataPath, Any], None, None]:
|
||||
"""Iterate and expand any group wildcards to all available entries in gateway."""
|
||||
for data_path, value_params in preprocessed_data:
|
||||
device, group, value_key = data_path
|
||||
if group == "*":
|
||||
for index in gateway.get_data(device):
|
||||
yield ((device, index, value_key), value_params)
|
||||
else:
|
||||
yield (data_path, value_params)
|
||||
|
||||
|
||||
def build_base_entity_description(
|
||||
gateway: ScreenLogicGateway,
|
||||
entity_key: str,
|
||||
data_path: ScreenLogicDataPath,
|
||||
value_data: dict,
|
||||
value_params: SupportedValueParameters,
|
||||
) -> dict:
|
||||
"""Build base entity description.
|
||||
|
||||
Returns a dict of entity description key value pairs common to all entities.
|
||||
"""
|
||||
return {
|
||||
"data_path": data_path,
|
||||
"key": entity_key,
|
||||
"entity_category": value_params.entity_category,
|
||||
"entity_registry_enabled_default": value_params.enabled.test(
|
||||
gateway, data_path
|
||||
),
|
||||
"name": value_data.get(ATTR.NAME),
|
||||
}
|
||||
|
||||
from screenlogicpy.const.data import DEVICE, VALUE
|
||||
|
||||
ENTITY_MIGRATIONS = {
|
||||
"chem_alarm": {
|
||||
|
@ -1,4 +1,5 @@
|
||||
"""Base ScreenLogicEntity definitions."""
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
import logging
|
||||
@ -18,15 +19,16 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from .const import ScreenLogicDataPath
|
||||
from .coordinator import ScreenlogicDataUpdateCoordinator
|
||||
from .util import generate_unique_id
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScreenLogicEntityRequiredKeyMixin:
|
||||
"""Mixin for required ScreenLogic entity key."""
|
||||
"""Mixin for required ScreenLogic entity data_path."""
|
||||
|
||||
data_path: ScreenLogicDataPath
|
||||
data_root: ScreenLogicDataPath
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -35,6 +37,8 @@ class ScreenLogicEntityDescription(
|
||||
):
|
||||
"""Base class for a ScreenLogic entity description."""
|
||||
|
||||
enabled_lambda: Callable[..., bool] | None = None
|
||||
|
||||
|
||||
class ScreenlogicEntity(CoordinatorEntity[ScreenlogicDataUpdateCoordinator]):
|
||||
"""Base class for all ScreenLogic entities."""
|
||||
@ -50,10 +54,11 @@ class ScreenlogicEntity(CoordinatorEntity[ScreenlogicDataUpdateCoordinator]):
|
||||
"""Initialize of the entity."""
|
||||
super().__init__(coordinator)
|
||||
self.entity_description = entity_description
|
||||
self._data_path = self.entity_description.data_path
|
||||
self._data_key = self._data_path[-1]
|
||||
self._attr_unique_id = f"{self.mac}_{self.entity_description.key}"
|
||||
self._data_key = self.entity_description.key
|
||||
self._data_path = (*self.entity_description.data_root, self._data_key)
|
||||
mac = self.mac
|
||||
self._attr_unique_id = f"{mac}_{generate_unique_id(*self._data_path)}"
|
||||
self._attr_name = self.entity_data[ATTR.NAME]
|
||||
assert mac is not None
|
||||
self._attr_device_info = DeviceInfo(
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, mac)},
|
||||
@ -88,9 +93,10 @@ class ScreenlogicEntity(CoordinatorEntity[ScreenlogicDataUpdateCoordinator]):
|
||||
@property
|
||||
def entity_data(self) -> dict:
|
||||
"""Shortcut to the data for this entity."""
|
||||
if (data := self.gateway.get_data(*self._data_path)) is None:
|
||||
raise KeyError(f"Data not found: {self._data_path}")
|
||||
return data
|
||||
try:
|
||||
return self.gateway.get_data(*self._data_path, strict=True)
|
||||
except KeyError as ke:
|
||||
raise HomeAssistantError(f"Data not found: {self._data_path}") from ke
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -120,6 +126,7 @@ class ScreenLogicPushEntity(ScreenlogicEntity):
|
||||
) -> None:
|
||||
"""Initialize of the entity."""
|
||||
super().__init__(coordinator, entity_description)
|
||||
self._subscription_code = entity_description.subscription_code
|
||||
self._last_update_success = True
|
||||
|
||||
@callback
|
||||
@ -134,7 +141,7 @@ class ScreenLogicPushEntity(ScreenlogicEntity):
|
||||
self.async_on_remove(
|
||||
await self.gateway.async_subscribe_client(
|
||||
self._async_data_updated,
|
||||
self.entity_description.subscription_code,
|
||||
self._subscription_code,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -34,7 +34,11 @@ async def async_setup_entry(
|
||||
]
|
||||
gateway = coordinator.gateway
|
||||
for circuit_index, circuit_data in gateway.get_data(DEVICE.CIRCUIT).items():
|
||||
if circuit_data[ATTR.FUNCTION] not in LIGHT_CIRCUIT_FUNCTIONS:
|
||||
if (
|
||||
not circuit_data
|
||||
or ((circuit_function := circuit_data.get(ATTR.FUNCTION)) is None)
|
||||
or circuit_function not in LIGHT_CIRCUIT_FUNCTIONS
|
||||
):
|
||||
continue
|
||||
circuit_name = circuit_data[ATTR.NAME]
|
||||
circuit_interface = INTERFACE(circuit_data[ATTR.INTERFACE])
|
||||
@ -43,9 +47,8 @@ async def async_setup_entry(
|
||||
coordinator,
|
||||
ScreenLogicLightDescription(
|
||||
subscription_code=CODE.STATUS_CHANGED,
|
||||
data_path=(DEVICE.CIRCUIT, circuit_index),
|
||||
data_root=(DEVICE.CIRCUIT,),
|
||||
key=circuit_index,
|
||||
name=circuit_name,
|
||||
entity_registry_enabled_default=(
|
||||
circuit_name not in GENERIC_CIRCUIT_NAMES
|
||||
and circuit_interface != INTERFACE.DONT_SHOW
|
||||
|
@ -4,10 +4,10 @@ from dataclasses import dataclass
|
||||
import logging
|
||||
|
||||
from screenlogicpy.const.data import ATTR, DEVICE, GROUP, VALUE
|
||||
from screenlogicpy.device_const.system import EQUIPMENT_FLAG
|
||||
|
||||
from homeassistant.components.number import (
|
||||
DOMAIN,
|
||||
NumberDeviceClass,
|
||||
NumberEntity,
|
||||
NumberEntityDescription,
|
||||
)
|
||||
@ -16,20 +16,10 @@ from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN as SL_DOMAIN, ScreenLogicDataPath
|
||||
from .const import DOMAIN as SL_DOMAIN
|
||||
from .coordinator import ScreenlogicDataUpdateCoordinator
|
||||
from .data import (
|
||||
DEVICE_INCLUSION_RULES,
|
||||
PathPart,
|
||||
SupportedValueParameters,
|
||||
build_base_entity_description,
|
||||
get_ha_unit,
|
||||
iterate_expand_group_wildcard,
|
||||
preprocess_supported_values,
|
||||
realize_path_template,
|
||||
)
|
||||
from .entity import ScreenlogicEntity, ScreenLogicEntityDescription
|
||||
from .util import cleanup_excluded_entity, generate_unique_id
|
||||
from .util import cleanup_excluded_entity, get_ha_unit
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -37,47 +27,44 @@ PARALLEL_UPDATES = 1
|
||||
|
||||
|
||||
@dataclass
|
||||
class SupportedNumberValueParametersMixin:
|
||||
"""Mixin for supported predefined data for a ScreenLogic number entity."""
|
||||
class ScreenLogicNumberRequiredMixin:
|
||||
"""Describes a required mixin for a ScreenLogic number entity."""
|
||||
|
||||
set_value_config: tuple[str, tuple[tuple[PathPart | str | int, ...], ...]]
|
||||
device_class: NumberDeviceClass | None = None
|
||||
set_value_name: str
|
||||
set_value_args: tuple[tuple[str | int, ...], ...]
|
||||
|
||||
|
||||
@dataclass
|
||||
class SupportedNumberValueParameters(
|
||||
SupportedValueParameters, SupportedNumberValueParametersMixin
|
||||
class ScreenLogicNumberDescription(
|
||||
NumberEntityDescription,
|
||||
ScreenLogicEntityDescription,
|
||||
ScreenLogicNumberRequiredMixin,
|
||||
):
|
||||
"""Supported predefined data for a ScreenLogic number entity."""
|
||||
"""Describes a ScreenLogic number entity."""
|
||||
|
||||
|
||||
SET_SCG_CONFIG_FUNC_DATA = (
|
||||
"async_set_scg_config",
|
||||
(
|
||||
(DEVICE.SCG, GROUP.CONFIGURATION, VALUE.POOL_SETPOINT),
|
||||
(DEVICE.SCG, GROUP.CONFIGURATION, VALUE.SPA_SETPOINT),
|
||||
SUPPORTED_SCG_NUMBERS = [
|
||||
ScreenLogicNumberDescription(
|
||||
set_value_name="async_set_scg_config",
|
||||
set_value_args=(
|
||||
(DEVICE.SCG, GROUP.CONFIGURATION, VALUE.POOL_SETPOINT),
|
||||
(DEVICE.SCG, GROUP.CONFIGURATION, VALUE.SPA_SETPOINT),
|
||||
),
|
||||
data_root=(DEVICE.SCG, GROUP.CONFIGURATION),
|
||||
key=VALUE.POOL_SETPOINT,
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
SUPPORTED_DATA: list[
|
||||
tuple[ScreenLogicDataPath, SupportedValueParameters]
|
||||
] = preprocess_supported_values(
|
||||
{
|
||||
DEVICE.SCG: {
|
||||
GROUP.CONFIGURATION: {
|
||||
VALUE.POOL_SETPOINT: SupportedNumberValueParameters(
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
set_value_config=SET_SCG_CONFIG_FUNC_DATA,
|
||||
),
|
||||
VALUE.SPA_SETPOINT: SupportedNumberValueParameters(
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
set_value_config=SET_SCG_CONFIG_FUNC_DATA,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
ScreenLogicNumberDescription(
|
||||
set_value_name="async_set_scg_config",
|
||||
set_value_args=(
|
||||
(DEVICE.SCG, GROUP.CONFIGURATION, VALUE.POOL_SETPOINT),
|
||||
(DEVICE.SCG, GROUP.CONFIGURATION, VALUE.SPA_SETPOINT),
|
||||
),
|
||||
data_root=(DEVICE.SCG, GROUP.CONFIGURATION),
|
||||
key=VALUE.SPA_SETPOINT,
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
@ -91,70 +78,21 @@ async def async_setup_entry(
|
||||
config_entry.entry_id
|
||||
]
|
||||
gateway = coordinator.gateway
|
||||
data_path: ScreenLogicDataPath
|
||||
value_params: SupportedNumberValueParameters
|
||||
for data_path, value_params in iterate_expand_group_wildcard(
|
||||
gateway, SUPPORTED_DATA
|
||||
):
|
||||
entity_key = generate_unique_id(*data_path)
|
||||
|
||||
device = data_path[0]
|
||||
|
||||
if not (DEVICE_INCLUSION_RULES.get(device) or value_params.included).test(
|
||||
gateway, data_path
|
||||
):
|
||||
cleanup_excluded_entity(coordinator, DOMAIN, entity_key)
|
||||
continue
|
||||
|
||||
try:
|
||||
value_data = gateway.get_data(*data_path, strict=True)
|
||||
except KeyError:
|
||||
_LOGGER.debug("Failed to find %s", data_path)
|
||||
continue
|
||||
|
||||
set_value_str, set_value_params = value_params.set_value_config
|
||||
set_value_func = getattr(gateway, set_value_str)
|
||||
|
||||
entity_description_kwargs = {
|
||||
**build_base_entity_description(
|
||||
gateway, entity_key, data_path, value_data, value_params
|
||||
),
|
||||
"device_class": value_params.device_class,
|
||||
"native_unit_of_measurement": get_ha_unit(value_data),
|
||||
"native_max_value": value_data.get(ATTR.MAX_SETPOINT),
|
||||
"native_min_value": value_data.get(ATTR.MIN_SETPOINT),
|
||||
"native_step": value_data.get(ATTR.STEP),
|
||||
"set_value": set_value_func,
|
||||
"set_value_params": set_value_params,
|
||||
}
|
||||
|
||||
entities.append(
|
||||
ScreenLogicNumber(
|
||||
coordinator,
|
||||
ScreenLogicNumberDescription(**entity_description_kwargs),
|
||||
)
|
||||
for scg_number_description in SUPPORTED_SCG_NUMBERS:
|
||||
scg_number_data_path = (
|
||||
*scg_number_description.data_root,
|
||||
scg_number_description.key,
|
||||
)
|
||||
if EQUIPMENT_FLAG.CHLORINATOR not in gateway.equipment_flags:
|
||||
cleanup_excluded_entity(coordinator, DOMAIN, scg_number_data_path)
|
||||
continue
|
||||
if gateway.get_data(*scg_number_data_path):
|
||||
entities.append(ScreenLogicNumber(coordinator, scg_number_description))
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScreenLogicNumberRequiredMixin:
|
||||
"""Describes a required mixin for a ScreenLogic number entity."""
|
||||
|
||||
set_value: Callable[..., bool]
|
||||
set_value_params: tuple[tuple[str | int, ...], ...]
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScreenLogicNumberDescription(
|
||||
NumberEntityDescription,
|
||||
ScreenLogicEntityDescription,
|
||||
ScreenLogicNumberRequiredMixin,
|
||||
):
|
||||
"""Describes a ScreenLogic number entity."""
|
||||
|
||||
|
||||
class ScreenLogicNumber(ScreenlogicEntity, NumberEntity):
|
||||
"""Class to represent a ScreenLogic Number entity."""
|
||||
|
||||
@ -166,9 +104,30 @@ class ScreenLogicNumber(ScreenlogicEntity, NumberEntity):
|
||||
entity_description: ScreenLogicNumberDescription,
|
||||
) -> None:
|
||||
"""Initialize a ScreenLogic number entity."""
|
||||
self._set_value_func = entity_description.set_value
|
||||
self._set_value_params = entity_description.set_value_params
|
||||
super().__init__(coordinator, entity_description)
|
||||
if not callable(
|
||||
func := getattr(self.gateway, entity_description.set_value_name)
|
||||
):
|
||||
raise TypeError(
|
||||
f"set_value_name '{entity_description.set_value_name}' is not a callable"
|
||||
)
|
||||
self._set_value_func: Callable[..., bool] = func
|
||||
self._set_value_args = entity_description.set_value_args
|
||||
self._attr_native_unit_of_measurement = get_ha_unit(
|
||||
self.entity_data.get(ATTR.UNIT)
|
||||
)
|
||||
if entity_description.native_max_value is None and isinstance(
|
||||
max_val := self.entity_data.get(ATTR.MAX_SETPOINT), int | float
|
||||
):
|
||||
self._attr_native_max_value = max_val
|
||||
if entity_description.native_min_value is None and isinstance(
|
||||
min_val := self.entity_data.get(ATTR.MIN_SETPOINT), int | float
|
||||
):
|
||||
self._attr_native_min_value = min_val
|
||||
if entity_description.native_step is None and isinstance(
|
||||
step := self.entity_data.get(ATTR.STEP), int | float
|
||||
):
|
||||
self._attr_native_step = step
|
||||
|
||||
@property
|
||||
def native_value(self) -> float:
|
||||
@ -182,12 +141,9 @@ class ScreenLogicNumber(ScreenlogicEntity, NumberEntity):
|
||||
# gathers the existing values and updates the particular value being
|
||||
# set by this entity.
|
||||
args = {}
|
||||
for data_path in self._set_value_params:
|
||||
data_path = realize_path_template(data_path, self._data_path)
|
||||
data_value = data_path[-1]
|
||||
args[data_value] = self.coordinator.gateway.get_value(
|
||||
*data_path, strict=True
|
||||
)
|
||||
for data_path in self._set_value_args:
|
||||
data_key = data_path[-1]
|
||||
args[data_key] = self.coordinator.gateway.get_value(*data_path, strict=True)
|
||||
|
||||
args[self._data_key] = value
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
"""Support for a ScreenLogic Sensor."""
|
||||
from collections.abc import Callable
|
||||
from copy import copy
|
||||
from dataclasses import dataclass
|
||||
import logging
|
||||
|
||||
from screenlogicpy.const.common import DEVICE_TYPE, STATE_TYPE
|
||||
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
|
||||
@ -17,221 +18,23 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN as SL_DOMAIN, ScreenLogicDataPath
|
||||
from .const import DOMAIN as SL_DOMAIN
|
||||
from .coordinator import ScreenlogicDataUpdateCoordinator
|
||||
from .data import (
|
||||
DEVICE_INCLUSION_RULES,
|
||||
DEVICE_SUBSCRIPTION,
|
||||
PathPart,
|
||||
ScreenLogicDataRule,
|
||||
ScreenLogicEquipmentRule,
|
||||
SupportedValueParameters,
|
||||
build_base_entity_description,
|
||||
get_ha_unit,
|
||||
iterate_expand_group_wildcard,
|
||||
preprocess_supported_values,
|
||||
)
|
||||
from .entity import (
|
||||
ScreenlogicEntity,
|
||||
ScreenLogicEntityDescription,
|
||||
ScreenLogicPushEntity,
|
||||
ScreenLogicPushEntityDescription,
|
||||
)
|
||||
from .util import cleanup_excluded_entity, generate_unique_id
|
||||
from .util import cleanup_excluded_entity, get_ha_unit
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class SupportedSensorValueParameters(SupportedValueParameters):
|
||||
"""Supported predefined data for a ScreenLogic sensor entity."""
|
||||
|
||||
device_class: SensorDeviceClass | None = None
|
||||
value_modification: Callable[[int], int | str] | None = lambda val: val
|
||||
|
||||
|
||||
SUPPORTED_DATA: list[
|
||||
tuple[ScreenLogicDataPath, SupportedValueParameters]
|
||||
] = preprocess_supported_values(
|
||||
{
|
||||
DEVICE.CONTROLLER: {
|
||||
GROUP.SENSOR: {
|
||||
VALUE.AIR_TEMPERATURE: SupportedSensorValueParameters(
|
||||
device_class=SensorDeviceClass.TEMPERATURE, entity_category=None
|
||||
),
|
||||
VALUE.ORP: SupportedSensorValueParameters(
|
||||
included=ScreenLogicEquipmentRule(
|
||||
lambda flags: EQUIPMENT_FLAG.INTELLICHEM in flags
|
||||
)
|
||||
),
|
||||
VALUE.PH: SupportedSensorValueParameters(
|
||||
included=ScreenLogicEquipmentRule(
|
||||
lambda flags: EQUIPMENT_FLAG.INTELLICHEM in flags
|
||||
)
|
||||
),
|
||||
},
|
||||
},
|
||||
DEVICE.PUMP: {
|
||||
"*": {
|
||||
VALUE.WATTS_NOW: SupportedSensorValueParameters(),
|
||||
VALUE.GPM_NOW: SupportedSensorValueParameters(
|
||||
enabled=ScreenLogicDataRule(
|
||||
lambda pump_data: pump_data[VALUE.TYPE]
|
||||
!= PUMP_TYPE.INTELLIFLO_VS,
|
||||
(PathPart.DEVICE, PathPart.INDEX),
|
||||
)
|
||||
),
|
||||
VALUE.RPM_NOW: SupportedSensorValueParameters(
|
||||
enabled=ScreenLogicDataRule(
|
||||
lambda pump_data: pump_data[VALUE.TYPE]
|
||||
!= PUMP_TYPE.INTELLIFLO_VF,
|
||||
(PathPart.DEVICE, PathPart.INDEX),
|
||||
)
|
||||
),
|
||||
},
|
||||
},
|
||||
DEVICE.INTELLICHEM: {
|
||||
GROUP.SENSOR: {
|
||||
VALUE.ORP_NOW: SupportedSensorValueParameters(),
|
||||
VALUE.ORP_SUPPLY_LEVEL: SupportedSensorValueParameters(
|
||||
value_modification=lambda val: val - 1
|
||||
),
|
||||
VALUE.PH_NOW: SupportedSensorValueParameters(),
|
||||
VALUE.PH_PROBE_WATER_TEMP: SupportedSensorValueParameters(),
|
||||
VALUE.PH_SUPPLY_LEVEL: SupportedSensorValueParameters(
|
||||
value_modification=lambda val: val - 1
|
||||
),
|
||||
VALUE.SATURATION: SupportedSensorValueParameters(),
|
||||
},
|
||||
GROUP.CONFIGURATION: {
|
||||
VALUE.CALCIUM_HARNESS: SupportedSensorValueParameters(),
|
||||
VALUE.CYA: SupportedSensorValueParameters(),
|
||||
VALUE.ORP_SETPOINT: SupportedSensorValueParameters(),
|
||||
VALUE.PH_SETPOINT: SupportedSensorValueParameters(),
|
||||
VALUE.SALT_TDS_PPM: SupportedSensorValueParameters(
|
||||
included=ScreenLogicEquipmentRule(
|
||||
lambda flags: EQUIPMENT_FLAG.INTELLICHEM in flags
|
||||
and EQUIPMENT_FLAG.CHLORINATOR not in flags,
|
||||
)
|
||||
),
|
||||
VALUE.TOTAL_ALKALINITY: SupportedSensorValueParameters(),
|
||||
},
|
||||
GROUP.DOSE_STATUS: {
|
||||
VALUE.ORP_DOSING_STATE: SupportedSensorValueParameters(
|
||||
value_modification=lambda val: DOSE_STATE(val).title,
|
||||
),
|
||||
VALUE.ORP_LAST_DOSE_TIME: SupportedSensorValueParameters(),
|
||||
VALUE.ORP_LAST_DOSE_VOLUME: SupportedSensorValueParameters(),
|
||||
VALUE.PH_DOSING_STATE: SupportedSensorValueParameters(
|
||||
value_modification=lambda val: DOSE_STATE(val).title,
|
||||
),
|
||||
VALUE.PH_LAST_DOSE_TIME: SupportedSensorValueParameters(),
|
||||
VALUE.PH_LAST_DOSE_VOLUME: SupportedSensorValueParameters(),
|
||||
},
|
||||
},
|
||||
DEVICE.SCG: {
|
||||
GROUP.SENSOR: {
|
||||
VALUE.SALT_PPM: SupportedSensorValueParameters(),
|
||||
},
|
||||
GROUP.CONFIGURATION: {
|
||||
VALUE.SUPER_CHLOR_TIMER: SupportedSensorValueParameters(),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
SL_DEVICE_TYPE_TO_HA_DEVICE_CLASS = {
|
||||
DEVICE_TYPE.DURATION: SensorDeviceClass.DURATION,
|
||||
DEVICE_TYPE.ENUM: SensorDeviceClass.ENUM,
|
||||
DEVICE_TYPE.ENERGY: SensorDeviceClass.POWER,
|
||||
DEVICE_TYPE.POWER: SensorDeviceClass.POWER,
|
||||
DEVICE_TYPE.TEMPERATURE: SensorDeviceClass.TEMPERATURE,
|
||||
DEVICE_TYPE.VOLUME: SensorDeviceClass.VOLUME,
|
||||
}
|
||||
|
||||
SL_STATE_TYPE_TO_HA_STATE_CLASS = {
|
||||
STATE_TYPE.MEASUREMENT: SensorStateClass.MEASUREMENT,
|
||||
STATE_TYPE.TOTAL_INCREASING: SensorStateClass.TOTAL_INCREASING,
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up entry."""
|
||||
entities: list[ScreenLogicSensor] = []
|
||||
coordinator: ScreenlogicDataUpdateCoordinator = hass.data[SL_DOMAIN][
|
||||
config_entry.entry_id
|
||||
]
|
||||
gateway = coordinator.gateway
|
||||
data_path: ScreenLogicDataPath
|
||||
value_params: SupportedSensorValueParameters
|
||||
for data_path, value_params in iterate_expand_group_wildcard(
|
||||
gateway, SUPPORTED_DATA
|
||||
):
|
||||
entity_key = generate_unique_id(*data_path)
|
||||
|
||||
device = data_path[0]
|
||||
|
||||
if not (DEVICE_INCLUSION_RULES.get(device) or value_params.included).test(
|
||||
gateway, data_path
|
||||
):
|
||||
cleanup_excluded_entity(coordinator, DOMAIN, entity_key)
|
||||
continue
|
||||
|
||||
try:
|
||||
value_data = gateway.get_data(*data_path, strict=True)
|
||||
except KeyError:
|
||||
_LOGGER.debug("Failed to find %s", data_path)
|
||||
continue
|
||||
|
||||
entity_description_kwargs = {
|
||||
**build_base_entity_description(
|
||||
gateway, entity_key, data_path, value_data, value_params
|
||||
),
|
||||
"device_class": SL_DEVICE_TYPE_TO_HA_DEVICE_CLASS.get(
|
||||
value_data.get(ATTR.DEVICE_TYPE)
|
||||
),
|
||||
"native_unit_of_measurement": get_ha_unit(value_data),
|
||||
"options": value_data.get(ATTR.ENUM_OPTIONS),
|
||||
"state_class": SL_STATE_TYPE_TO_HA_STATE_CLASS.get(
|
||||
value_data.get(ATTR.STATE_TYPE)
|
||||
),
|
||||
"value_mod": value_params.value_modification,
|
||||
}
|
||||
|
||||
if (
|
||||
sub_code := (
|
||||
value_params.subscription_code or DEVICE_SUBSCRIPTION.get(device)
|
||||
)
|
||||
) is not None:
|
||||
entities.append(
|
||||
ScreenLogicPushSensor(
|
||||
coordinator,
|
||||
ScreenLogicPushSensorDescription(
|
||||
subscription_code=sub_code,
|
||||
**entity_description_kwargs,
|
||||
),
|
||||
)
|
||||
)
|
||||
else:
|
||||
entities.append(
|
||||
ScreenLogicSensor(
|
||||
coordinator,
|
||||
ScreenLogicSensorDescription(
|
||||
**entity_description_kwargs,
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScreenLogicSensorMixin:
|
||||
"""Mixin for SecreenLogic sensor entity."""
|
||||
@ -246,12 +49,265 @@ class ScreenLogicSensorDescription(
|
||||
"""Describes a ScreenLogic sensor."""
|
||||
|
||||
|
||||
@dataclass
|
||||
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_HARNESS,
|
||||
),
|
||||
ScreenLogicPushSensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.CONFIGURATION),
|
||||
key=VALUE.CYA,
|
||||
),
|
||||
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,
|
||||
),
|
||||
ScreenLogicPushSensorDescription(
|
||||
subscription_code=CODE.CHEMISTRY_CHANGED,
|
||||
data_root=(DEVICE.INTELLICHEM, GROUP.CONFIGURATION),
|
||||
key=VALUE.SALT_TDS_PPM,
|
||||
),
|
||||
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: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up entry."""
|
||||
entities: list[ScreenLogicSensor] = []
|
||||
coordinator: ScreenlogicDataUpdateCoordinator = hass.data[SL_DOMAIN][
|
||||
config_entry.entry_id
|
||||
]
|
||||
gateway = coordinator.gateway
|
||||
|
||||
for core_sensor_description in SUPPORTED_CORE_SENSORS:
|
||||
if (
|
||||
gateway.get_data(
|
||||
*core_sensor_description.data_root, core_sensor_description.key
|
||||
)
|
||||
is not None
|
||||
):
|
||||
entities.append(ScreenLogicPushSensor(coordinator, core_sensor_description))
|
||||
|
||||
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, DOMAIN, chem_sensor_data_path)
|
||||
continue
|
||||
if gateway.get_data(*chem_sensor_data_path):
|
||||
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, DOMAIN, scg_sensor_data_path)
|
||||
continue
|
||||
if gateway.get_data(*scg_sensor_data_path):
|
||||
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."""
|
||||
@ -260,14 +316,29 @@ class ScreenLogicSensor(ScreenlogicEntity, SensorEntity):
|
||||
return value_mod(val) if value_mod else val
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScreenLogicPushSensorDescription(
|
||||
ScreenLogicSensorDescription, ScreenLogicPushEntityDescription
|
||||
):
|
||||
"""Describes a ScreenLogic push sensor."""
|
||||
|
||||
|
||||
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.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)
|
||||
)
|
||||
|
@ -30,7 +30,11 @@ async def async_setup_entry(
|
||||
]
|
||||
gateway = coordinator.gateway
|
||||
for circuit_index, circuit_data in gateway.get_data(DEVICE.CIRCUIT).items():
|
||||
if circuit_data[ATTR.FUNCTION] in LIGHT_CIRCUIT_FUNCTIONS:
|
||||
if (
|
||||
not circuit_data
|
||||
or ((circuit_function := circuit_data.get(ATTR.FUNCTION)) is None)
|
||||
or circuit_function in LIGHT_CIRCUIT_FUNCTIONS
|
||||
):
|
||||
continue
|
||||
circuit_name = circuit_data[ATTR.NAME]
|
||||
circuit_interface = INTERFACE(circuit_data[ATTR.INTERFACE])
|
||||
@ -39,9 +43,8 @@ async def async_setup_entry(
|
||||
coordinator,
|
||||
ScreenLogicSwitchDescription(
|
||||
subscription_code=CODE.STATUS_CHANGED,
|
||||
data_path=(DEVICE.CIRCUIT, circuit_index),
|
||||
data_root=(DEVICE.CIRCUIT,),
|
||||
key=circuit_index,
|
||||
name=circuit_name,
|
||||
entity_registry_enabled_default=(
|
||||
circuit_name not in GENERIC_CIRCUIT_NAMES
|
||||
and circuit_interface != INTERFACE.DONT_SHOW
|
||||
|
@ -5,32 +5,40 @@ from screenlogicpy.const.data import SHARED_VALUES
|
||||
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from .const import DOMAIN as SL_DOMAIN
|
||||
from .const import DOMAIN as SL_DOMAIN, SL_UNIT_TO_HA_UNIT, ScreenLogicDataPath
|
||||
from .coordinator import ScreenlogicDataUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def generate_unique_id(
|
||||
device: str | int, group: str | int | None, data_key: str | int
|
||||
) -> str:
|
||||
def generate_unique_id(*args: str | int | None) -> str:
|
||||
"""Generate new unique_id for a screenlogic entity from specified parameters."""
|
||||
if data_key in SHARED_VALUES and device is not None:
|
||||
if group is not None and (isinstance(group, int) or group.isdigit()):
|
||||
return f"{device}_{group}_{data_key}"
|
||||
return f"{device}_{data_key}"
|
||||
return str(data_key)
|
||||
_LOGGER.debug("gen_uid called with %s", args)
|
||||
if len(args) == 3:
|
||||
if args[2] in SHARED_VALUES:
|
||||
if args[1] is not None and (isinstance(args[1], int) or args[1].isdigit()):
|
||||
return f"{args[0]}_{args[1]}_{args[2]}"
|
||||
return f"{args[0]}_{args[2]}"
|
||||
return f"{args[2]}"
|
||||
return f"{args[1]}"
|
||||
|
||||
|
||||
def get_ha_unit(sl_unit) -> str:
|
||||
"""Return equivalent Home Assistant unit of measurement if exists."""
|
||||
if (ha_unit := SL_UNIT_TO_HA_UNIT.get(sl_unit)) is not None:
|
||||
return ha_unit
|
||||
return sl_unit
|
||||
|
||||
|
||||
def cleanup_excluded_entity(
|
||||
coordinator: ScreenlogicDataUpdateCoordinator,
|
||||
platform_domain: str,
|
||||
entity_key: str,
|
||||
data_path: ScreenLogicDataPath,
|
||||
) -> None:
|
||||
"""Remove excluded entity if it exists."""
|
||||
assert coordinator.config_entry
|
||||
entity_registry = er.async_get(coordinator.hass)
|
||||
unique_id = f"{coordinator.config_entry.unique_id}_{entity_key}"
|
||||
unique_id = f"{coordinator.config_entry.unique_id}_{generate_unique_id(*data_path)}"
|
||||
if entity_id := entity_registry.async_get_entity_id(
|
||||
platform_domain, SL_DOMAIN, unique_id
|
||||
):
|
||||
|
@ -35,12 +35,21 @@ def num_key_string_to_int(data: dict) -> None:
|
||||
DATA_FULL_CHEM = num_key_string_to_int(
|
||||
load_json_object_fixture("screenlogic/data_full_chem.json")
|
||||
)
|
||||
DATA_FULL_NO_GPM = num_key_string_to_int(
|
||||
load_json_object_fixture("screenlogic/data_full_no_gpm.json")
|
||||
)
|
||||
DATA_FULL_NO_SALT_PPM = num_key_string_to_int(
|
||||
load_json_object_fixture("screenlogic/data_full_no_salt_ppm.json")
|
||||
)
|
||||
DATA_MIN_MIGRATION = num_key_string_to_int(
|
||||
load_json_object_fixture("screenlogic/data_min_migration.json")
|
||||
)
|
||||
DATA_MIN_ENTITY_CLEANUP = num_key_string_to_int(
|
||||
load_json_object_fixture("screenlogic/data_min_entity_cleanup.json")
|
||||
)
|
||||
DATA_MISSING_VALUES_CHEM_CHLOR = num_key_string_to_int(
|
||||
load_json_object_fixture("screenlogic/data_missing_values_chem_chlor.json")
|
||||
)
|
||||
|
||||
|
||||
async def stub_async_connect(
|
||||
|
784
tests/components/screenlogic/fixtures/data_full_no_gpm.json
Normal file
784
tests/components/screenlogic/fixtures/data_full_no_gpm.json
Normal file
@ -0,0 +1,784 @@
|
||||
{
|
||||
"adapter": {
|
||||
"firmware": {
|
||||
"name": "Protocol Adapter Firmware",
|
||||
"value": "POOL: 5.2 Build 738.0 Rel"
|
||||
}
|
||||
},
|
||||
"controller": {
|
||||
"controller_id": 100,
|
||||
"configuration": {
|
||||
"body_type": {
|
||||
"0": {
|
||||
"min_setpoint": 40,
|
||||
"max_setpoint": 104
|
||||
},
|
||||
"1": {
|
||||
"min_setpoint": 40,
|
||||
"max_setpoint": 104
|
||||
}
|
||||
},
|
||||
"is_celsius": {
|
||||
"name": "Is Celsius",
|
||||
"value": 0
|
||||
},
|
||||
"controller_type": 1,
|
||||
"hardware_type": 0,
|
||||
"controller_data": 0,
|
||||
"generic_circuit_name": "Water Features",
|
||||
"circuit_count": 7,
|
||||
"color_count": 8,
|
||||
"color": [
|
||||
{
|
||||
"name": "White",
|
||||
"value": [255, 255, 255]
|
||||
},
|
||||
{
|
||||
"name": "Light Green",
|
||||
"value": [160, 255, 160]
|
||||
},
|
||||
{
|
||||
"name": "Green",
|
||||
"value": [0, 255, 80]
|
||||
},
|
||||
{
|
||||
"name": "Cyan",
|
||||
"value": [0, 255, 200]
|
||||
},
|
||||
{
|
||||
"name": "Blue",
|
||||
"value": [100, 140, 255]
|
||||
},
|
||||
{
|
||||
"name": "Lavender",
|
||||
"value": [230, 130, 255]
|
||||
},
|
||||
{
|
||||
"name": "Magenta",
|
||||
"value": [255, 0, 128]
|
||||
},
|
||||
{
|
||||
"name": "Light Magenta",
|
||||
"value": [255, 180, 210]
|
||||
}
|
||||
],
|
||||
"interface_tab_flags": 127,
|
||||
"show_alarms": 1,
|
||||
"remotes": 0,
|
||||
"unknown_at_offset_09": 0,
|
||||
"unknown_at_offset_10": 0,
|
||||
"unknown_at_offset_11": 0
|
||||
},
|
||||
"model": {
|
||||
"name": "Model",
|
||||
"value": "IntelliTouch i7+3"
|
||||
},
|
||||
"equipment": {
|
||||
"flags": 56,
|
||||
"list": ["INTELLIBRITE", "INTELLIFLO_0", "INTELLIFLO_1"]
|
||||
},
|
||||
"sensor": {
|
||||
"state": {
|
||||
"name": "Controller State",
|
||||
"value": 1,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Unknown", "Ready", "Sync", "Service"]
|
||||
},
|
||||
"freeze_mode": {
|
||||
"name": "Freeze Mode",
|
||||
"value": 0
|
||||
},
|
||||
"pool_delay": {
|
||||
"name": "Pool Delay",
|
||||
"value": 0
|
||||
},
|
||||
"spa_delay": {
|
||||
"name": "Spa Delay",
|
||||
"value": 0
|
||||
},
|
||||
"cleaner_delay": {
|
||||
"name": "Cleaner Delay",
|
||||
"value": 0
|
||||
},
|
||||
"air_temperature": {
|
||||
"name": "Air Temperature",
|
||||
"value": 91,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"ph": {
|
||||
"name": "pH",
|
||||
"value": 0.0,
|
||||
"unit": "pH",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"orp": {
|
||||
"name": "ORP",
|
||||
"value": 0,
|
||||
"unit": "mV",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"saturation": {
|
||||
"name": "Saturation Index",
|
||||
"value": 0.0,
|
||||
"unit": "lsi",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"salt_ppm": {
|
||||
"name": "Salt",
|
||||
"value": 0,
|
||||
"unit": "ppm",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"ph_supply_level": {
|
||||
"name": "pH Supply Level",
|
||||
"value": 0,
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"orp_supply_level": {
|
||||
"name": "ORP Supply Level",
|
||||
"value": 0,
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"active_alert": {
|
||||
"name": "Active Alert",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
}
|
||||
}
|
||||
},
|
||||
"circuit": {
|
||||
"500": {
|
||||
"circuit_id": 500,
|
||||
"name": "Spa",
|
||||
"configuration": {
|
||||
"name_index": 71,
|
||||
"flags": 1,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_62": 0,
|
||||
"unknown_at_offset_63": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 1,
|
||||
"interface": 1,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 1,
|
||||
"value": 0
|
||||
},
|
||||
"501": {
|
||||
"circuit_id": 501,
|
||||
"name": "Cleaner",
|
||||
"configuration": {
|
||||
"name_index": 21,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_90": 0,
|
||||
"unknown_at_offset_91": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 5,
|
||||
"interface": 5,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 2,
|
||||
"value": 0
|
||||
},
|
||||
"502": {
|
||||
"circuit_id": 502,
|
||||
"name": "Jets",
|
||||
"configuration": {
|
||||
"name_index": 45,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_114": 0,
|
||||
"unknown_at_offset_115": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 0,
|
||||
"interface": 5,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 3,
|
||||
"value": 0
|
||||
},
|
||||
"503": {
|
||||
"circuit_id": 503,
|
||||
"name": "Pool Light",
|
||||
"configuration": {
|
||||
"name_index": 62,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_146": 0,
|
||||
"unknown_at_offset_147": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 16,
|
||||
"interface": 3,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 10
|
||||
},
|
||||
"device_id": 4,
|
||||
"value": 0
|
||||
},
|
||||
"504": {
|
||||
"circuit_id": 504,
|
||||
"name": "Spa Light",
|
||||
"configuration": {
|
||||
"name_index": 73,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_178": 0,
|
||||
"unknown_at_offset_179": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 16,
|
||||
"interface": 3,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 1,
|
||||
"color_stagger": 10
|
||||
},
|
||||
"device_id": 5,
|
||||
"value": 0
|
||||
},
|
||||
"505": {
|
||||
"circuit_id": 505,
|
||||
"name": "Pool",
|
||||
"configuration": {
|
||||
"name_index": 60,
|
||||
"flags": 1,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_202": 0,
|
||||
"unknown_at_offset_203": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 2,
|
||||
"interface": 0,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 6,
|
||||
"value": 1
|
||||
},
|
||||
"506": {
|
||||
"circuit_id": 506,
|
||||
"name": "Air Blower",
|
||||
"configuration": {
|
||||
"name_index": 1,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_234": 0,
|
||||
"unknown_at_offset_235": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 0,
|
||||
"interface": 5,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 7,
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
"pump": {
|
||||
"0": {
|
||||
"data": 134,
|
||||
"type": 2,
|
||||
"state": {
|
||||
"name": "Pool Pump",
|
||||
"value": 1
|
||||
},
|
||||
"watts_now": {
|
||||
"name": "Pool Pump Watts Now",
|
||||
"value": 63,
|
||||
"unit": "W",
|
||||
"device_type": "power",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"rpm_now": {
|
||||
"name": "Pool Pump RPM Now",
|
||||
"value": 1050,
|
||||
"unit": "rpm",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"unknown_at_offset_16": 0,
|
||||
"unknown_at_offset_24": 255,
|
||||
"preset": {
|
||||
"0": {
|
||||
"device_id": 6,
|
||||
"setpoint": 1050,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"1": {
|
||||
"device_id": 1,
|
||||
"setpoint": 1850,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"2": {
|
||||
"device_id": 2,
|
||||
"setpoint": 1500,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"3": {
|
||||
"device_id": 0,
|
||||
"setpoint": 1000,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"4": {
|
||||
"device_id": 0,
|
||||
"setpoint": 1000,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"5": {
|
||||
"device_id": 0,
|
||||
"setpoint": 1000,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"6": {
|
||||
"device_id": 0,
|
||||
"setpoint": 1000,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"7": {
|
||||
"device_id": 0,
|
||||
"setpoint": 1000,
|
||||
"is_rpm": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"1": {
|
||||
"data": 131,
|
||||
"type": 2,
|
||||
"state": {
|
||||
"name": "Jets Pump",
|
||||
"value": 0
|
||||
},
|
||||
"watts_now": {
|
||||
"name": "Jets Pump Watts Now",
|
||||
"value": 0,
|
||||
"unit": "W",
|
||||
"device_type": "power",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"rpm_now": {
|
||||
"name": "Jets Pump RPM Now",
|
||||
"value": 0,
|
||||
"unit": "rpm",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"unknown_at_offset_16": 0,
|
||||
"gpm_now": {
|
||||
"name": "Jets Pump GPM Now",
|
||||
"value": 0,
|
||||
"unit": "gpm",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"unknown_at_offset_24": 255,
|
||||
"preset": {
|
||||
"0": {
|
||||
"device_id": 3,
|
||||
"setpoint": 2970,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"1": {
|
||||
"device_id": 0,
|
||||
"setpoint": 1000,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"2": {
|
||||
"device_id": 0,
|
||||
"setpoint": 1000,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"3": {
|
||||
"device_id": 0,
|
||||
"setpoint": 1000,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"4": {
|
||||
"device_id": 0,
|
||||
"setpoint": 1000,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"5": {
|
||||
"device_id": 0,
|
||||
"setpoint": 1000,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"6": {
|
||||
"device_id": 0,
|
||||
"setpoint": 1000,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"7": {
|
||||
"device_id": 0,
|
||||
"setpoint": 1000,
|
||||
"is_rpm": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"2": {
|
||||
"data": 0
|
||||
},
|
||||
"3": {
|
||||
"data": 0
|
||||
},
|
||||
"4": {
|
||||
"data": 0
|
||||
},
|
||||
"5": {
|
||||
"data": 0
|
||||
},
|
||||
"6": {
|
||||
"data": 0
|
||||
},
|
||||
"7": {
|
||||
"data": 0
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"0": {
|
||||
"body_type": 0,
|
||||
"min_setpoint": 40,
|
||||
"max_setpoint": 104,
|
||||
"name": "Pool",
|
||||
"last_temperature": {
|
||||
"name": "Last Pool Temperature",
|
||||
"value": 86,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"heat_state": {
|
||||
"name": "Pool Heat",
|
||||
"value": 0,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Off", "Solar", "Heater", "Both"]
|
||||
},
|
||||
"heat_setpoint": {
|
||||
"name": "Pool Heat Set Point",
|
||||
"value": 85,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature"
|
||||
},
|
||||
"cool_setpoint": {
|
||||
"name": "Pool Cool Set Point",
|
||||
"value": 100,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature"
|
||||
},
|
||||
"heat_mode": {
|
||||
"name": "Pool Heat Mode",
|
||||
"value": 0,
|
||||
"device_type": "enum",
|
||||
"enum_options": [
|
||||
"Off",
|
||||
"Solar",
|
||||
"Solar Preferred",
|
||||
"Heater",
|
||||
"Don't Change"
|
||||
]
|
||||
}
|
||||
},
|
||||
"1": {
|
||||
"body_type": 1,
|
||||
"min_setpoint": 40,
|
||||
"max_setpoint": 104,
|
||||
"name": "Spa",
|
||||
"last_temperature": {
|
||||
"name": "Last Spa Temperature",
|
||||
"value": 84,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"heat_state": {
|
||||
"name": "Spa Heat",
|
||||
"value": 0,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Off", "Solar", "Heater", "Both"]
|
||||
},
|
||||
"heat_setpoint": {
|
||||
"name": "Spa Heat Set Point",
|
||||
"value": 102,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature"
|
||||
},
|
||||
"cool_setpoint": {
|
||||
"name": "Spa Cool Set Point",
|
||||
"value": 91,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature"
|
||||
},
|
||||
"heat_mode": {
|
||||
"name": "Spa Heat Mode",
|
||||
"value": 3,
|
||||
"device_type": "enum",
|
||||
"enum_options": [
|
||||
"Off",
|
||||
"Solar",
|
||||
"Solar Preferred",
|
||||
"Heater",
|
||||
"Don't Change"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"intellichem": {
|
||||
"unknown_at_offset_00": 42,
|
||||
"unknown_at_offset_04": 0,
|
||||
"sensor": {
|
||||
"ph_now": {
|
||||
"name": "pH Now",
|
||||
"value": 0.0,
|
||||
"unit": "pH",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"orp_now": {
|
||||
"name": "ORP Now",
|
||||
"value": 0,
|
||||
"unit": "mV",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"ph_supply_level": {
|
||||
"name": "pH Supply Level",
|
||||
"value": 0,
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"orp_supply_level": {
|
||||
"name": "ORP Supply Level",
|
||||
"value": 0,
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"saturation": {
|
||||
"name": "Saturation Index",
|
||||
"value": 0.0,
|
||||
"unit": "lsi",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"ph_probe_water_temp": {
|
||||
"name": "pH Probe Water Temperature",
|
||||
"value": 0,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature",
|
||||
"state_type": "measurement"
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"ph_setpoint": {
|
||||
"name": "pH Setpoint",
|
||||
"value": 0.0,
|
||||
"unit": "pH"
|
||||
},
|
||||
"orp_setpoint": {
|
||||
"name": "ORP Setpoint",
|
||||
"value": 0,
|
||||
"unit": "mV"
|
||||
},
|
||||
"calcium_harness": {
|
||||
"name": "Calcium Hardness",
|
||||
"value": 0,
|
||||
"unit": "ppm"
|
||||
},
|
||||
"cya": {
|
||||
"name": "Cyanuric Acid",
|
||||
"value": 0,
|
||||
"unit": "ppm"
|
||||
},
|
||||
"total_alkalinity": {
|
||||
"name": "Total Alkalinity",
|
||||
"value": 0,
|
||||
"unit": "ppm"
|
||||
},
|
||||
"salt_tds_ppm": {
|
||||
"name": "Salt/TDS",
|
||||
"value": 0,
|
||||
"unit": "ppm"
|
||||
},
|
||||
"probe_is_celsius": 0,
|
||||
"flags": 0
|
||||
},
|
||||
"dose_status": {
|
||||
"ph_last_dose_time": {
|
||||
"name": "Last pH Dose Time",
|
||||
"value": 0,
|
||||
"unit": "sec",
|
||||
"device_type": "duration",
|
||||
"state_type": "total_increasing"
|
||||
},
|
||||
"orp_last_dose_time": {
|
||||
"name": "Last ORP Dose Time",
|
||||
"value": 0,
|
||||
"unit": "sec",
|
||||
"device_type": "duration",
|
||||
"state_type": "total_increasing"
|
||||
},
|
||||
"ph_last_dose_volume": {
|
||||
"name": "Last pH Dose Volume",
|
||||
"value": 0,
|
||||
"unit": "mL",
|
||||
"device_type": "volume",
|
||||
"state_type": "total_increasing"
|
||||
},
|
||||
"orp_last_dose_volume": {
|
||||
"name": "Last ORP Dose Volume",
|
||||
"value": 0,
|
||||
"unit": "mL",
|
||||
"device_type": "volume",
|
||||
"state_type": "total_increasing"
|
||||
},
|
||||
"flags": 0,
|
||||
"ph_dosing_state": {
|
||||
"name": "pH Dosing State",
|
||||
"value": 0,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Dosing", "Mixing", "Monitoring"]
|
||||
},
|
||||
"orp_dosing_state": {
|
||||
"name": "ORP Dosing State",
|
||||
"value": 0,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Dosing", "Mixing", "Monitoring"]
|
||||
}
|
||||
},
|
||||
"alarm": {
|
||||
"flags": 0,
|
||||
"flow_alarm": {
|
||||
"name": "Flow Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"ph_high_alarm": {
|
||||
"name": "pH HIGH Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"ph_low_alarm": {
|
||||
"name": "pH LOW Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"orp_high_alarm": {
|
||||
"name": "ORP HIGH Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"orp_low_alarm": {
|
||||
"name": "ORP LOW Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"ph_supply_alarm": {
|
||||
"name": "pH Supply Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"orp_supply_alarm": {
|
||||
"name": "ORP Supply Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"probe_fault_alarm": {
|
||||
"name": "Probe Fault",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
}
|
||||
},
|
||||
"alert": {
|
||||
"flags": 0,
|
||||
"ph_lockout": {
|
||||
"name": "pH Lockout",
|
||||
"value": 0
|
||||
},
|
||||
"ph_limit": {
|
||||
"name": "pH Dose Limit Reached",
|
||||
"value": 0
|
||||
},
|
||||
"orp_limit": {
|
||||
"name": "ORP Dose Limit Reached",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
"firmware": {
|
||||
"name": "IntelliChem Firmware",
|
||||
"value": "0.000"
|
||||
},
|
||||
"water_balance": {
|
||||
"flags": 0,
|
||||
"corrosive": {
|
||||
"name": "SI Corrosive",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"scaling": {
|
||||
"name": "SI Scaling",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
}
|
||||
},
|
||||
"unknown_at_offset_44": 0,
|
||||
"unknown_at_offset_45": 0,
|
||||
"unknown_at_offset_46": 0
|
||||
},
|
||||
"scg": {
|
||||
"scg_present": 0,
|
||||
"sensor": {
|
||||
"state": {
|
||||
"name": "Chlorinator",
|
||||
"value": 1
|
||||
},
|
||||
"salt_ppm": {
|
||||
"name": "Chlorinator Salt",
|
||||
"value": 0,
|
||||
"unit": "ppm",
|
||||
"state_type": "measurement"
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"pool_setpoint": {
|
||||
"name": "Pool Chlorinator Setpoint",
|
||||
"value": 50,
|
||||
"unit": "%",
|
||||
"min_setpoint": 0,
|
||||
"max_setpoint": 100,
|
||||
"step": 5,
|
||||
"body_type": 0
|
||||
},
|
||||
"spa_setpoint": {
|
||||
"name": "Spa Chlorinator Setpoint",
|
||||
"value": 0,
|
||||
"unit": "%",
|
||||
"min_setpoint": 0,
|
||||
"max_setpoint": 100,
|
||||
"step": 5,
|
||||
"body_type": 1
|
||||
},
|
||||
"super_chlor_timer": {
|
||||
"name": "Super Chlorination Timer",
|
||||
"value": 0,
|
||||
"unit": "hr",
|
||||
"min_setpoint": 1,
|
||||
"max_setpoint": 72,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"flags": 0
|
||||
}
|
||||
}
|
859
tests/components/screenlogic/fixtures/data_full_no_salt_ppm.json
Normal file
859
tests/components/screenlogic/fixtures/data_full_no_salt_ppm.json
Normal file
@ -0,0 +1,859 @@
|
||||
{
|
||||
"adapter": {
|
||||
"firmware": {
|
||||
"name": "Protocol Adapter Firmware",
|
||||
"value": "POOL: 5.2 Build 736.0 Rel"
|
||||
}
|
||||
},
|
||||
"controller": {
|
||||
"controller_id": 100,
|
||||
"configuration": {
|
||||
"body_type": {
|
||||
"0": {
|
||||
"min_setpoint": 40,
|
||||
"max_setpoint": 104
|
||||
},
|
||||
"1": {
|
||||
"min_setpoint": 40,
|
||||
"max_setpoint": 104
|
||||
}
|
||||
},
|
||||
"is_celsius": {
|
||||
"name": "Is Celsius",
|
||||
"value": 0
|
||||
},
|
||||
"controller_type": 13,
|
||||
"hardware_type": 0,
|
||||
"controller_data": 0,
|
||||
"generic_circuit_name": "Water Features",
|
||||
"circuit_count": 11,
|
||||
"color_count": 8,
|
||||
"color": [
|
||||
{
|
||||
"name": "White",
|
||||
"value": [255, 255, 255]
|
||||
},
|
||||
{
|
||||
"name": "Light Green",
|
||||
"value": [160, 255, 160]
|
||||
},
|
||||
{
|
||||
"name": "Green",
|
||||
"value": [0, 255, 80]
|
||||
},
|
||||
{
|
||||
"name": "Cyan",
|
||||
"value": [0, 255, 200]
|
||||
},
|
||||
{
|
||||
"name": "Blue",
|
||||
"value": [100, 140, 255]
|
||||
},
|
||||
{
|
||||
"name": "Lavender",
|
||||
"value": [230, 130, 255]
|
||||
},
|
||||
{
|
||||
"name": "Magenta",
|
||||
"value": [255, 0, 128]
|
||||
},
|
||||
{
|
||||
"name": "Light Magenta",
|
||||
"value": [255, 180, 210]
|
||||
}
|
||||
],
|
||||
"interface_tab_flags": 127,
|
||||
"show_alarms": 0,
|
||||
"remotes": 0,
|
||||
"unknown_at_offset_09": 0,
|
||||
"unknown_at_offset_10": 0,
|
||||
"unknown_at_offset_11": 0
|
||||
},
|
||||
"model": {
|
||||
"name": "Model",
|
||||
"value": "EasyTouch2 8"
|
||||
},
|
||||
"equipment": {
|
||||
"flags": 60,
|
||||
"list": ["CHLORINATOR", "INTELLIBRITE", "INTELLIFLO_0", "INTELLIFLO_1"]
|
||||
},
|
||||
"sensor": {
|
||||
"state": {
|
||||
"name": "Controller State",
|
||||
"value": 1,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Unknown", "Ready", "Sync", "Service"]
|
||||
},
|
||||
"freeze_mode": {
|
||||
"name": "Freeze Mode",
|
||||
"value": 0
|
||||
},
|
||||
"pool_delay": {
|
||||
"name": "Pool Delay",
|
||||
"value": 0
|
||||
},
|
||||
"spa_delay": {
|
||||
"name": "Spa Delay",
|
||||
"value": 0
|
||||
},
|
||||
"cleaner_delay": {
|
||||
"name": "Cleaner Delay",
|
||||
"value": 0
|
||||
},
|
||||
"air_temperature": {
|
||||
"name": "Air Temperature",
|
||||
"value": 69,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"ph": {
|
||||
"name": "pH",
|
||||
"value": 7.61,
|
||||
"unit": "pH",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"orp": {
|
||||
"name": "ORP",
|
||||
"value": 728,
|
||||
"unit": "mV",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"saturation": {
|
||||
"name": "Saturation Index",
|
||||
"value": 0.06,
|
||||
"unit": "lsi",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"salt_ppm": {
|
||||
"name": "Salt",
|
||||
"value": 0,
|
||||
"unit": "ppm",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"ph_supply_level": {
|
||||
"name": "pH Supply Level",
|
||||
"value": 2,
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"orp_supply_level": {
|
||||
"name": "ORP Supply Level",
|
||||
"value": 3,
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"active_alert": {
|
||||
"name": "Active Alert",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
}
|
||||
}
|
||||
},
|
||||
"circuit": {
|
||||
"500": {
|
||||
"circuit_id": 500,
|
||||
"name": "Spa",
|
||||
"configuration": {
|
||||
"name_index": 71,
|
||||
"flags": 1,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_62": 0,
|
||||
"unknown_at_offset_63": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 1,
|
||||
"interface": 1,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 1,
|
||||
"value": 0
|
||||
},
|
||||
"501": {
|
||||
"circuit_id": 501,
|
||||
"name": "Waterfall",
|
||||
"configuration": {
|
||||
"name_index": 85,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_94": 0,
|
||||
"unknown_at_offset_95": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 0,
|
||||
"interface": 2,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 2,
|
||||
"value": 0
|
||||
},
|
||||
"502": {
|
||||
"circuit_id": 502,
|
||||
"name": "Pool Light",
|
||||
"configuration": {
|
||||
"name_index": 62,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_126": 0,
|
||||
"unknown_at_offset_127": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 16,
|
||||
"interface": 3,
|
||||
"color": {
|
||||
"color_set": 2,
|
||||
"color_position": 0,
|
||||
"color_stagger": 2
|
||||
},
|
||||
"device_id": 3,
|
||||
"value": 0
|
||||
},
|
||||
"503": {
|
||||
"circuit_id": 503,
|
||||
"name": "Spa Light",
|
||||
"configuration": {
|
||||
"name_index": 73,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_158": 0,
|
||||
"unknown_at_offset_159": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 16,
|
||||
"interface": 3,
|
||||
"color": {
|
||||
"color_set": 6,
|
||||
"color_position": 1,
|
||||
"color_stagger": 10
|
||||
},
|
||||
"device_id": 4,
|
||||
"value": 0
|
||||
},
|
||||
"504": {
|
||||
"circuit_id": 504,
|
||||
"name": "Cleaner",
|
||||
"configuration": {
|
||||
"name_index": 21,
|
||||
"flags": 0,
|
||||
"default_runtime": 240,
|
||||
"unknown_at_offset_186": 0,
|
||||
"unknown_at_offset_187": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 5,
|
||||
"interface": 0,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 5,
|
||||
"value": 0
|
||||
},
|
||||
"505": {
|
||||
"circuit_id": 505,
|
||||
"name": "Pool Low",
|
||||
"configuration": {
|
||||
"name_index": 63,
|
||||
"flags": 1,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_214": 0,
|
||||
"unknown_at_offset_215": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 2,
|
||||
"interface": 0,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 6,
|
||||
"value": 0
|
||||
},
|
||||
"506": {
|
||||
"circuit_id": 506,
|
||||
"name": "Yard Light",
|
||||
"configuration": {
|
||||
"name_index": 91,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_246": 0,
|
||||
"unknown_at_offset_247": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 7,
|
||||
"interface": 4,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 7,
|
||||
"value": 0
|
||||
},
|
||||
"507": {
|
||||
"circuit_id": 507,
|
||||
"name": "Cameras",
|
||||
"configuration": {
|
||||
"name_index": 101,
|
||||
"flags": 0,
|
||||
"default_runtime": 1620,
|
||||
"unknown_at_offset_274": 0,
|
||||
"unknown_at_offset_275": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 0,
|
||||
"interface": 2,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 8,
|
||||
"value": 1
|
||||
},
|
||||
"508": {
|
||||
"circuit_id": 508,
|
||||
"name": "Pool High",
|
||||
"configuration": {
|
||||
"name_index": 61,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_306": 0,
|
||||
"unknown_at_offset_307": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 0,
|
||||
"interface": 0,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 9,
|
||||
"value": 0
|
||||
},
|
||||
"510": {
|
||||
"circuit_id": 510,
|
||||
"name": "Spillway",
|
||||
"configuration": {
|
||||
"name_index": 78,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_334": 0,
|
||||
"unknown_at_offset_335": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 14,
|
||||
"interface": 1,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 11,
|
||||
"value": 0
|
||||
},
|
||||
"511": {
|
||||
"circuit_id": 511,
|
||||
"name": "Pool High",
|
||||
"configuration": {
|
||||
"name_index": 61,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_366": 0,
|
||||
"unknown_at_offset_367": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 0,
|
||||
"interface": 5,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 12,
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
"pump": {
|
||||
"0": {
|
||||
"data": 70,
|
||||
"type": 3,
|
||||
"state": {
|
||||
"name": "Pool Low Pump",
|
||||
"value": 0
|
||||
},
|
||||
"watts_now": {
|
||||
"name": "Pool Low Pump Watts Now",
|
||||
"value": 0,
|
||||
"unit": "W",
|
||||
"device_type": "power",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"rpm_now": {
|
||||
"name": "Pool Low Pump RPM Now",
|
||||
"value": 0,
|
||||
"unit": "rpm",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"unknown_at_offset_16": 0,
|
||||
"gpm_now": {
|
||||
"name": "Pool Low Pump GPM Now",
|
||||
"value": 0,
|
||||
"unit": "gpm",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"unknown_at_offset_24": 255,
|
||||
"preset": {
|
||||
"0": {
|
||||
"device_id": 6,
|
||||
"setpoint": 63,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"1": {
|
||||
"device_id": 9,
|
||||
"setpoint": 72,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"2": {
|
||||
"device_id": 1,
|
||||
"setpoint": 3450,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"3": {
|
||||
"device_id": 130,
|
||||
"setpoint": 75,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"4": {
|
||||
"device_id": 12,
|
||||
"setpoint": 72,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"5": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"6": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"7": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"1": {
|
||||
"data": 66,
|
||||
"type": 3,
|
||||
"state": {
|
||||
"name": "Waterfall Pump",
|
||||
"value": 0
|
||||
},
|
||||
"watts_now": {
|
||||
"name": "Waterfall Pump Watts Now",
|
||||
"value": 0,
|
||||
"unit": "W",
|
||||
"device_type": "power",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"rpm_now": {
|
||||
"name": "Waterfall Pump RPM Now",
|
||||
"value": 0,
|
||||
"unit": "rpm",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"unknown_at_offset_16": 0,
|
||||
"gpm_now": {
|
||||
"name": "Waterfall Pump GPM Now",
|
||||
"value": 0,
|
||||
"unit": "gpm",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"unknown_at_offset_24": 255,
|
||||
"preset": {
|
||||
"0": {
|
||||
"device_id": 2,
|
||||
"setpoint": 2700,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"1": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"2": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"3": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"4": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"5": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"6": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"7": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"2": {
|
||||
"data": 0
|
||||
},
|
||||
"3": {
|
||||
"data": 0
|
||||
},
|
||||
"4": {
|
||||
"data": 0
|
||||
},
|
||||
"5": {
|
||||
"data": 0
|
||||
},
|
||||
"6": {
|
||||
"data": 0
|
||||
},
|
||||
"7": {
|
||||
"data": 0
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"0": {
|
||||
"body_type": 0,
|
||||
"min_setpoint": 40,
|
||||
"max_setpoint": 104,
|
||||
"name": "Pool",
|
||||
"last_temperature": {
|
||||
"name": "Last Pool Temperature",
|
||||
"value": 81,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"heat_state": {
|
||||
"name": "Pool Heat",
|
||||
"value": 0,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Off", "Solar", "Heater", "Both"]
|
||||
},
|
||||
"heat_setpoint": {
|
||||
"name": "Pool Heat Set Point",
|
||||
"value": 83,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature"
|
||||
},
|
||||
"cool_setpoint": {
|
||||
"name": "Pool Cool Set Point",
|
||||
"value": 100,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature"
|
||||
},
|
||||
"heat_mode": {
|
||||
"name": "Pool Heat Mode",
|
||||
"value": 0,
|
||||
"device_type": "enum",
|
||||
"enum_options": [
|
||||
"Off",
|
||||
"Solar",
|
||||
"Solar Preferred",
|
||||
"Heater",
|
||||
"Don't Change"
|
||||
]
|
||||
}
|
||||
},
|
||||
"1": {
|
||||
"body_type": 1,
|
||||
"min_setpoint": 40,
|
||||
"max_setpoint": 104,
|
||||
"name": "Spa",
|
||||
"last_temperature": {
|
||||
"name": "Last Spa Temperature",
|
||||
"value": 84,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"heat_state": {
|
||||
"name": "Spa Heat",
|
||||
"value": 0,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Off", "Solar", "Heater", "Both"]
|
||||
},
|
||||
"heat_setpoint": {
|
||||
"name": "Spa Heat Set Point",
|
||||
"value": 94,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature"
|
||||
},
|
||||
"cool_setpoint": {
|
||||
"name": "Spa Cool Set Point",
|
||||
"value": 69,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature"
|
||||
},
|
||||
"heat_mode": {
|
||||
"name": "Spa Heat Mode",
|
||||
"value": 0,
|
||||
"device_type": "enum",
|
||||
"enum_options": [
|
||||
"Off",
|
||||
"Solar",
|
||||
"Solar Preferred",
|
||||
"Heater",
|
||||
"Don't Change"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"intellichem": {
|
||||
"unknown_at_offset_00": 42,
|
||||
"unknown_at_offset_04": 0,
|
||||
"sensor": {
|
||||
"ph_now": {
|
||||
"name": "pH Now",
|
||||
"value": 0.0,
|
||||
"unit": "pH",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"orp_now": {
|
||||
"name": "ORP Now",
|
||||
"value": 0,
|
||||
"unit": "mV",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"ph_supply_level": {
|
||||
"name": "pH Supply Level",
|
||||
"value": 2,
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"orp_supply_level": {
|
||||
"name": "ORP Supply Level",
|
||||
"value": 3,
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"saturation": {
|
||||
"name": "Saturation Index",
|
||||
"value": 0.06,
|
||||
"unit": "lsi",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"ph_probe_water_temp": {
|
||||
"name": "pH Probe Water Temperature",
|
||||
"value": 81,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature",
|
||||
"state_type": "measurement"
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"ph_setpoint": {
|
||||
"name": "pH Setpoint",
|
||||
"value": 7.6,
|
||||
"unit": "pH"
|
||||
},
|
||||
"orp_setpoint": {
|
||||
"name": "ORP Setpoint",
|
||||
"value": 720,
|
||||
"unit": "mV"
|
||||
},
|
||||
"calcium_harness": {
|
||||
"name": "Calcium Hardness",
|
||||
"value": 800,
|
||||
"unit": "ppm"
|
||||
},
|
||||
"cya": {
|
||||
"name": "Cyanuric Acid",
|
||||
"value": 45,
|
||||
"unit": "ppm"
|
||||
},
|
||||
"total_alkalinity": {
|
||||
"name": "Total Alkalinity",
|
||||
"value": 45,
|
||||
"unit": "ppm"
|
||||
},
|
||||
"salt_tds_ppm": {
|
||||
"name": "Salt/TDS",
|
||||
"value": 1000,
|
||||
"unit": "ppm"
|
||||
},
|
||||
"probe_is_celsius": 0,
|
||||
"flags": 32
|
||||
},
|
||||
"dose_status": {
|
||||
"ph_last_dose_time": {
|
||||
"name": "Last pH Dose Time",
|
||||
"value": 5,
|
||||
"unit": "sec",
|
||||
"device_type": "duration",
|
||||
"state_type": "total_increasing"
|
||||
},
|
||||
"orp_last_dose_time": {
|
||||
"name": "Last ORP Dose Time",
|
||||
"value": 4,
|
||||
"unit": "sec",
|
||||
"device_type": "duration",
|
||||
"state_type": "total_increasing"
|
||||
},
|
||||
"ph_last_dose_volume": {
|
||||
"name": "Last pH Dose Volume",
|
||||
"value": 8,
|
||||
"unit": "mL",
|
||||
"device_type": "volume",
|
||||
"state_type": "total_increasing"
|
||||
},
|
||||
"orp_last_dose_volume": {
|
||||
"name": "Last ORP Dose Volume",
|
||||
"value": 8,
|
||||
"unit": "mL",
|
||||
"device_type": "volume",
|
||||
"state_type": "total_increasing"
|
||||
},
|
||||
"flags": 149,
|
||||
"ph_dosing_state": {
|
||||
"name": "pH Dosing State",
|
||||
"value": 1,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Dosing", "Mixing", "Monitoring"]
|
||||
},
|
||||
"orp_dosing_state": {
|
||||
"name": "ORP Dosing State",
|
||||
"value": 2,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Dosing", "Mixing", "Monitoring"]
|
||||
}
|
||||
},
|
||||
"alarm": {
|
||||
"flags": 1,
|
||||
"flow_alarm": {
|
||||
"name": "Flow Alarm",
|
||||
"value": 1,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"ph_high_alarm": {
|
||||
"name": "pH HIGH Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"ph_low_alarm": {
|
||||
"name": "pH LOW Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"orp_high_alarm": {
|
||||
"name": "ORP HIGH Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"orp_low_alarm": {
|
||||
"name": "ORP LOW Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"ph_supply_alarm": {
|
||||
"name": "pH Supply Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"orp_supply_alarm": {
|
||||
"name": "ORP Supply Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"probe_fault_alarm": {
|
||||
"name": "Probe Fault",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
}
|
||||
},
|
||||
"alert": {
|
||||
"flags": 0,
|
||||
"ph_lockout": {
|
||||
"name": "pH Lockout",
|
||||
"value": 0
|
||||
},
|
||||
"ph_limit": {
|
||||
"name": "pH Dose Limit Reached",
|
||||
"value": 0
|
||||
},
|
||||
"orp_limit": {
|
||||
"name": "ORP Dose Limit Reached",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
"firmware": {
|
||||
"name": "IntelliChem Firmware",
|
||||
"value": "1.060"
|
||||
},
|
||||
"water_balance": {
|
||||
"flags": 0,
|
||||
"corrosive": {
|
||||
"name": "SI Corrosive",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"scaling": {
|
||||
"name": "SI Scaling",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
}
|
||||
},
|
||||
"unknown_at_offset_44": 0,
|
||||
"unknown_at_offset_45": 0,
|
||||
"unknown_at_offset_46": 0
|
||||
},
|
||||
"scg": {
|
||||
"scg_present": 1,
|
||||
"sensor": {
|
||||
"state": {
|
||||
"name": "Chlorinator",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"pool_setpoint": {
|
||||
"name": "Pool Chlorinator Setpoint",
|
||||
"value": 50,
|
||||
"unit": "%",
|
||||
"min_setpoint": 0,
|
||||
"max_setpoint": 100,
|
||||
"step": 5,
|
||||
"body_type": 0
|
||||
},
|
||||
"super_chlor_timer": {
|
||||
"name": "Super Chlorination Timer",
|
||||
"value": 0,
|
||||
"unit": "hr",
|
||||
"min_setpoint": 1,
|
||||
"max_setpoint": 72,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"flags": 0
|
||||
}
|
||||
}
|
@ -0,0 +1,849 @@
|
||||
{
|
||||
"adapter": {
|
||||
"firmware": {
|
||||
"name": "Protocol Adapter Firmware",
|
||||
"value": "POOL: 5.2 Build 736.0 Rel"
|
||||
}
|
||||
},
|
||||
"controller": {
|
||||
"controller_id": 100,
|
||||
"configuration": {
|
||||
"body_type": {
|
||||
"0": {
|
||||
"min_setpoint": 40,
|
||||
"max_setpoint": 104
|
||||
},
|
||||
"1": {
|
||||
"min_setpoint": 40,
|
||||
"max_setpoint": 104
|
||||
}
|
||||
},
|
||||
"is_celsius": {
|
||||
"name": "Is Celsius",
|
||||
"value": 0
|
||||
},
|
||||
"controller_type": 13,
|
||||
"hardware_type": 0,
|
||||
"controller_data": 0,
|
||||
"generic_circuit_name": "Water Features",
|
||||
"circuit_count": 11,
|
||||
"color_count": 8,
|
||||
"color": [
|
||||
{
|
||||
"name": "White",
|
||||
"value": [255, 255, 255]
|
||||
},
|
||||
{
|
||||
"name": "Light Green",
|
||||
"value": [160, 255, 160]
|
||||
},
|
||||
{
|
||||
"name": "Green",
|
||||
"value": [0, 255, 80]
|
||||
},
|
||||
{
|
||||
"name": "Cyan",
|
||||
"value": [0, 255, 200]
|
||||
},
|
||||
{
|
||||
"name": "Blue",
|
||||
"value": [100, 140, 255]
|
||||
},
|
||||
{
|
||||
"name": "Lavender",
|
||||
"value": [230, 130, 255]
|
||||
},
|
||||
{
|
||||
"name": "Magenta",
|
||||
"value": [255, 0, 128]
|
||||
},
|
||||
{
|
||||
"name": "Light Magenta",
|
||||
"value": [255, 180, 210]
|
||||
}
|
||||
],
|
||||
"interface_tab_flags": 127,
|
||||
"show_alarms": 0,
|
||||
"remotes": 0,
|
||||
"unknown_at_offset_09": 0,
|
||||
"unknown_at_offset_10": 0,
|
||||
"unknown_at_offset_11": 0
|
||||
},
|
||||
"model": {
|
||||
"name": "Model",
|
||||
"value": "EasyTouch2 8"
|
||||
},
|
||||
"equipment": {
|
||||
"flags": 32828,
|
||||
"list": [
|
||||
"CHLORINATOR",
|
||||
"INTELLIBRITE",
|
||||
"INTELLIFLO_0",
|
||||
"INTELLIFLO_1",
|
||||
"INTELLICHEM"
|
||||
]
|
||||
},
|
||||
"sensor": {
|
||||
"state": {
|
||||
"name": "Controller State",
|
||||
"value": 1,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Unknown", "Ready", "Sync", "Service"]
|
||||
},
|
||||
"pool_delay": {
|
||||
"name": "Pool Delay",
|
||||
"value": 0
|
||||
},
|
||||
"spa_delay": {
|
||||
"name": "Spa Delay",
|
||||
"value": 0
|
||||
},
|
||||
"cleaner_delay": {
|
||||
"name": "Cleaner Delay",
|
||||
"value": 0
|
||||
},
|
||||
"air_temperature": {
|
||||
"name": "Air Temperature",
|
||||
"value": 69,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"orp": {
|
||||
"name": "ORP",
|
||||
"value": 728,
|
||||
"unit": "mV",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"saturation": {
|
||||
"name": "Saturation Index",
|
||||
"value": 0.06,
|
||||
"unit": "lsi",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"salt_ppm": {
|
||||
"name": "Salt",
|
||||
"value": 0,
|
||||
"unit": "ppm",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"ph_supply_level": {
|
||||
"name": "pH Supply Level",
|
||||
"value": 2,
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"orp_supply_level": {
|
||||
"name": "ORP Supply Level",
|
||||
"value": 3,
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"active_alert": {
|
||||
"name": "Active Alert",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
}
|
||||
}
|
||||
},
|
||||
"circuit": {
|
||||
"500": {
|
||||
"circuit_id": 500,
|
||||
"name": "Spa",
|
||||
"configuration": {
|
||||
"name_index": 71,
|
||||
"flags": 1,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_62": 0,
|
||||
"unknown_at_offset_63": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 1,
|
||||
"interface": 1,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 1,
|
||||
"value": 0
|
||||
},
|
||||
"501": {
|
||||
"circuit_id": 501,
|
||||
"name": "Waterfall",
|
||||
"configuration": {
|
||||
"name_index": 85,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_94": 0,
|
||||
"unknown_at_offset_95": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 0,
|
||||
"interface": 2,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 2,
|
||||
"value": 0
|
||||
},
|
||||
"502": {
|
||||
"circuit_id": 502,
|
||||
"name": "Pool Light",
|
||||
"configuration": {
|
||||
"name_index": 62,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_126": 0,
|
||||
"unknown_at_offset_127": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 16,
|
||||
"interface": 3,
|
||||
"color": {
|
||||
"color_set": 2,
|
||||
"color_position": 0,
|
||||
"color_stagger": 2
|
||||
},
|
||||
"device_id": 3,
|
||||
"value": 0
|
||||
},
|
||||
"503": {
|
||||
"circuit_id": 503,
|
||||
"name": "Spa Light",
|
||||
"configuration": {
|
||||
"name_index": 73,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_158": 0,
|
||||
"unknown_at_offset_159": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 16,
|
||||
"interface": 3,
|
||||
"color": {
|
||||
"color_set": 6,
|
||||
"color_position": 1,
|
||||
"color_stagger": 10
|
||||
},
|
||||
"device_id": 4,
|
||||
"value": 0
|
||||
},
|
||||
"504": {
|
||||
"circuit_id": 504,
|
||||
"name": "Cleaner",
|
||||
"configuration": {
|
||||
"name_index": 21,
|
||||
"flags": 0,
|
||||
"default_runtime": 240,
|
||||
"unknown_at_offset_186": 0,
|
||||
"unknown_at_offset_187": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 5,
|
||||
"interface": 0,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 5,
|
||||
"value": 0
|
||||
},
|
||||
"505": {
|
||||
"circuit_id": 505,
|
||||
"name": "Pool Low",
|
||||
"configuration": {
|
||||
"name_index": 63,
|
||||
"flags": 1,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_214": 0,
|
||||
"unknown_at_offset_215": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 2,
|
||||
"interface": 0,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 6,
|
||||
"value": 0
|
||||
},
|
||||
"506": {
|
||||
"circuit_id": 506,
|
||||
"name": "Yard Light",
|
||||
"configuration": {
|
||||
"name_index": 91,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_246": 0,
|
||||
"unknown_at_offset_247": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 7,
|
||||
"interface": 4,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 7,
|
||||
"value": 0
|
||||
},
|
||||
"507": {
|
||||
"circuit_id": 507,
|
||||
"name": "Cameras",
|
||||
"configuration": {
|
||||
"name_index": 101,
|
||||
"flags": 0,
|
||||
"default_runtime": 1620,
|
||||
"unknown_at_offset_274": 0,
|
||||
"unknown_at_offset_275": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 0,
|
||||
"interface": 2,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 8,
|
||||
"value": 1
|
||||
},
|
||||
"508": {
|
||||
"circuit_id": 508,
|
||||
"name": "Pool High",
|
||||
"configuration": {
|
||||
"name_index": 61,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_306": 0,
|
||||
"unknown_at_offset_307": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 0,
|
||||
"interface": 0,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 9,
|
||||
"value": 0
|
||||
},
|
||||
"510": {
|
||||
"circuit_id": 510,
|
||||
"name": "Spillway",
|
||||
"configuration": {
|
||||
"name_index": 78,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_334": 0,
|
||||
"unknown_at_offset_335": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 14,
|
||||
"interface": 1,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 11,
|
||||
"value": 0
|
||||
},
|
||||
"511": {
|
||||
"circuit_id": 511,
|
||||
"name": "Pool High",
|
||||
"configuration": {
|
||||
"name_index": 61,
|
||||
"flags": 0,
|
||||
"default_runtime": 720,
|
||||
"unknown_at_offset_366": 0,
|
||||
"unknown_at_offset_367": 0,
|
||||
"delay": 0
|
||||
},
|
||||
"function": 0,
|
||||
"interface": 5,
|
||||
"color": {
|
||||
"color_set": 0,
|
||||
"color_position": 0,
|
||||
"color_stagger": 0
|
||||
},
|
||||
"device_id": 12,
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
"pump": {
|
||||
"0": {
|
||||
"data": 70,
|
||||
"type": 3,
|
||||
"state": {
|
||||
"name": "Pool Low Pump",
|
||||
"value": 0
|
||||
},
|
||||
"watts_now": {
|
||||
"name": "Pool Low Pump Watts Now",
|
||||
"value": 0,
|
||||
"unit": "W",
|
||||
"device_type": "power",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"rpm_now": {
|
||||
"name": "Pool Low Pump RPM Now",
|
||||
"value": 0,
|
||||
"unit": "rpm",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"unknown_at_offset_16": 0,
|
||||
"unknown_at_offset_24": 255,
|
||||
"preset": {
|
||||
"0": {
|
||||
"device_id": 6,
|
||||
"setpoint": 63,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"1": {
|
||||
"device_id": 9,
|
||||
"setpoint": 72,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"2": {
|
||||
"device_id": 1,
|
||||
"setpoint": 3450,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"3": {
|
||||
"device_id": 130,
|
||||
"setpoint": 75,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"4": {
|
||||
"device_id": 12,
|
||||
"setpoint": 72,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"5": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"6": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"7": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"1": {
|
||||
"data": 66,
|
||||
"type": 3,
|
||||
"state": {
|
||||
"name": "Waterfall Pump",
|
||||
"value": 0
|
||||
},
|
||||
"watts_now": {
|
||||
"name": "Waterfall Pump Watts Now",
|
||||
"value": 0,
|
||||
"unit": "W",
|
||||
"device_type": "power",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"rpm_now": {
|
||||
"name": "Waterfall Pump RPM Now",
|
||||
"value": 0,
|
||||
"unit": "rpm",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"unknown_at_offset_16": 0,
|
||||
"gpm_now": {
|
||||
"name": "Waterfall Pump GPM Now",
|
||||
"value": 0,
|
||||
"unit": "gpm",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"unknown_at_offset_24": 255,
|
||||
"preset": {
|
||||
"0": {
|
||||
"device_id": 2,
|
||||
"setpoint": 2700,
|
||||
"is_rpm": 1
|
||||
},
|
||||
"1": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"2": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"3": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"4": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"5": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"6": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
},
|
||||
"7": {
|
||||
"device_id": 0,
|
||||
"setpoint": 30,
|
||||
"is_rpm": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"2": {
|
||||
"data": 0
|
||||
},
|
||||
"3": {
|
||||
"data": 0
|
||||
},
|
||||
"4": {
|
||||
"data": 0
|
||||
},
|
||||
"5": {
|
||||
"data": 0
|
||||
},
|
||||
"6": {
|
||||
"data": 0
|
||||
},
|
||||
"7": {
|
||||
"data": 0
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"0": {
|
||||
"body_type": 0,
|
||||
"min_setpoint": 40,
|
||||
"max_setpoint": 104,
|
||||
"name": "Pool",
|
||||
"last_temperature": {
|
||||
"name": "Last Pool Temperature",
|
||||
"value": 81,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"heat_state": {
|
||||
"name": "Pool Heat",
|
||||
"value": 0,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Off", "Solar", "Heater", "Both"]
|
||||
},
|
||||
"heat_setpoint": {
|
||||
"name": "Pool Heat Set Point",
|
||||
"value": 83,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature"
|
||||
},
|
||||
"cool_setpoint": {
|
||||
"name": "Pool Cool Set Point",
|
||||
"value": 100,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature"
|
||||
},
|
||||
"heat_mode": {
|
||||
"name": "Pool Heat Mode",
|
||||
"value": 0,
|
||||
"device_type": "enum",
|
||||
"enum_options": [
|
||||
"Off",
|
||||
"Solar",
|
||||
"Solar Preferred",
|
||||
"Heater",
|
||||
"Don't Change"
|
||||
]
|
||||
}
|
||||
},
|
||||
"1": {
|
||||
"body_type": 1,
|
||||
"min_setpoint": 40,
|
||||
"max_setpoint": 104,
|
||||
"name": "Spa",
|
||||
"last_temperature": {
|
||||
"name": "Last Spa Temperature",
|
||||
"value": 84,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"heat_state": {
|
||||
"name": "Spa Heat",
|
||||
"value": 0,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Off", "Solar", "Heater", "Both"]
|
||||
},
|
||||
"heat_setpoint": {
|
||||
"name": "Spa Heat Set Point",
|
||||
"value": 94,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature"
|
||||
},
|
||||
"cool_setpoint": {
|
||||
"name": "Spa Cool Set Point",
|
||||
"value": 69,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature"
|
||||
},
|
||||
"heat_mode": {
|
||||
"name": "Spa Heat Mode",
|
||||
"value": 0,
|
||||
"device_type": "enum",
|
||||
"enum_options": [
|
||||
"Off",
|
||||
"Solar",
|
||||
"Solar Preferred",
|
||||
"Heater",
|
||||
"Don't Change"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"intellichem": {
|
||||
"unknown_at_offset_00": 42,
|
||||
"unknown_at_offset_04": 0,
|
||||
"sensor": {
|
||||
"orp_now": {
|
||||
"name": "ORP Now",
|
||||
"value": 0,
|
||||
"unit": "mV",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"ph_supply_level": {
|
||||
"name": "pH Supply Level",
|
||||
"value": 2,
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"orp_supply_level": {
|
||||
"name": "ORP Supply Level",
|
||||
"value": 3,
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"saturation": {
|
||||
"name": "Saturation Index",
|
||||
"value": 0.06,
|
||||
"unit": "lsi",
|
||||
"state_type": "measurement"
|
||||
},
|
||||
"ph_probe_water_temp": {
|
||||
"name": "pH Probe Water Temperature",
|
||||
"value": 81,
|
||||
"unit": "\u00b0F",
|
||||
"device_type": "temperature",
|
||||
"state_type": "measurement"
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"ph_setpoint": {
|
||||
"name": "pH Setpoint",
|
||||
"value": 7.6,
|
||||
"unit": "pH"
|
||||
},
|
||||
"orp_setpoint": {
|
||||
"name": "ORP Setpoint",
|
||||
"value": 720,
|
||||
"unit": "mV"
|
||||
},
|
||||
"calcium_harness": {
|
||||
"name": "Calcium Hardness",
|
||||
"value": 800,
|
||||
"unit": "ppm"
|
||||
},
|
||||
"cya": {
|
||||
"name": "Cyanuric Acid",
|
||||
"value": 45,
|
||||
"unit": "ppm"
|
||||
},
|
||||
"total_alkalinity": {
|
||||
"name": "Total Alkalinity",
|
||||
"value": 45,
|
||||
"unit": "ppm"
|
||||
},
|
||||
"salt_tds_ppm": {
|
||||
"name": "Salt/TDS",
|
||||
"value": 1000,
|
||||
"unit": "ppm"
|
||||
},
|
||||
"probe_is_celsius": 0,
|
||||
"flags": 32
|
||||
},
|
||||
"dose_status": {
|
||||
"ph_last_dose_time": {
|
||||
"name": "Last pH Dose Time",
|
||||
"value": 5,
|
||||
"unit": "sec",
|
||||
"device_type": "duration",
|
||||
"state_type": "total_increasing"
|
||||
},
|
||||
"orp_last_dose_time": {
|
||||
"name": "Last ORP Dose Time",
|
||||
"value": 4,
|
||||
"unit": "sec",
|
||||
"device_type": "duration",
|
||||
"state_type": "total_increasing"
|
||||
},
|
||||
"ph_last_dose_volume": {
|
||||
"name": "Last pH Dose Volume",
|
||||
"value": 8,
|
||||
"unit": "mL",
|
||||
"device_type": "volume",
|
||||
"state_type": "total_increasing"
|
||||
},
|
||||
"orp_last_dose_volume": {
|
||||
"name": "Last ORP Dose Volume",
|
||||
"value": 8,
|
||||
"unit": "mL",
|
||||
"device_type": "volume",
|
||||
"state_type": "total_increasing"
|
||||
},
|
||||
"flags": 149,
|
||||
"ph_dosing_state": {
|
||||
"name": "pH Dosing State",
|
||||
"value": 1,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Dosing", "Mixing", "Monitoring"]
|
||||
},
|
||||
"orp_dosing_state": {
|
||||
"name": "ORP Dosing State",
|
||||
"value": 2,
|
||||
"device_type": "enum",
|
||||
"enum_options": ["Dosing", "Mixing", "Monitoring"]
|
||||
}
|
||||
},
|
||||
"alarm": {
|
||||
"flags": 1,
|
||||
"flow_alarm": {
|
||||
"name": "Flow Alarm",
|
||||
"value": 1,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"ph_high_alarm": {
|
||||
"name": "pH HIGH Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"ph_low_alarm": {
|
||||
"name": "pH LOW Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"orp_high_alarm": {
|
||||
"name": "ORP HIGH Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"orp_low_alarm": {
|
||||
"name": "ORP LOW Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"ph_supply_alarm": {
|
||||
"name": "pH Supply Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"orp_supply_alarm": {
|
||||
"name": "ORP Supply Alarm",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"probe_fault_alarm": {
|
||||
"name": "Probe Fault",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
}
|
||||
},
|
||||
"alert": {
|
||||
"flags": 0,
|
||||
"ph_lockout": {
|
||||
"name": "pH Lockout",
|
||||
"value": 0
|
||||
},
|
||||
"ph_limit": {
|
||||
"name": "pH Dose Limit Reached",
|
||||
"value": 0
|
||||
},
|
||||
"orp_limit": {
|
||||
"name": "ORP Dose Limit Reached",
|
||||
"value": 0
|
||||
}
|
||||
},
|
||||
"firmware": {
|
||||
"name": "IntelliChem Firmware",
|
||||
"value": "1.060"
|
||||
},
|
||||
"water_balance": {
|
||||
"flags": 0,
|
||||
"corrosive": {
|
||||
"name": "SI Corrosive",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
},
|
||||
"scaling": {
|
||||
"name": "SI Scaling",
|
||||
"value": 0,
|
||||
"device_type": "alarm"
|
||||
}
|
||||
},
|
||||
"unknown_at_offset_44": 0,
|
||||
"unknown_at_offset_45": 0,
|
||||
"unknown_at_offset_46": 0
|
||||
},
|
||||
"scg": {
|
||||
"scg_present": 1,
|
||||
"sensor": {
|
||||
"state": {
|
||||
"name": "Chlorinator",
|
||||
"value": 0
|
||||
},
|
||||
"salt_ppm": {
|
||||
"name": "Chlorinator Salt",
|
||||
"value": 0,
|
||||
"unit": "ppm",
|
||||
"state_type": "measurement"
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"pool_setpoint": {
|
||||
"name": "Pool Chlorinator Setpoint",
|
||||
"value": 50,
|
||||
"unit": "%",
|
||||
"min_setpoint": 0,
|
||||
"max_setpoint": 100,
|
||||
"step": 5,
|
||||
"body_type": 0
|
||||
},
|
||||
"super_chlor_timer": {
|
||||
"name": "Super Chlorination Timer",
|
||||
"value": 0,
|
||||
"unit": "hr",
|
||||
"min_setpoint": 1,
|
||||
"max_setpoint": 72,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
"flags": 0
|
||||
}
|
||||
}
|
@ -1,12 +1,9 @@
|
||||
"""Tests for ScreenLogic integration data processing."""
|
||||
from unittest.mock import DEFAULT, patch
|
||||
|
||||
import pytest
|
||||
from screenlogicpy import ScreenLogicGateway
|
||||
from screenlogicpy.const.data import ATTR, DEVICE, GROUP, VALUE
|
||||
|
||||
from homeassistant.components.screenlogic import DOMAIN
|
||||
from homeassistant.components.screenlogic.data import PathPart, realize_path_template
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
@ -71,21 +68,3 @@ async def test_async_cleanup_entries(
|
||||
|
||||
deleted_entity = entity_registry.async_get(unused_entity.entity_id)
|
||||
assert deleted_entity is None
|
||||
|
||||
|
||||
def test_realize_path_templates() -> None:
|
||||
"""Test path template realization."""
|
||||
assert realize_path_template(
|
||||
(PathPart.DEVICE, PathPart.INDEX), (DEVICE.PUMP, 0, VALUE.WATTS_NOW)
|
||||
) == (DEVICE.PUMP, 0)
|
||||
|
||||
assert realize_path_template(
|
||||
(PathPart.DEVICE, PathPart.INDEX, PathPart.VALUE, ATTR.NAME_INDEX),
|
||||
(DEVICE.CIRCUIT, 500, GROUP.CONFIGURATION),
|
||||
) == (DEVICE.CIRCUIT, 500, GROUP.CONFIGURATION, ATTR.NAME_INDEX)
|
||||
|
||||
with pytest.raises(KeyError):
|
||||
realize_path_template(
|
||||
(PathPart.DEVICE, PathPart.KEY, ATTR.VALUE),
|
||||
(DEVICE.ADAPTER, VALUE.FIRMWARE),
|
||||
)
|
||||
|
@ -6,6 +6,7 @@ import pytest
|
||||
from screenlogicpy import ScreenLogicGateway
|
||||
|
||||
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
||||
from homeassistant.components.number import DOMAIN as NUMBER_DOMAIN
|
||||
from homeassistant.components.screenlogic import DOMAIN
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
@ -14,6 +15,7 @@ from homeassistant.util import slugify
|
||||
|
||||
from . import (
|
||||
DATA_MIN_MIGRATION,
|
||||
DATA_MISSING_VALUES_CHEM_CHLOR,
|
||||
GATEWAY_DISCOVERY_IMPORT_PATH,
|
||||
MOCK_ADAPTER_MAC,
|
||||
MOCK_ADAPTER_NAME,
|
||||
@ -77,6 +79,13 @@ TEST_MIGRATING_ENTITIES = [
|
||||
"old_sensor",
|
||||
SENSOR_DOMAIN,
|
||||
),
|
||||
EntityMigrationData(
|
||||
"Pump Sensor Missing Index",
|
||||
"currentWatts",
|
||||
"Pump Sensor Missing Index",
|
||||
"currentWatts",
|
||||
SENSOR_DOMAIN,
|
||||
),
|
||||
]
|
||||
|
||||
MIGRATION_CONNECT = lambda *args, **kwargs: stub_async_connect(
|
||||
@ -234,3 +243,37 @@ async def test_entity_migration_data(
|
||||
|
||||
entity_not_migrated = entity_registry.async_get(old_eid)
|
||||
assert entity_not_migrated == original_entity
|
||||
|
||||
|
||||
async def test_platform_setup(
|
||||
hass: HomeAssistant, mock_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test setup for platforms that define expected data."""
|
||||
stub_connect = lambda *args, **kwargs: stub_async_connect(
|
||||
DATA_MISSING_VALUES_CHEM_CHLOR, *args, **kwargs
|
||||
)
|
||||
|
||||
device_prefix = slugify(MOCK_ADAPTER_NAME)
|
||||
|
||||
tested_entity_ids = [
|
||||
f"{BINARY_SENSOR_DOMAIN}.{device_prefix}_active_alert",
|
||||
f"{SENSOR_DOMAIN}.{device_prefix}_air_temperature",
|
||||
f"{NUMBER_DOMAIN}.{device_prefix}_pool_chlorinator_setpoint",
|
||||
]
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
with patch(
|
||||
GATEWAY_DISCOVERY_IMPORT_PATH,
|
||||
return_value={},
|
||||
), patch.multiple(
|
||||
ScreenLogicGateway,
|
||||
async_connect=stub_connect,
|
||||
is_connected=True,
|
||||
_async_connected_request=DEFAULT,
|
||||
):
|
||||
assert await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
for entity_id in tested_entity_ids:
|
||||
assert hass.states.get(entity_id) is not None
|
||||
|
Loading…
x
Reference in New Issue
Block a user