Explicitly define ScreenLogic entity descriptions (#100173)
This commit is contained in:
parent
2ae07096d2
commit
77007ef091
16 changed files with 3144 additions and 681 deletions
|
@ -129,9 +129,12 @@ async def _async_migrate_entries(
|
||||||
new_key,
|
new_key,
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
assert device is not None and (
|
if device == "pump" and source_index is None:
|
||||||
device != "pump" or (device == "pump" and source_index is not None)
|
_LOGGER.debug(
|
||||||
)
|
"Unable to parse 'source_index' from existing unique_id for pump entity '%s'",
|
||||||
|
source_key,
|
||||||
|
)
|
||||||
|
continue
|
||||||
new_unique_id = (
|
new_unique_id = (
|
||||||
f"{source_mac}_{generate_unique_id(device, source_index, new_key)}"
|
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
|
updates["new_unique_id"] = new_unique_id
|
||||||
|
|
||||||
if (old_name := migrations.get("old_name")) is not None:
|
if (old_name := migrations.get("old_name")) is not None:
|
||||||
assert old_name
|
|
||||||
new_name = migrations["new_name"]
|
new_name = migrations["new_name"]
|
||||||
if (s_old_name := slugify(old_name)) in entry.entity_id:
|
if (s_old_name := slugify(old_name)) in entry.entity_id:
|
||||||
new_entity_id = entry.entity_id.replace(s_old_name, slugify(new_name))
|
new_entity_id = entry.entity_id.replace(s_old_name, slugify(new_name))
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
"""Support for a ScreenLogic Binary Sensor."""
|
"""Support for a ScreenLogic Binary Sensor."""
|
||||||
|
from copy import copy
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import logging
|
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.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 (
|
from homeassistant.components.binary_sensor import (
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
@ -12,85 +15,157 @@ from homeassistant.components.binary_sensor import (
|
||||||
BinarySensorEntityDescription,
|
BinarySensorEntityDescription,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import EntityCategory
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
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 .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 (
|
from .entity import (
|
||||||
ScreenlogicEntity,
|
ScreenlogicEntity,
|
||||||
ScreenLogicEntityDescription,
|
ScreenLogicEntityDescription,
|
||||||
ScreenLogicPushEntity,
|
ScreenLogicPushEntity,
|
||||||
ScreenLogicPushEntityDescription,
|
ScreenLogicPushEntityDescription,
|
||||||
)
|
)
|
||||||
from .util import cleanup_excluded_entity, generate_unique_id
|
from .util import cleanup_excluded_entity
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SupportedBinarySensorValueParameters(SupportedValueParameters):
|
class ScreenLogicBinarySensorDescription(
|
||||||
"""Supported predefined data for a ScreenLogic binary sensor entity."""
|
BinarySensorEntityDescription, ScreenLogicEntityDescription
|
||||||
|
):
|
||||||
device_class: BinarySensorDeviceClass | None = None
|
"""A class that describes ScreenLogic binary sensor eneites."""
|
||||||
|
|
||||||
|
|
||||||
SUPPORTED_DATA: list[
|
@dataclass
|
||||||
tuple[ScreenLogicDataPath, SupportedValueParameters]
|
class ScreenLogicPushBinarySensorDescription(
|
||||||
] = preprocess_supported_values(
|
ScreenLogicBinarySensorDescription, ScreenLogicPushEntityDescription
|
||||||
{
|
):
|
||||||
DEVICE.CONTROLLER: {
|
"""Describes a ScreenLogicPushBinarySensor."""
|
||||||
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(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
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(
|
async def async_setup_entry(
|
||||||
|
@ -104,72 +179,65 @@ async def async_setup_entry(
|
||||||
config_entry.entry_id
|
config_entry.entry_id
|
||||||
]
|
]
|
||||||
gateway = coordinator.gateway
|
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 (
|
if (
|
||||||
sub_code := (
|
gateway.get_data(
|
||||||
value_params.subscription_code or DEVICE_SUBSCRIPTION.get(device)
|
*core_sensor_description.data_root, core_sensor_description.key
|
||||||
)
|
)
|
||||||
) is not None:
|
is not None
|
||||||
|
):
|
||||||
entities.append(
|
entities.append(
|
||||||
ScreenLogicPushBinarySensor(
|
ScreenLogicPushBinarySensor(coordinator, core_sensor_description)
|
||||||
coordinator,
|
)
|
||||||
ScreenLogicPushBinarySensorDescription(
|
|
||||||
subscription_code=sub_code, **entity_description_kwargs
|
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(
|
entities.append(
|
||||||
ScreenLogicBinarySensor(
|
ScreenLogicPushBinarySensor(coordinator, chem_sensor_description)
|
||||||
coordinator,
|
)
|
||||||
ScreenLogicBinarySensorDescription(**entity_description_kwargs),
|
|
||||||
)
|
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)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ScreenLogicBinarySensorDescription(
|
|
||||||
BinarySensorEntityDescription, ScreenLogicEntityDescription
|
|
||||||
):
|
|
||||||
"""A class that describes ScreenLogic binary sensor eneites."""
|
|
||||||
|
|
||||||
|
|
||||||
class ScreenLogicBinarySensor(ScreenlogicEntity, BinarySensorEntity):
|
class ScreenLogicBinarySensor(ScreenlogicEntity, BinarySensorEntity):
|
||||||
"""Base class for all ScreenLogic binary sensor entities."""
|
"""Representation of a ScreenLogic binary sensor entity."""
|
||||||
|
|
||||||
entity_description: ScreenLogicBinarySensorDescription
|
entity_description: ScreenLogicBinarySensorDescription
|
||||||
_attr_has_entity_name = True
|
_attr_has_entity_name = True
|
||||||
|
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
def is_on(self) -> bool:
|
||||||
|
@ -177,14 +245,21 @@ class ScreenLogicBinarySensor(ScreenlogicEntity, BinarySensorEntity):
|
||||||
return self.entity_data[ATTR.VALUE] == ON_OFF.ON
|
return self.entity_data[ATTR.VALUE] == ON_OFF.ON
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ScreenLogicPushBinarySensorDescription(
|
|
||||||
ScreenLogicBinarySensorDescription, ScreenLogicPushEntityDescription
|
|
||||||
):
|
|
||||||
"""Describes a ScreenLogicPushBinarySensor."""
|
|
||||||
|
|
||||||
|
|
||||||
class ScreenLogicPushBinarySensor(ScreenLogicPushEntity, ScreenLogicBinarySensor):
|
class ScreenLogicPushBinarySensor(ScreenLogicPushEntity, ScreenLogicBinarySensor):
|
||||||
"""Representation of a basic ScreenLogic sensor entity."""
|
"""Representation of a ScreenLogic push binary sensor entity."""
|
||||||
|
|
||||||
entity_description: ScreenLogicPushBinarySensorDescription
|
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
|
gateway = coordinator.gateway
|
||||||
|
|
||||||
for body_index, body_data in gateway.get_data(DEVICE.BODY).items():
|
for body_index in gateway.get_data(DEVICE.BODY):
|
||||||
body_path = (DEVICE.BODY, body_index)
|
|
||||||
entities.append(
|
entities.append(
|
||||||
ScreenLogicClimate(
|
ScreenLogicClimate(
|
||||||
coordinator,
|
coordinator,
|
||||||
ScreenLogicClimateDescription(
|
ScreenLogicClimateDescription(
|
||||||
subscription_code=CODE.STATUS_CHANGED,
|
subscription_code=CODE.STATUS_CHANGED,
|
||||||
data_path=body_path,
|
data_root=(DEVICE.BODY,),
|
||||||
key=body_index,
|
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_min_temp = self.entity_data[ATTR.MIN_SETPOINT]
|
||||||
self._attr_max_temp = self.entity_data[ATTR.MAX_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
|
self._last_preset = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -1,189 +1,5 @@
|
||||||
"""Support for configurable supported data values for the ScreenLogic integration."""
|
"""Support for configurable supported data values for the ScreenLogic integration."""
|
||||||
from collections.abc import Callable, Generator
|
from screenlogicpy.const.data import DEVICE, VALUE
|
||||||
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),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ENTITY_MIGRATIONS = {
|
ENTITY_MIGRATIONS = {
|
||||||
"chem_alarm": {
|
"chem_alarm": {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Base ScreenLogicEntity definitions."""
|
"""Base ScreenLogicEntity definitions."""
|
||||||
|
from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import logging
|
import logging
|
||||||
|
@ -18,15 +19,16 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
from .const import ScreenLogicDataPath
|
from .const import ScreenLogicDataPath
|
||||||
from .coordinator import ScreenlogicDataUpdateCoordinator
|
from .coordinator import ScreenlogicDataUpdateCoordinator
|
||||||
|
from .util import generate_unique_id
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ScreenLogicEntityRequiredKeyMixin:
|
class ScreenLogicEntityRequiredKeyMixin:
|
||||||
"""Mixin for required ScreenLogic entity key."""
|
"""Mixin for required ScreenLogic entity data_path."""
|
||||||
|
|
||||||
data_path: ScreenLogicDataPath
|
data_root: ScreenLogicDataPath
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -35,6 +37,8 @@ class ScreenLogicEntityDescription(
|
||||||
):
|
):
|
||||||
"""Base class for a ScreenLogic entity description."""
|
"""Base class for a ScreenLogic entity description."""
|
||||||
|
|
||||||
|
enabled_lambda: Callable[..., bool] | None = None
|
||||||
|
|
||||||
|
|
||||||
class ScreenlogicEntity(CoordinatorEntity[ScreenlogicDataUpdateCoordinator]):
|
class ScreenlogicEntity(CoordinatorEntity[ScreenlogicDataUpdateCoordinator]):
|
||||||
"""Base class for all ScreenLogic entities."""
|
"""Base class for all ScreenLogic entities."""
|
||||||
|
@ -50,10 +54,11 @@ class ScreenlogicEntity(CoordinatorEntity[ScreenlogicDataUpdateCoordinator]):
|
||||||
"""Initialize of the entity."""
|
"""Initialize of the entity."""
|
||||||
super().__init__(coordinator)
|
super().__init__(coordinator)
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
self._data_path = self.entity_description.data_path
|
self._data_key = self.entity_description.key
|
||||||
self._data_key = self._data_path[-1]
|
self._data_path = (*self.entity_description.data_root, self._data_key)
|
||||||
self._attr_unique_id = f"{self.mac}_{self.entity_description.key}"
|
|
||||||
mac = self.mac
|
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
|
assert mac is not None
|
||||||
self._attr_device_info = DeviceInfo(
|
self._attr_device_info = DeviceInfo(
|
||||||
connections={(dr.CONNECTION_NETWORK_MAC, mac)},
|
connections={(dr.CONNECTION_NETWORK_MAC, mac)},
|
||||||
|
@ -88,9 +93,10 @@ class ScreenlogicEntity(CoordinatorEntity[ScreenlogicDataUpdateCoordinator]):
|
||||||
@property
|
@property
|
||||||
def entity_data(self) -> dict:
|
def entity_data(self) -> dict:
|
||||||
"""Shortcut to the data for this entity."""
|
"""Shortcut to the data for this entity."""
|
||||||
if (data := self.gateway.get_data(*self._data_path)) is None:
|
try:
|
||||||
raise KeyError(f"Data not found: {self._data_path}")
|
return self.gateway.get_data(*self._data_path, strict=True)
|
||||||
return data
|
except KeyError as ke:
|
||||||
|
raise HomeAssistantError(f"Data not found: {self._data_path}") from ke
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -120,6 +126,7 @@ class ScreenLogicPushEntity(ScreenlogicEntity):
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize of the entity."""
|
"""Initialize of the entity."""
|
||||||
super().__init__(coordinator, entity_description)
|
super().__init__(coordinator, entity_description)
|
||||||
|
self._subscription_code = entity_description.subscription_code
|
||||||
self._last_update_success = True
|
self._last_update_success = True
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
@ -134,7 +141,7 @@ class ScreenLogicPushEntity(ScreenlogicEntity):
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
await self.gateway.async_subscribe_client(
|
await self.gateway.async_subscribe_client(
|
||||||
self._async_data_updated,
|
self._async_data_updated,
|
||||||
self.entity_description.subscription_code,
|
self._subscription_code,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,11 @@ async def async_setup_entry(
|
||||||
]
|
]
|
||||||
gateway = coordinator.gateway
|
gateway = coordinator.gateway
|
||||||
for circuit_index, circuit_data in gateway.get_data(DEVICE.CIRCUIT).items():
|
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
|
continue
|
||||||
circuit_name = circuit_data[ATTR.NAME]
|
circuit_name = circuit_data[ATTR.NAME]
|
||||||
circuit_interface = INTERFACE(circuit_data[ATTR.INTERFACE])
|
circuit_interface = INTERFACE(circuit_data[ATTR.INTERFACE])
|
||||||
|
@ -43,9 +47,8 @@ async def async_setup_entry(
|
||||||
coordinator,
|
coordinator,
|
||||||
ScreenLogicLightDescription(
|
ScreenLogicLightDescription(
|
||||||
subscription_code=CODE.STATUS_CHANGED,
|
subscription_code=CODE.STATUS_CHANGED,
|
||||||
data_path=(DEVICE.CIRCUIT, circuit_index),
|
data_root=(DEVICE.CIRCUIT,),
|
||||||
key=circuit_index,
|
key=circuit_index,
|
||||||
name=circuit_name,
|
|
||||||
entity_registry_enabled_default=(
|
entity_registry_enabled_default=(
|
||||||
circuit_name not in GENERIC_CIRCUIT_NAMES
|
circuit_name not in GENERIC_CIRCUIT_NAMES
|
||||||
and circuit_interface != INTERFACE.DONT_SHOW
|
and circuit_interface != INTERFACE.DONT_SHOW
|
||||||
|
|
|
@ -4,10 +4,10 @@ from dataclasses import dataclass
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from screenlogicpy.const.data import ATTR, DEVICE, GROUP, VALUE
|
from screenlogicpy.const.data import ATTR, DEVICE, GROUP, VALUE
|
||||||
|
from screenlogicpy.device_const.system import EQUIPMENT_FLAG
|
||||||
|
|
||||||
from homeassistant.components.number import (
|
from homeassistant.components.number import (
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
NumberDeviceClass,
|
|
||||||
NumberEntity,
|
NumberEntity,
|
||||||
NumberEntityDescription,
|
NumberEntityDescription,
|
||||||
)
|
)
|
||||||
|
@ -16,20 +16,10 @@ from homeassistant.const import EntityCategory
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
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 .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 .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__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -37,47 +27,44 @@ PARALLEL_UPDATES = 1
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SupportedNumberValueParametersMixin:
|
class ScreenLogicNumberRequiredMixin:
|
||||||
"""Mixin for supported predefined data for a ScreenLogic number entity."""
|
"""Describes a required mixin for a ScreenLogic number entity."""
|
||||||
|
|
||||||
set_value_config: tuple[str, tuple[tuple[PathPart | str | int, ...], ...]]
|
set_value_name: str
|
||||||
device_class: NumberDeviceClass | None = None
|
set_value_args: tuple[tuple[str | int, ...], ...]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SupportedNumberValueParameters(
|
class ScreenLogicNumberDescription(
|
||||||
SupportedValueParameters, SupportedNumberValueParametersMixin
|
NumberEntityDescription,
|
||||||
|
ScreenLogicEntityDescription,
|
||||||
|
ScreenLogicNumberRequiredMixin,
|
||||||
):
|
):
|
||||||
"""Supported predefined data for a ScreenLogic number entity."""
|
"""Describes a ScreenLogic number entity."""
|
||||||
|
|
||||||
|
|
||||||
SET_SCG_CONFIG_FUNC_DATA = (
|
SUPPORTED_SCG_NUMBERS = [
|
||||||
"async_set_scg_config",
|
ScreenLogicNumberDescription(
|
||||||
(
|
set_value_name="async_set_scg_config",
|
||||||
(DEVICE.SCG, GROUP.CONFIGURATION, VALUE.POOL_SETPOINT),
|
set_value_args=(
|
||||||
(DEVICE.SCG, GROUP.CONFIGURATION, VALUE.SPA_SETPOINT),
|
(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,
|
||||||
),
|
),
|
||||||
)
|
ScreenLogicNumberDescription(
|
||||||
|
set_value_name="async_set_scg_config",
|
||||||
|
set_value_args=(
|
||||||
SUPPORTED_DATA: list[
|
(DEVICE.SCG, GROUP.CONFIGURATION, VALUE.POOL_SETPOINT),
|
||||||
tuple[ScreenLogicDataPath, SupportedValueParameters]
|
(DEVICE.SCG, GROUP.CONFIGURATION, VALUE.SPA_SETPOINT),
|
||||||
] = preprocess_supported_values(
|
),
|
||||||
{
|
data_root=(DEVICE.SCG, GROUP.CONFIGURATION),
|
||||||
DEVICE.SCG: {
|
key=VALUE.SPA_SETPOINT,
|
||||||
GROUP.CONFIGURATION: {
|
entity_category=EntityCategory.CONFIG,
|
||||||
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,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
|
@ -91,70 +78,21 @@ async def async_setup_entry(
|
||||||
config_entry.entry_id
|
config_entry.entry_id
|
||||||
]
|
]
|
||||||
gateway = coordinator.gateway
|
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]
|
for scg_number_description in SUPPORTED_SCG_NUMBERS:
|
||||||
|
scg_number_data_path = (
|
||||||
if not (DEVICE_INCLUSION_RULES.get(device) or value_params.included).test(
|
*scg_number_description.data_root,
|
||||||
gateway, data_path
|
scg_number_description.key,
|
||||||
):
|
|
||||||
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),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
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)
|
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 ScreenLogicNumber(ScreenlogicEntity, NumberEntity):
|
||||||
"""Class to represent a ScreenLogic Number entity."""
|
"""Class to represent a ScreenLogic Number entity."""
|
||||||
|
|
||||||
|
@ -166,9 +104,30 @@ class ScreenLogicNumber(ScreenlogicEntity, NumberEntity):
|
||||||
entity_description: ScreenLogicNumberDescription,
|
entity_description: ScreenLogicNumberDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize a ScreenLogic number entity."""
|
"""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)
|
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
|
@property
|
||||||
def native_value(self) -> float:
|
def native_value(self) -> float:
|
||||||
|
@ -182,12 +141,9 @@ class ScreenLogicNumber(ScreenlogicEntity, NumberEntity):
|
||||||
# gathers the existing values and updates the particular value being
|
# gathers the existing values and updates the particular value being
|
||||||
# set by this entity.
|
# set by this entity.
|
||||||
args = {}
|
args = {}
|
||||||
for data_path in self._set_value_params:
|
for data_path in self._set_value_args:
|
||||||
data_path = realize_path_template(data_path, self._data_path)
|
data_key = data_path[-1]
|
||||||
data_value = data_path[-1]
|
args[data_key] = self.coordinator.gateway.get_value(*data_path, strict=True)
|
||||||
args[data_value] = self.coordinator.gateway.get_value(
|
|
||||||
*data_path, strict=True
|
|
||||||
)
|
|
||||||
|
|
||||||
args[self._data_key] = value
|
args[self._data_key] = value
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
"""Support for a ScreenLogic Sensor."""
|
"""Support for a ScreenLogic Sensor."""
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
|
from copy import copy
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from screenlogicpy.const.common import DEVICE_TYPE, STATE_TYPE
|
|
||||||
from screenlogicpy.const.data import ATTR, DEVICE, GROUP, VALUE
|
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.chemistry import DOSE_STATE
|
||||||
from screenlogicpy.device_const.pump import PUMP_TYPE
|
from screenlogicpy.device_const.pump import PUMP_TYPE
|
||||||
from screenlogicpy.device_const.system import EQUIPMENT_FLAG
|
from screenlogicpy.device_const.system import EQUIPMENT_FLAG
|
||||||
|
@ -17,221 +18,23 @@ from homeassistant.components.sensor import (
|
||||||
SensorStateClass,
|
SensorStateClass,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import EntityCategory
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
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 .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 (
|
from .entity import (
|
||||||
ScreenlogicEntity,
|
ScreenlogicEntity,
|
||||||
ScreenLogicEntityDescription,
|
ScreenLogicEntityDescription,
|
||||||
ScreenLogicPushEntity,
|
ScreenLogicPushEntity,
|
||||||
ScreenLogicPushEntityDescription,
|
ScreenLogicPushEntityDescription,
|
||||||
)
|
)
|
||||||
from .util import cleanup_excluded_entity, generate_unique_id
|
from .util import cleanup_excluded_entity, get_ha_unit
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_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
|
@dataclass
|
||||||
class ScreenLogicSensorMixin:
|
class ScreenLogicSensorMixin:
|
||||||
"""Mixin for SecreenLogic sensor entity."""
|
"""Mixin for SecreenLogic sensor entity."""
|
||||||
|
@ -246,12 +49,265 @@ class ScreenLogicSensorDescription(
|
||||||
"""Describes a ScreenLogic sensor."""
|
"""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):
|
class ScreenLogicSensor(ScreenlogicEntity, SensorEntity):
|
||||||
"""Representation of a ScreenLogic sensor entity."""
|
"""Representation of a ScreenLogic sensor entity."""
|
||||||
|
|
||||||
entity_description: ScreenLogicSensorDescription
|
entity_description: ScreenLogicSensorDescription
|
||||||
_attr_has_entity_name = True
|
_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
|
@property
|
||||||
def native_value(self) -> str | int | float:
|
def native_value(self) -> str | int | float:
|
||||||
"""State of the sensor."""
|
"""State of the sensor."""
|
||||||
|
@ -260,14 +316,29 @@ class ScreenLogicSensor(ScreenlogicEntity, SensorEntity):
|
||||||
return value_mod(val) if value_mod else val
|
return value_mod(val) if value_mod else val
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ScreenLogicPushSensorDescription(
|
|
||||||
ScreenLogicSensorDescription, ScreenLogicPushEntityDescription
|
|
||||||
):
|
|
||||||
"""Describes a ScreenLogic push sensor."""
|
|
||||||
|
|
||||||
|
|
||||||
class ScreenLogicPushSensor(ScreenLogicSensor, ScreenLogicPushEntity):
|
class ScreenLogicPushSensor(ScreenLogicSensor, ScreenLogicPushEntity):
|
||||||
"""Representation of a ScreenLogic push sensor entity."""
|
"""Representation of a ScreenLogic push sensor entity."""
|
||||||
|
|
||||||
entity_description: ScreenLogicPushSensorDescription
|
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
|
gateway = coordinator.gateway
|
||||||
for circuit_index, circuit_data in gateway.get_data(DEVICE.CIRCUIT).items():
|
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
|
continue
|
||||||
circuit_name = circuit_data[ATTR.NAME]
|
circuit_name = circuit_data[ATTR.NAME]
|
||||||
circuit_interface = INTERFACE(circuit_data[ATTR.INTERFACE])
|
circuit_interface = INTERFACE(circuit_data[ATTR.INTERFACE])
|
||||||
|
@ -39,9 +43,8 @@ async def async_setup_entry(
|
||||||
coordinator,
|
coordinator,
|
||||||
ScreenLogicSwitchDescription(
|
ScreenLogicSwitchDescription(
|
||||||
subscription_code=CODE.STATUS_CHANGED,
|
subscription_code=CODE.STATUS_CHANGED,
|
||||||
data_path=(DEVICE.CIRCUIT, circuit_index),
|
data_root=(DEVICE.CIRCUIT,),
|
||||||
key=circuit_index,
|
key=circuit_index,
|
||||||
name=circuit_name,
|
|
||||||
entity_registry_enabled_default=(
|
entity_registry_enabled_default=(
|
||||||
circuit_name not in GENERIC_CIRCUIT_NAMES
|
circuit_name not in GENERIC_CIRCUIT_NAMES
|
||||||
and circuit_interface != INTERFACE.DONT_SHOW
|
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 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
|
from .coordinator import ScreenlogicDataUpdateCoordinator
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def generate_unique_id(
|
def generate_unique_id(*args: str | int | None) -> str:
|
||||||
device: str | int, group: str | int | None, data_key: str | int
|
|
||||||
) -> str:
|
|
||||||
"""Generate new unique_id for a screenlogic entity from specified parameters."""
|
"""Generate new unique_id for a screenlogic entity from specified parameters."""
|
||||||
if data_key in SHARED_VALUES and device is not None:
|
_LOGGER.debug("gen_uid called with %s", args)
|
||||||
if group is not None and (isinstance(group, int) or group.isdigit()):
|
if len(args) == 3:
|
||||||
return f"{device}_{group}_{data_key}"
|
if args[2] in SHARED_VALUES:
|
||||||
return f"{device}_{data_key}"
|
if args[1] is not None and (isinstance(args[1], int) or args[1].isdigit()):
|
||||||
return str(data_key)
|
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(
|
def cleanup_excluded_entity(
|
||||||
coordinator: ScreenlogicDataUpdateCoordinator,
|
coordinator: ScreenlogicDataUpdateCoordinator,
|
||||||
platform_domain: str,
|
platform_domain: str,
|
||||||
entity_key: str,
|
data_path: ScreenLogicDataPath,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Remove excluded entity if it exists."""
|
"""Remove excluded entity if it exists."""
|
||||||
assert coordinator.config_entry
|
assert coordinator.config_entry
|
||||||
entity_registry = er.async_get(coordinator.hass)
|
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(
|
if entity_id := entity_registry.async_get_entity_id(
|
||||||
platform_domain, SL_DOMAIN, unique_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(
|
DATA_FULL_CHEM = num_key_string_to_int(
|
||||||
load_json_object_fixture("screenlogic/data_full_chem.json")
|
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(
|
DATA_MIN_MIGRATION = num_key_string_to_int(
|
||||||
load_json_object_fixture("screenlogic/data_min_migration.json")
|
load_json_object_fixture("screenlogic/data_min_migration.json")
|
||||||
)
|
)
|
||||||
DATA_MIN_ENTITY_CLEANUP = num_key_string_to_int(
|
DATA_MIN_ENTITY_CLEANUP = num_key_string_to_int(
|
||||||
load_json_object_fixture("screenlogic/data_min_entity_cleanup.json")
|
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(
|
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."""
|
"""Tests for ScreenLogic integration data processing."""
|
||||||
from unittest.mock import DEFAULT, patch
|
from unittest.mock import DEFAULT, patch
|
||||||
|
|
||||||
import pytest
|
|
||||||
from screenlogicpy import ScreenLogicGateway
|
from screenlogicpy import ScreenLogicGateway
|
||||||
from screenlogicpy.const.data import ATTR, DEVICE, GROUP, VALUE
|
|
||||||
|
|
||||||
from homeassistant.components.screenlogic import DOMAIN
|
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.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
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)
|
deleted_entity = entity_registry.async_get(unused_entity.entity_id)
|
||||||
assert deleted_entity is None
|
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 screenlogicpy import ScreenLogicGateway
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
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.screenlogic import DOMAIN
|
||||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
@ -14,6 +15,7 @@ from homeassistant.util import slugify
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
DATA_MIN_MIGRATION,
|
DATA_MIN_MIGRATION,
|
||||||
|
DATA_MISSING_VALUES_CHEM_CHLOR,
|
||||||
GATEWAY_DISCOVERY_IMPORT_PATH,
|
GATEWAY_DISCOVERY_IMPORT_PATH,
|
||||||
MOCK_ADAPTER_MAC,
|
MOCK_ADAPTER_MAC,
|
||||||
MOCK_ADAPTER_NAME,
|
MOCK_ADAPTER_NAME,
|
||||||
|
@ -77,6 +79,13 @@ TEST_MIGRATING_ENTITIES = [
|
||||||
"old_sensor",
|
"old_sensor",
|
||||||
SENSOR_DOMAIN,
|
SENSOR_DOMAIN,
|
||||||
),
|
),
|
||||||
|
EntityMigrationData(
|
||||||
|
"Pump Sensor Missing Index",
|
||||||
|
"currentWatts",
|
||||||
|
"Pump Sensor Missing Index",
|
||||||
|
"currentWatts",
|
||||||
|
SENSOR_DOMAIN,
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
MIGRATION_CONNECT = lambda *args, **kwargs: stub_async_connect(
|
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)
|
entity_not_migrated = entity_registry.async_get(old_eid)
|
||||||
assert entity_not_migrated == original_entity
|
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…
Add table
Add a link
Reference in a new issue