Support local push updates for most ScreenLogic entities (#87438)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
4fbb14ecc7
commit
687d326bb4
14 changed files with 352 additions and 252 deletions
|
@ -1008,6 +1008,7 @@ omit =
|
|||
homeassistant/components/screenlogic/__init__.py
|
||||
homeassistant/components/screenlogic/binary_sensor.py
|
||||
homeassistant/components/screenlogic/climate.py
|
||||
homeassistant/components/screenlogic/entity.py
|
||||
homeassistant/components/screenlogic/light.py
|
||||
homeassistant/components/screenlogic/number.py
|
||||
homeassistant/components/screenlogic/sensor.py
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
"""The Screenlogic integration."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from screenlogicpy import ScreenLogicError, ScreenLogicGateway
|
||||
from screenlogicpy.const import (
|
||||
DATA as SL_DATA,
|
||||
EQUIPMENT,
|
||||
ON_OFF,
|
||||
SL_GATEWAY_IP,
|
||||
SL_GATEWAY_NAME,
|
||||
SL_GATEWAY_PORT,
|
||||
|
@ -17,15 +17,8 @@ from homeassistant.config_entries import ConfigEntry
|
|||
from homeassistant.const import CONF_IP_ADDRESS, CONF_PORT, CONF_SCAN_INTERVAL, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.debounce import Debouncer
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.event import async_call_later
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
CoordinatorEntity,
|
||||
DataUpdateCoordinator,
|
||||
UpdateFailed,
|
||||
)
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .config_flow import async_discover_gateways_by_unique_id, name_for_mac
|
||||
from .const import DEFAULT_SCAN_INTERVAL, DOMAIN
|
||||
|
@ -52,12 +45,12 @@ PLATFORMS = [
|
|||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up Screenlogic from a config entry."""
|
||||
gateway = ScreenLogicGateway()
|
||||
|
||||
connect_info = await async_get_connect_info(hass, entry)
|
||||
|
||||
gateway = ScreenLogicGateway(**connect_info)
|
||||
|
||||
try:
|
||||
await gateway.async_connect()
|
||||
await gateway.async_connect(**connect_info)
|
||||
except ScreenLogicError as ex:
|
||||
_LOGGER.error("Error while connecting to the gateway %s: %s", connect_info, ex)
|
||||
raise ConfigEntryNotReady from ex
|
||||
|
@ -119,11 +112,16 @@ async def async_get_connect_info(hass: HomeAssistant, entry: ConfigEntry):
|
|||
class ScreenlogicDataUpdateCoordinator(DataUpdateCoordinator):
|
||||
"""Class to manage the data update for the Screenlogic component."""
|
||||
|
||||
def __init__(self, hass, *, config_entry, gateway):
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
*,
|
||||
config_entry: ConfigEntry,
|
||||
gateway: ScreenLogicGateway,
|
||||
) -> None:
|
||||
"""Initialize the Screenlogic Data Update Coordinator."""
|
||||
self.config_entry = config_entry
|
||||
self.gateway = gateway
|
||||
self.screenlogic_data = {}
|
||||
|
||||
interval = timedelta(
|
||||
seconds=config_entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
|
||||
|
@ -140,17 +138,34 @@ class ScreenlogicDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
),
|
||||
)
|
||||
|
||||
@property
|
||||
def gateway_data(self) -> dict[str | int, Any]:
|
||||
"""Return the gateway data."""
|
||||
return self.gateway.get_data()
|
||||
|
||||
async def _async_update_configured_data(self):
|
||||
"""Update data sets based on equipment config."""
|
||||
equipment_flags = self.gateway.get_data()[SL_DATA.KEY_CONFIG]["equipment_flags"]
|
||||
if not self.gateway.is_client:
|
||||
await self.gateway.async_get_status()
|
||||
if equipment_flags & EQUIPMENT.FLAG_INTELLICHEM:
|
||||
await self.gateway.async_get_chemistry()
|
||||
|
||||
await self.gateway.async_get_pumps()
|
||||
if equipment_flags & EQUIPMENT.FLAG_CHLORINATOR:
|
||||
await self.gateway.async_get_scg()
|
||||
|
||||
async def _async_update_data(self):
|
||||
"""Fetch data from the Screenlogic gateway."""
|
||||
try:
|
||||
await self.gateway.async_update()
|
||||
await self._async_update_configured_data()
|
||||
except ScreenLogicError as error:
|
||||
_LOGGER.warning("Update error - attempting reconnect: %s", error)
|
||||
await self._async_reconnect_update_data()
|
||||
except ScreenLogicWarning as warn:
|
||||
raise UpdateFailed(f"Incomplete update: {warn}") from warn
|
||||
|
||||
return self.gateway.get_data()
|
||||
return None
|
||||
|
||||
async def _async_reconnect_update_data(self):
|
||||
"""Attempt to reconnect to the gateway and fetch data."""
|
||||
|
@ -159,125 +174,9 @@ class ScreenlogicDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
await self.gateway.async_disconnect()
|
||||
|
||||
connect_info = await async_get_connect_info(self.hass, self.config_entry)
|
||||
self.gateway = ScreenLogicGateway(**connect_info)
|
||||
await self.gateway.async_connect(**connect_info)
|
||||
|
||||
await self.gateway.async_update()
|
||||
await self._async_update_configured_data()
|
||||
|
||||
except (ScreenLogicError, ScreenLogicWarning) as ex:
|
||||
raise UpdateFailed(ex) from ex
|
||||
|
||||
|
||||
class ScreenlogicEntity(CoordinatorEntity[ScreenlogicDataUpdateCoordinator]):
|
||||
"""Base class for all ScreenLogic entities."""
|
||||
|
||||
def __init__(self, coordinator, data_key, enabled=True):
|
||||
"""Initialize of the entity."""
|
||||
super().__init__(coordinator)
|
||||
self._data_key = data_key
|
||||
self._enabled_default = enabled
|
||||
|
||||
@property
|
||||
def entity_registry_enabled_default(self):
|
||||
"""Entity enabled by default."""
|
||||
return self._enabled_default
|
||||
|
||||
@property
|
||||
def mac(self):
|
||||
"""Mac address."""
|
||||
return self.coordinator.config_entry.unique_id
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Entity Unique ID."""
|
||||
return f"{self.mac}_{self._data_key}"
|
||||
|
||||
@property
|
||||
def config_data(self):
|
||||
"""Shortcut for config data."""
|
||||
return self.coordinator.data["config"]
|
||||
|
||||
@property
|
||||
def gateway(self):
|
||||
"""Return the gateway."""
|
||||
return self.coordinator.gateway
|
||||
|
||||
@property
|
||||
def gateway_name(self):
|
||||
"""Return the configured name of the gateway."""
|
||||
return self.gateway.name
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return device information for the controller."""
|
||||
controller_type = self.config_data["controller_type"]
|
||||
hardware_type = self.config_data["hardware_type"]
|
||||
try:
|
||||
equipment_model = EQUIPMENT.CONTROLLER_HARDWARE[controller_type][
|
||||
hardware_type
|
||||
]
|
||||
except KeyError:
|
||||
equipment_model = f"Unknown Model C:{controller_type} H:{hardware_type}"
|
||||
return DeviceInfo(
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, self.mac)},
|
||||
manufacturer="Pentair",
|
||||
model=equipment_model,
|
||||
name=self.gateway_name,
|
||||
sw_version=self.gateway.version,
|
||||
)
|
||||
|
||||
async def _async_refresh(self):
|
||||
"""Refresh the data from the gateway."""
|
||||
await self.coordinator.async_refresh()
|
||||
# Second debounced refresh to catch any secondary
|
||||
# changes in the device
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
async def _async_refresh_timed(self, now):
|
||||
"""Refresh from a timed called."""
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
|
||||
class ScreenLogicCircuitEntity(ScreenlogicEntity):
|
||||
"""ScreenLogic circuit entity."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Get the name of the switch."""
|
||||
return self.circuit["name"]
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Get whether the switch is in on state."""
|
||||
return self.circuit["value"] == ON_OFF.ON
|
||||
|
||||
async def async_turn_on(self, **kwargs) -> None:
|
||||
"""Send the ON command."""
|
||||
await self._async_set_circuit(ON_OFF.ON)
|
||||
|
||||
async def async_turn_off(self, **kwargs) -> None:
|
||||
"""Send the OFF command."""
|
||||
await self._async_set_circuit(ON_OFF.OFF)
|
||||
|
||||
# Turning off spa or pool circuit may require more time for the
|
||||
# heater to reflect changes depending on the pool controller,
|
||||
# so we schedule an extra refresh a bit farther out
|
||||
if self._data_key in PRIMARY_CIRCUIT_IDS:
|
||||
async_call_later(
|
||||
self.hass, HEATER_COOLDOWN_DELAY, self._async_refresh_timed
|
||||
)
|
||||
|
||||
async def _async_set_circuit(self, circuit_value) -> None:
|
||||
if await self.gateway.async_set_circuit(self._data_key, circuit_value):
|
||||
_LOGGER.debug("Turn %s %s", self._data_key, circuit_value)
|
||||
await self._async_refresh()
|
||||
else:
|
||||
_LOGGER.warning(
|
||||
"Failed to set_circuit %s %s", self._data_key, circuit_value
|
||||
)
|
||||
|
||||
@property
|
||||
def circuit(self):
|
||||
"""Shortcut to access the circuit."""
|
||||
return self.coordinator.data[SL_DATA.KEY_CIRCUITS][self._data_key]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""Support for a ScreenLogic Binary Sensor."""
|
||||
from screenlogicpy.const import DATA as SL_DATA, DEVICE_TYPE, EQUIPMENT, ON_OFF
|
||||
from screenlogicpy.const import CODE, DATA as SL_DATA, DEVICE_TYPE, EQUIPMENT, ON_OFF
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
BinarySensorDeviceClass,
|
||||
|
@ -10,8 +10,9 @@ from homeassistant.core import HomeAssistant
|
|||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import ScreenlogicEntity
|
||||
from . import ScreenlogicDataUpdateCoordinator
|
||||
from .const import DOMAIN
|
||||
from .entity import ScreenlogicEntity, ScreenLogicPushEntity
|
||||
|
||||
SL_DEVICE_TYPE_TO_HA_DEVICE_CLASS = {DEVICE_TYPE.ALARM: BinarySensorDeviceClass.PROBLEM}
|
||||
|
||||
|
@ -29,69 +30,70 @@ async def async_setup_entry(
|
|||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up entry."""
|
||||
entities = []
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
entities: list[ScreenLogicBinarySensorEntity] = []
|
||||
coordinator: ScreenlogicDataUpdateCoordinator = hass.data[DOMAIN][
|
||||
config_entry.entry_id
|
||||
]
|
||||
gateway_data = coordinator.gateway_data
|
||||
chemistry = gateway_data[SL_DATA.KEY_CHEMISTRY]
|
||||
config = gateway_data[SL_DATA.KEY_CONFIG]
|
||||
|
||||
# Generic binary sensor
|
||||
entities.append(ScreenLogicBinarySensor(coordinator, "chem_alarm"))
|
||||
entities.append(
|
||||
ScreenLogicStatusBinarySensor(coordinator, "chem_alarm", CODE.STATUS_CHANGED)
|
||||
)
|
||||
|
||||
entities.extend(
|
||||
[
|
||||
ScreenlogicConfigBinarySensor(coordinator, cfg_sensor)
|
||||
for cfg_sensor in coordinator.data[SL_DATA.KEY_CONFIG]
|
||||
ScreenlogicConfigBinarySensor(coordinator, cfg_sensor, CODE.STATUS_CHANGED)
|
||||
for cfg_sensor in config
|
||||
if cfg_sensor in SUPPORTED_CONFIG_BINARY_SENSORS
|
||||
]
|
||||
)
|
||||
|
||||
if (
|
||||
coordinator.data[SL_DATA.KEY_CONFIG]["equipment_flags"]
|
||||
& EQUIPMENT.FLAG_INTELLICHEM
|
||||
):
|
||||
if config["equipment_flags"] & EQUIPMENT.FLAG_INTELLICHEM:
|
||||
# IntelliChem alarm sensors
|
||||
entities.extend(
|
||||
[
|
||||
ScreenlogicChemistryAlarmBinarySensor(coordinator, chem_alarm)
|
||||
for chem_alarm in coordinator.data[SL_DATA.KEY_CHEMISTRY][
|
||||
SL_DATA.KEY_ALERTS
|
||||
]
|
||||
if chem_alarm != "_raw"
|
||||
ScreenlogicChemistryAlarmBinarySensor(
|
||||
coordinator, chem_alarm, CODE.CHEMISTRY_CHANGED
|
||||
)
|
||||
for chem_alarm in chemistry[SL_DATA.KEY_ALERTS]
|
||||
if not chem_alarm.startswith("_")
|
||||
]
|
||||
)
|
||||
|
||||
# Intellichem notification sensors
|
||||
entities.extend(
|
||||
[
|
||||
ScreenlogicChemistryNotificationBinarySensor(coordinator, chem_notif)
|
||||
for chem_notif in coordinator.data[SL_DATA.KEY_CHEMISTRY][
|
||||
SL_DATA.KEY_NOTIFICATIONS
|
||||
]
|
||||
if chem_notif != "_raw"
|
||||
ScreenlogicChemistryNotificationBinarySensor(
|
||||
coordinator, chem_notif, CODE.CHEMISTRY_CHANGED
|
||||
)
|
||||
for chem_notif in chemistry[SL_DATA.KEY_NOTIFICATIONS]
|
||||
if not chem_notif.startswith("_")
|
||||
]
|
||||
)
|
||||
|
||||
if (
|
||||
coordinator.data[SL_DATA.KEY_CONFIG]["equipment_flags"]
|
||||
& EQUIPMENT.FLAG_CHLORINATOR
|
||||
):
|
||||
if config["equipment_flags"] & EQUIPMENT.FLAG_CHLORINATOR:
|
||||
# SCG binary sensor
|
||||
entities.append(ScreenlogicSCGBinarySensor(coordinator, "scg_status"))
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class ScreenLogicBinarySensor(ScreenlogicEntity, BinarySensorEntity):
|
||||
"""Representation of the basic ScreenLogic binary sensor entity."""
|
||||
class ScreenLogicBinarySensorEntity(ScreenlogicEntity, BinarySensorEntity):
|
||||
"""Base class for all ScreenLogic binary sensor entities."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
def name(self) -> str | None:
|
||||
"""Return the sensor name."""
|
||||
return self.sensor["name"]
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
def device_class(self) -> BinarySensorDeviceClass | None:
|
||||
"""Return the device class."""
|
||||
device_type = self.sensor.get("device_type")
|
||||
return SL_DEVICE_TYPE_TO_HA_DEVICE_CLASS.get(device_type)
|
||||
|
@ -102,46 +104,58 @@ class ScreenLogicBinarySensor(ScreenlogicEntity, BinarySensorEntity):
|
|||
return self.sensor["value"] == ON_OFF.ON
|
||||
|
||||
@property
|
||||
def sensor(self):
|
||||
def sensor(self) -> dict:
|
||||
"""Shortcut to access the sensor data."""
|
||||
return self.coordinator.data[SL_DATA.KEY_SENSORS][self._data_key]
|
||||
return self.gateway_data[SL_DATA.KEY_SENSORS][self._data_key]
|
||||
|
||||
|
||||
class ScreenlogicChemistryAlarmBinarySensor(ScreenLogicBinarySensor):
|
||||
class ScreenLogicStatusBinarySensor(
|
||||
ScreenLogicBinarySensorEntity, ScreenLogicPushEntity
|
||||
):
|
||||
"""Representation of a basic ScreenLogic sensor entity."""
|
||||
|
||||
|
||||
class ScreenlogicChemistryAlarmBinarySensor(
|
||||
ScreenLogicBinarySensorEntity, ScreenLogicPushEntity
|
||||
):
|
||||
"""Representation of a ScreenLogic IntelliChem alarm binary sensor entity."""
|
||||
|
||||
@property
|
||||
def sensor(self):
|
||||
def sensor(self) -> dict:
|
||||
"""Shortcut to access the sensor data."""
|
||||
return self.coordinator.data[SL_DATA.KEY_CHEMISTRY][SL_DATA.KEY_ALERTS][
|
||||
return self.gateway_data[SL_DATA.KEY_CHEMISTRY][SL_DATA.KEY_ALERTS][
|
||||
self._data_key
|
||||
]
|
||||
|
||||
|
||||
class ScreenlogicChemistryNotificationBinarySensor(ScreenLogicBinarySensor):
|
||||
class ScreenlogicChemistryNotificationBinarySensor(
|
||||
ScreenLogicBinarySensorEntity, ScreenLogicPushEntity
|
||||
):
|
||||
"""Representation of a ScreenLogic IntelliChem notification binary sensor entity."""
|
||||
|
||||
@property
|
||||
def sensor(self):
|
||||
def sensor(self) -> dict:
|
||||
"""Shortcut to access the sensor data."""
|
||||
return self.coordinator.data[SL_DATA.KEY_CHEMISTRY][SL_DATA.KEY_NOTIFICATIONS][
|
||||
return self.gateway_data[SL_DATA.KEY_CHEMISTRY][SL_DATA.KEY_NOTIFICATIONS][
|
||||
self._data_key
|
||||
]
|
||||
|
||||
|
||||
class ScreenlogicSCGBinarySensor(ScreenLogicBinarySensor):
|
||||
class ScreenlogicSCGBinarySensor(ScreenLogicBinarySensorEntity):
|
||||
"""Representation of a ScreenLogic SCG binary sensor entity."""
|
||||
|
||||
@property
|
||||
def sensor(self):
|
||||
def sensor(self) -> dict:
|
||||
"""Shortcut to access the sensor data."""
|
||||
return self.coordinator.data[SL_DATA.KEY_SCG][self._data_key]
|
||||
return self.gateway_data[SL_DATA.KEY_SCG][self._data_key]
|
||||
|
||||
|
||||
class ScreenlogicConfigBinarySensor(ScreenLogicBinarySensor):
|
||||
class ScreenlogicConfigBinarySensor(
|
||||
ScreenLogicBinarySensorEntity, ScreenLogicPushEntity
|
||||
):
|
||||
"""Representation of a ScreenLogic config data binary sensor entity."""
|
||||
|
||||
@property
|
||||
def sensor(self):
|
||||
def sensor(self) -> dict:
|
||||
"""Shortcut to access the sensor data."""
|
||||
return self.coordinator.data[SL_DATA.KEY_CONFIG][self._data_key]
|
||||
return self.gateway_data[SL_DATA.KEY_CONFIG][self._data_key]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import logging
|
||||
from typing import Any
|
||||
|
||||
from screenlogicpy.const import DATA as SL_DATA, EQUIPMENT, HEAT_MODE
|
||||
from screenlogicpy.const import CODE, DATA as SL_DATA, EQUIPMENT, HEAT_MODE
|
||||
|
||||
from homeassistant.components.climate import (
|
||||
ATTR_PRESET_MODE,
|
||||
|
@ -18,8 +18,9 @@ from homeassistant.exceptions import HomeAssistantError
|
|||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
|
||||
from . import ScreenlogicEntity
|
||||
from . import ScreenlogicDataUpdateCoordinator
|
||||
from .const import DOMAIN
|
||||
from .entity import ScreenLogicPushEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -40,15 +41,17 @@ async def async_setup_entry(
|
|||
) -> None:
|
||||
"""Set up entry."""
|
||||
entities = []
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
coordinator: ScreenlogicDataUpdateCoordinator = hass.data[DOMAIN][
|
||||
config_entry.entry_id
|
||||
]
|
||||
|
||||
for body in coordinator.data[SL_DATA.KEY_BODIES]:
|
||||
for body in coordinator.gateway_data[SL_DATA.KEY_BODIES]:
|
||||
entities.append(ScreenLogicClimate(coordinator, body))
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class ScreenLogicClimate(ScreenlogicEntity, ClimateEntity, RestoreEntity):
|
||||
class ScreenLogicClimate(ScreenLogicPushEntity, ClimateEntity, RestoreEntity):
|
||||
"""Represents a ScreenLogic climate entity."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
@ -60,10 +63,10 @@ class ScreenLogicClimate(ScreenlogicEntity, ClimateEntity, RestoreEntity):
|
|||
|
||||
def __init__(self, coordinator, body):
|
||||
"""Initialize a ScreenLogic climate entity."""
|
||||
super().__init__(coordinator, body)
|
||||
super().__init__(coordinator, body, CODE.STATUS_CHANGED)
|
||||
self._configured_heat_modes = []
|
||||
# Is solar listed as available equipment?
|
||||
if self.coordinator.data["config"]["equipment_flags"] & EQUIPMENT.FLAG_SOLAR:
|
||||
if self.gateway_data["config"]["equipment_flags"] & EQUIPMENT.FLAG_SOLAR:
|
||||
self._configured_heat_modes.extend(
|
||||
[HEAT_MODE.SOLAR, HEAT_MODE.SOLAR_PREFERRED]
|
||||
)
|
||||
|
@ -126,7 +129,7 @@ class ScreenLogicClimate(ScreenlogicEntity, ClimateEntity, RestoreEntity):
|
|||
return HEAT_MODE.NAME_FOR_NUM[self.body["heat_mode"]["value"]]
|
||||
|
||||
@property
|
||||
def preset_modes(self):
|
||||
def preset_modes(self) -> list[str]:
|
||||
"""All available presets."""
|
||||
return [
|
||||
HEAT_MODE.NAME_FOR_NUM[mode_num] for mode_num in self._configured_heat_modes
|
||||
|
@ -137,15 +140,14 @@ class ScreenLogicClimate(ScreenlogicEntity, ClimateEntity, RestoreEntity):
|
|||
if (temperature := kwargs.get(ATTR_TEMPERATURE)) is None:
|
||||
raise ValueError(f"Expected attribute {ATTR_TEMPERATURE}")
|
||||
|
||||
if await self.gateway.async_set_heat_temp(
|
||||
if not await self.gateway.async_set_heat_temp(
|
||||
int(self._data_key), int(temperature)
|
||||
):
|
||||
await self._async_refresh()
|
||||
else:
|
||||
raise HomeAssistantError(
|
||||
f"Failed to set_temperature {temperature} on body"
|
||||
f" {self.body['body_type']['value']}"
|
||||
)
|
||||
_LOGGER.debug("Set temperature for body %s to %s", self._data_key, temperature)
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the operation mode."""
|
||||
|
@ -154,13 +156,12 @@ class ScreenLogicClimate(ScreenlogicEntity, ClimateEntity, RestoreEntity):
|
|||
else:
|
||||
mode = HEAT_MODE.NUM_FOR_NAME[self.preset_mode]
|
||||
|
||||
if await self.gateway.async_set_heat_mode(int(self._data_key), int(mode)):
|
||||
await self._async_refresh()
|
||||
else:
|
||||
if not await self.gateway.async_set_heat_mode(int(self._data_key), int(mode)):
|
||||
raise HomeAssistantError(
|
||||
f"Failed to set_hvac_mode {mode} on body"
|
||||
f" {self.body['body_type']['value']}"
|
||||
)
|
||||
_LOGGER.debug("Set hvac_mode on body %s to %s", self._data_key, mode)
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set the preset mode."""
|
||||
|
@ -169,13 +170,12 @@ class ScreenLogicClimate(ScreenlogicEntity, ClimateEntity, RestoreEntity):
|
|||
if self.hvac_mode == HVACMode.OFF:
|
||||
return
|
||||
|
||||
if await self.gateway.async_set_heat_mode(int(self._data_key), int(mode)):
|
||||
await self._async_refresh()
|
||||
else:
|
||||
if not await self.gateway.async_set_heat_mode(int(self._data_key), int(mode)):
|
||||
raise HomeAssistantError(
|
||||
f"Failed to set_preset_mode {mode} on body"
|
||||
f" {self.body['body_type']['value']}"
|
||||
)
|
||||
_LOGGER.debug("Set preset_mode on body %s to %s", self._data_key, mode)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Run when entity is about to be added."""
|
||||
|
@ -206,4 +206,4 @@ class ScreenLogicClimate(ScreenlogicEntity, ClimateEntity, RestoreEntity):
|
|||
@property
|
||||
def body(self):
|
||||
"""Shortcut to access body data."""
|
||||
return self.coordinator.data[SL_DATA.KEY_BODIES][self._data_key]
|
||||
return self.gateway_data[SL_DATA.KEY_BODIES][self._data_key]
|
||||
|
|
|
@ -19,6 +19,6 @@ async def async_get_config_entry_diagnostics(
|
|||
|
||||
return {
|
||||
"config_entry": config_entry.as_dict(),
|
||||
"data": coordinator.data,
|
||||
"data": coordinator.gateway.get_data(),
|
||||
"debug": coordinator.gateway.get_debug(),
|
||||
}
|
||||
|
|
138
homeassistant/components/screenlogic/entity.py
Normal file
138
homeassistant/components/screenlogic/entity.py
Normal file
|
@ -0,0 +1,138 @@
|
|||
"""Base ScreenLogicEntity definitions."""
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
# from screenlogicpy import ScreenLogicError, ScreenLogicGateway
|
||||
from screenlogicpy.const import DATA as SL_DATA, EQUIPMENT, ON_OFF
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from . import ScreenlogicDataUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ScreenlogicEntity(CoordinatorEntity[ScreenlogicDataUpdateCoordinator]):
|
||||
"""Base class for all ScreenLogic entities."""
|
||||
|
||||
def __init__(self, coordinator, data_key, enabled=True):
|
||||
"""Initialize of the entity."""
|
||||
super().__init__(coordinator)
|
||||
self._data_key = data_key
|
||||
self._attr_entity_registry_enabled_default = enabled
|
||||
self._attr_unique_id = f"{self.mac}_{self._data_key}"
|
||||
|
||||
controller_type = self.config_data["controller_type"]
|
||||
hardware_type = self.config_data["hardware_type"]
|
||||
try:
|
||||
equipment_model = EQUIPMENT.CONTROLLER_HARDWARE[controller_type][
|
||||
hardware_type
|
||||
]
|
||||
except KeyError:
|
||||
equipment_model = f"Unknown Model C:{controller_type} H:{hardware_type}"
|
||||
self._attr_device_info = DeviceInfo(
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, self.mac)},
|
||||
manufacturer="Pentair",
|
||||
model=equipment_model,
|
||||
name=self.gateway_name,
|
||||
sw_version=self.gateway.version,
|
||||
)
|
||||
|
||||
@property
|
||||
def mac(self):
|
||||
"""Mac address."""
|
||||
return self.coordinator.config_entry.unique_id
|
||||
|
||||
@property
|
||||
def config_data(self):
|
||||
"""Shortcut for config data."""
|
||||
return self.gateway_data[SL_DATA.KEY_CONFIG]
|
||||
|
||||
@property
|
||||
def gateway(self):
|
||||
"""Return the gateway."""
|
||||
return self.coordinator.gateway
|
||||
|
||||
@property
|
||||
def gateway_data(self) -> dict[str | int, Any]:
|
||||
"""Return the gateway data."""
|
||||
return self.gateway.get_data()
|
||||
|
||||
@property
|
||||
def gateway_name(self):
|
||||
"""Return the configured name of the gateway."""
|
||||
return self.gateway.name
|
||||
|
||||
async def _async_refresh(self):
|
||||
"""Refresh the data from the gateway."""
|
||||
await self.coordinator.async_refresh()
|
||||
# Second debounced refresh to catch any secondary
|
||||
# changes in the device
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
async def _async_refresh_timed(self, now):
|
||||
"""Refresh from a timed called."""
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
|
||||
class ScreenLogicPushEntity(ScreenlogicEntity):
|
||||
"""Base class for all ScreenLogic push entities."""
|
||||
|
||||
def __init__(self, coordinator, data_key, message_code, enabled=True):
|
||||
"""Initialize the entity."""
|
||||
super().__init__(coordinator, data_key, enabled)
|
||||
self._update_message_code = message_code
|
||||
|
||||
@callback
|
||||
def _async_data_updated(self) -> None:
|
||||
"""Handle data updates."""
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""When entity is added to hass."""
|
||||
|
||||
self.async_on_remove(
|
||||
await self.gateway.async_subscribe_client(
|
||||
self._async_data_updated, self._update_message_code
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class ScreenLogicCircuitEntity(ScreenLogicPushEntity):
|
||||
"""Base class for all ScreenLogic switch and light entities."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Get the name of the switch."""
|
||||
return self.circuit["name"]
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Get whether the switch is in on state."""
|
||||
return self.circuit["value"] == ON_OFF.ON
|
||||
|
||||
async def async_turn_on(self, **kwargs) -> None:
|
||||
"""Send the ON command."""
|
||||
await self._async_set_circuit(ON_OFF.ON)
|
||||
|
||||
async def async_turn_off(self, **kwargs) -> None:
|
||||
"""Send the OFF command."""
|
||||
await self._async_set_circuit(ON_OFF.OFF)
|
||||
|
||||
async def _async_set_circuit(self, circuit_value) -> None:
|
||||
if not await self.gateway.async_set_circuit(self._data_key, circuit_value):
|
||||
raise HomeAssistantError(
|
||||
f"Failed to set_circuit {self._data_key} {circuit_value}"
|
||||
)
|
||||
_LOGGER.debug("Turn %s %s", self._data_key, circuit_value)
|
||||
|
||||
@property
|
||||
def circuit(self) -> dict[str | int, Any]:
|
||||
"""Shortcut to access the circuit."""
|
||||
return self.gateway_data[SL_DATA.KEY_CIRCUITS][self._data_key]
|
|
@ -1,15 +1,16 @@
|
|||
"""Support for a ScreenLogic light 'circuit' switch."""
|
||||
import logging
|
||||
|
||||
from screenlogicpy.const import DATA as SL_DATA, GENERIC_CIRCUIT_NAMES
|
||||
from screenlogicpy.const import CODE, DATA as SL_DATA, GENERIC_CIRCUIT_NAMES
|
||||
|
||||
from homeassistant.components.light import ColorMode, LightEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import ScreenLogicCircuitEntity
|
||||
from . import ScreenlogicDataUpdateCoordinator
|
||||
from .const import DOMAIN, LIGHT_CIRCUIT_FUNCTIONS
|
||||
from .entity import ScreenLogicCircuitEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -20,13 +21,19 @@ async def async_setup_entry(
|
|||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up entry."""
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
coordinator: ScreenlogicDataUpdateCoordinator = hass.data[DOMAIN][
|
||||
config_entry.entry_id
|
||||
]
|
||||
circuits = coordinator.gateway_data[SL_DATA.KEY_CIRCUITS]
|
||||
async_add_entities(
|
||||
[
|
||||
ScreenLogicLight(
|
||||
coordinator, circuit_num, circuit["name"] not in GENERIC_CIRCUIT_NAMES
|
||||
coordinator,
|
||||
circuit_num,
|
||||
CODE.STATUS_CHANGED,
|
||||
circuit["name"] not in GENERIC_CIRCUIT_NAMES,
|
||||
)
|
||||
for circuit_num, circuit in coordinator.data[SL_DATA.KEY_CIRCUITS].items()
|
||||
for circuit_num, circuit in circuits.items()
|
||||
if circuit["function"] in LIGHT_CIRCUIT_FUNCTIONS
|
||||
]
|
||||
)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Pentair ScreenLogic",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/screenlogic",
|
||||
"requirements": ["screenlogicpy==0.6.4"],
|
||||
"requirements": ["screenlogicpy==0.7.0"],
|
||||
"codeowners": ["@dieselrabbit", "@bdraco"],
|
||||
"dhcp": [
|
||||
{ "registered_devices": true },
|
||||
|
@ -12,6 +12,6 @@
|
|||
"macaddress": "00C033*"
|
||||
}
|
||||
],
|
||||
"iot_class": "local_polling",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["screenlogicpy"]
|
||||
}
|
||||
|
|
|
@ -9,8 +9,9 @@ from homeassistant.core import HomeAssistant
|
|||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import ScreenlogicEntity
|
||||
from . import ScreenlogicDataUpdateCoordinator
|
||||
from .const import DOMAIN
|
||||
from .entity import ScreenlogicEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -28,13 +29,15 @@ async def async_setup_entry(
|
|||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up entry."""
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
equipment_flags = coordinator.data[SL_DATA.KEY_CONFIG]["equipment_flags"]
|
||||
coordinator: ScreenlogicDataUpdateCoordinator = hass.data[DOMAIN][
|
||||
config_entry.entry_id
|
||||
]
|
||||
equipment_flags = coordinator.gateway_data[SL_DATA.KEY_CONFIG]["equipment_flags"]
|
||||
if equipment_flags & EQUIPMENT.FLAG_CHLORINATOR:
|
||||
async_add_entities(
|
||||
[
|
||||
ScreenLogicNumber(coordinator, scg_level)
|
||||
for scg_level in coordinator.data[SL_DATA.KEY_SCG]
|
||||
for scg_level in coordinator.gateway_data[SL_DATA.KEY_SCG]
|
||||
if scg_level in SUPPORTED_SCG_NUMBERS
|
||||
]
|
||||
)
|
||||
|
@ -65,7 +68,7 @@ class ScreenLogicNumber(ScreenlogicEntity, NumberEntity):
|
|||
# both existing level values and override the one that changed.
|
||||
levels = {}
|
||||
for level in SUPPORTED_SCG_NUMBERS:
|
||||
levels[level] = self.coordinator.data[SL_DATA.KEY_SCG][level]["value"]
|
||||
levels[level] = self.gateway_data[SL_DATA.KEY_SCG][level]["value"]
|
||||
levels[self._data_key] = int(value)
|
||||
|
||||
if await self.coordinator.gateway.async_set_scg_config(
|
||||
|
@ -88,4 +91,4 @@ class ScreenLogicNumber(ScreenlogicEntity, NumberEntity):
|
|||
@property
|
||||
def sensor(self) -> dict:
|
||||
"""Shortcut to access the level sensor data."""
|
||||
return self.coordinator.data[SL_DATA.KEY_SCG][self._data_key]
|
||||
return self.gateway_data[SL_DATA.KEY_SCG][self._data_key]
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
"""Support for a ScreenLogic Sensor."""
|
||||
from typing import Any
|
||||
|
||||
from screenlogicpy.const import (
|
||||
CHEM_DOSING_STATE,
|
||||
CODE,
|
||||
DATA as SL_DATA,
|
||||
DEVICE_TYPE,
|
||||
EQUIPMENT,
|
||||
STATE_TYPE,
|
||||
UNIT,
|
||||
)
|
||||
|
||||
|
@ -26,8 +30,9 @@ from homeassistant.core import HomeAssistant
|
|||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import ScreenlogicEntity
|
||||
from . import ScreenlogicDataUpdateCoordinator
|
||||
from .const import DOMAIN
|
||||
from .entity import ScreenlogicEntity, ScreenLogicPushEntity
|
||||
|
||||
SUPPORTED_BASIC_SENSORS = (
|
||||
"air_temperature",
|
||||
|
@ -68,12 +73,18 @@ SUPPORTED_PUMP_SENSORS = ("currentWatts", "currentRPM", "currentGPM")
|
|||
|
||||
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,
|
||||
}
|
||||
|
||||
SL_UNIT_TO_HA_UNIT = {
|
||||
UNIT.CELSIUS: UnitOfTemperature.CELSIUS,
|
||||
UNIT.FAHRENHEIT: UnitOfTemperature.FAHRENHEIT,
|
||||
|
@ -93,14 +104,18 @@ async def async_setup_entry(
|
|||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up entry."""
|
||||
entities = []
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
equipment_flags = coordinator.data[SL_DATA.KEY_CONFIG]["equipment_flags"]
|
||||
entities: list[ScreenLogicSensorEntity] = []
|
||||
coordinator: ScreenlogicDataUpdateCoordinator = hass.data[DOMAIN][
|
||||
config_entry.entry_id
|
||||
]
|
||||
equipment_flags = coordinator.gateway_data[SL_DATA.KEY_CONFIG]["equipment_flags"]
|
||||
|
||||
# Generic sensors
|
||||
for sensor_name in coordinator.data[SL_DATA.KEY_SENSORS]:
|
||||
# Generic push sensors
|
||||
for sensor_name in coordinator.gateway_data[SL_DATA.KEY_SENSORS]:
|
||||
if sensor_name in SUPPORTED_BASIC_SENSORS:
|
||||
entities.append(ScreenLogicSensor(coordinator, sensor_name))
|
||||
entities.append(
|
||||
ScreenLogicStatusSensor(coordinator, sensor_name, CODE.STATUS_CHANGED)
|
||||
)
|
||||
|
||||
# While these values exist in the chemistry data, their last value doesn't
|
||||
# persist there when the pump is off/there is no flow. Pulling them from
|
||||
|
@ -109,10 +124,12 @@ async def async_setup_entry(
|
|||
equipment_flags & EQUIPMENT.FLAG_INTELLICHEM
|
||||
and sensor_name in SUPPORTED_BASIC_CHEM_SENSORS
|
||||
):
|
||||
entities.append(ScreenLogicSensor(coordinator, sensor_name))
|
||||
entities.append(
|
||||
ScreenLogicStatusSensor(coordinator, sensor_name, CODE.STATUS_CHANGED)
|
||||
)
|
||||
|
||||
# Pump sensors
|
||||
for pump_num, pump_data in coordinator.data[SL_DATA.KEY_PUMPS].items():
|
||||
for pump_num, pump_data in coordinator.gateway_data[SL_DATA.KEY_PUMPS].items():
|
||||
if pump_data["data"] != 0 and "currentWatts" in pump_data:
|
||||
for pump_key in pump_data:
|
||||
enabled = True
|
||||
|
@ -129,14 +146,16 @@ async def async_setup_entry(
|
|||
|
||||
# IntelliChem sensors
|
||||
if equipment_flags & EQUIPMENT.FLAG_INTELLICHEM:
|
||||
for chem_sensor_name in coordinator.data[SL_DATA.KEY_CHEMISTRY]:
|
||||
for chem_sensor_name in coordinator.gateway_data[SL_DATA.KEY_CHEMISTRY]:
|
||||
enabled = True
|
||||
if equipment_flags & EQUIPMENT.FLAG_CHLORINATOR:
|
||||
if chem_sensor_name in ("salt_tds_ppm",):
|
||||
enabled = False
|
||||
if chem_sensor_name in SUPPORTED_CHEM_SENSORS:
|
||||
entities.append(
|
||||
ScreenLogicChemistrySensor(coordinator, chem_sensor_name, enabled)
|
||||
ScreenLogicChemistrySensor(
|
||||
coordinator, chem_sensor_name, CODE.CHEMISTRY_CHANGED, enabled
|
||||
)
|
||||
)
|
||||
|
||||
# SCG sensors
|
||||
|
@ -144,7 +163,7 @@ async def async_setup_entry(
|
|||
entities.extend(
|
||||
[
|
||||
ScreenLogicSCGSensor(coordinator, scg_sensor)
|
||||
for scg_sensor in coordinator.data[SL_DATA.KEY_SCG]
|
||||
for scg_sensor in coordinator.gateway_data[SL_DATA.KEY_SCG]
|
||||
if scg_sensor in SUPPORTED_SCG_SENSORS
|
||||
]
|
||||
)
|
||||
|
@ -152,54 +171,66 @@ async def async_setup_entry(
|
|||
async_add_entities(entities)
|
||||
|
||||
|
||||
class ScreenLogicSensor(ScreenlogicEntity, SensorEntity):
|
||||
"""Representation of the basic ScreenLogic sensor entity."""
|
||||
class ScreenLogicSensorEntity(ScreenlogicEntity, SensorEntity):
|
||||
"""Base class for all ScreenLogic sensor entities."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
def name(self) -> str | None:
|
||||
"""Name of the sensor."""
|
||||
return self.sensor["name"]
|
||||
|
||||
@property
|
||||
def native_unit_of_measurement(self):
|
||||
def native_unit_of_measurement(self) -> str | None:
|
||||
"""Return the unit of measurement."""
|
||||
sl_unit = self.sensor.get("unit")
|
||||
return SL_UNIT_TO_HA_UNIT.get(sl_unit, sl_unit)
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
def device_class(self) -> SensorDeviceClass | None:
|
||||
"""Device class of the sensor."""
|
||||
device_type = self.sensor.get("device_type")
|
||||
return SL_DEVICE_TYPE_TO_HA_DEVICE_CLASS.get(device_type)
|
||||
|
||||
@property
|
||||
def entity_category(self):
|
||||
def entity_category(self) -> EntityCategory | None:
|
||||
"""Entity Category of the sensor."""
|
||||
return (
|
||||
None if self._data_key == "air_temperature" else EntityCategory.DIAGNOSTIC
|
||||
)
|
||||
|
||||
@property
|
||||
def state_class(self):
|
||||
def state_class(self) -> SensorStateClass | None:
|
||||
"""Return the state class of the sensor."""
|
||||
state_type = self.sensor.get("state_type")
|
||||
if self._data_key == "scg_super_chlor_timer":
|
||||
return None
|
||||
return SensorStateClass.MEASUREMENT
|
||||
return SL_STATE_TYPE_TO_HA_STATE_CLASS.get(
|
||||
state_type, SensorStateClass.MEASUREMENT
|
||||
)
|
||||
|
||||
@property
|
||||
def native_value(self):
|
||||
def options(self) -> list[str] | None:
|
||||
"""Return a set of possible options."""
|
||||
return self.sensor.get("enum_options")
|
||||
|
||||
@property
|
||||
def native_value(self) -> str | int | float:
|
||||
"""State of the sensor."""
|
||||
return self.sensor["value"]
|
||||
|
||||
@property
|
||||
def sensor(self):
|
||||
def sensor(self) -> dict[str | int, Any]:
|
||||
"""Shortcut to access the sensor data."""
|
||||
return self.coordinator.data[SL_DATA.KEY_SENSORS][self._data_key]
|
||||
return self.gateway_data[SL_DATA.KEY_SENSORS][self._data_key]
|
||||
|
||||
|
||||
class ScreenLogicPumpSensor(ScreenLogicSensor):
|
||||
class ScreenLogicStatusSensor(ScreenLogicSensorEntity, ScreenLogicPushEntity):
|
||||
"""Representation of a basic ScreenLogic sensor entity."""
|
||||
|
||||
|
||||
class ScreenLogicPumpSensor(ScreenLogicSensorEntity):
|
||||
"""Representation of a ScreenLogic pump sensor entity."""
|
||||
|
||||
def __init__(self, coordinator, pump, key, enabled=True):
|
||||
|
@ -209,21 +240,21 @@ class ScreenLogicPumpSensor(ScreenLogicSensor):
|
|||
self._key = key
|
||||
|
||||
@property
|
||||
def sensor(self):
|
||||
def sensor(self) -> dict[str | int, Any]:
|
||||
"""Shortcut to access the pump sensor data."""
|
||||
return self.coordinator.data[SL_DATA.KEY_PUMPS][self._pump_id][self._key]
|
||||
return self.gateway_data[SL_DATA.KEY_PUMPS][self._pump_id][self._key]
|
||||
|
||||
|
||||
class ScreenLogicChemistrySensor(ScreenLogicSensor):
|
||||
class ScreenLogicChemistrySensor(ScreenLogicSensorEntity, ScreenLogicPushEntity):
|
||||
"""Representation of a ScreenLogic IntelliChem sensor entity."""
|
||||
|
||||
def __init__(self, coordinator, key, enabled=True):
|
||||
def __init__(self, coordinator, key, message_code, enabled=True):
|
||||
"""Initialize of the pump sensor."""
|
||||
super().__init__(coordinator, f"chem_{key}", enabled)
|
||||
super().__init__(coordinator, f"chem_{key}", message_code, enabled)
|
||||
self._key = key
|
||||
|
||||
@property
|
||||
def native_value(self):
|
||||
def native_value(self) -> str | int | float:
|
||||
"""State of the sensor."""
|
||||
value = self.sensor["value"]
|
||||
if "dosing_state" in self._key:
|
||||
|
@ -231,15 +262,15 @@ class ScreenLogicChemistrySensor(ScreenLogicSensor):
|
|||
return (value - 1) if "supply" in self._data_key else value
|
||||
|
||||
@property
|
||||
def sensor(self):
|
||||
def sensor(self) -> dict[str | int, Any]:
|
||||
"""Shortcut to access the pump sensor data."""
|
||||
return self.coordinator.data[SL_DATA.KEY_CHEMISTRY][self._key]
|
||||
return self.gateway_data[SL_DATA.KEY_CHEMISTRY][self._key]
|
||||
|
||||
|
||||
class ScreenLogicSCGSensor(ScreenLogicSensor):
|
||||
class ScreenLogicSCGSensor(ScreenLogicSensorEntity):
|
||||
"""Representation of ScreenLogic SCG sensor entity."""
|
||||
|
||||
@property
|
||||
def sensor(self):
|
||||
def sensor(self) -> dict[str | int, Any]:
|
||||
"""Shortcut to access the pump sensor data."""
|
||||
return self.coordinator.data[SL_DATA.KEY_SCG][self._data_key]
|
||||
return self.gateway_data[SL_DATA.KEY_SCG][self._data_key]
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
"""Support for a ScreenLogic 'circuit' switch."""
|
||||
import logging
|
||||
|
||||
from screenlogicpy.const import DATA as SL_DATA, GENERIC_CIRCUIT_NAMES
|
||||
from screenlogicpy.const import CODE, DATA as SL_DATA, GENERIC_CIRCUIT_NAMES
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import ScreenLogicCircuitEntity
|
||||
from . import ScreenlogicDataUpdateCoordinator
|
||||
from .const import DOMAIN, LIGHT_CIRCUIT_FUNCTIONS
|
||||
from .entity import ScreenLogicCircuitEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -20,13 +21,19 @@ async def async_setup_entry(
|
|||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up entry."""
|
||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||
coordinator: ScreenlogicDataUpdateCoordinator = hass.data[DOMAIN][
|
||||
config_entry.entry_id
|
||||
]
|
||||
circuits = coordinator.gateway_data[SL_DATA.KEY_CIRCUITS]
|
||||
async_add_entities(
|
||||
[
|
||||
ScreenLogicSwitch(
|
||||
coordinator, circuit_num, circuit["name"] not in GENERIC_CIRCUIT_NAMES
|
||||
coordinator,
|
||||
circuit_num,
|
||||
CODE.STATUS_CHANGED,
|
||||
circuit["name"] not in GENERIC_CIRCUIT_NAMES,
|
||||
)
|
||||
for circuit_num, circuit in coordinator.data[SL_DATA.KEY_CIRCUITS].items()
|
||||
for circuit_num, circuit in circuits.items()
|
||||
if circuit["function"] not in LIGHT_CIRCUIT_FUNCTIONS
|
||||
]
|
||||
)
|
||||
|
|
|
@ -4717,7 +4717,7 @@
|
|||
"name": "Pentair ScreenLogic",
|
||||
"integration_type": "hub",
|
||||
"config_flow": true,
|
||||
"iot_class": "local_polling"
|
||||
"iot_class": "local_push"
|
||||
},
|
||||
"scsgate": {
|
||||
"name": "SCSGate",
|
||||
|
|
|
@ -2297,7 +2297,7 @@ satel_integra==0.3.7
|
|||
scapy==2.5.0
|
||||
|
||||
# homeassistant.components.screenlogic
|
||||
screenlogicpy==0.6.4
|
||||
screenlogicpy==0.7.0
|
||||
|
||||
# homeassistant.components.scsgate
|
||||
scsgate==0.1.0
|
||||
|
|
|
@ -1618,7 +1618,7 @@ samsungtvws[async,encrypted]==2.5.0
|
|||
scapy==2.5.0
|
||||
|
||||
# homeassistant.components.screenlogic
|
||||
screenlogicpy==0.6.4
|
||||
screenlogicpy==0.7.0
|
||||
|
||||
# homeassistant.components.backup
|
||||
securetar==2022.2.0
|
||||
|
|
Loading…
Add table
Reference in a new issue