Add ISY994 variables as number entities (#85511)
Co-authored-by: J. Nick Koston <nick@koston.org>pull/85641/head^2
parent
7af23698bc
commit
d3249432c9
|
@ -607,6 +607,7 @@ omit =
|
|||
homeassistant/components/isy994/helpers.py
|
||||
homeassistant/components/isy994/light.py
|
||||
homeassistant/components/isy994/lock.py
|
||||
homeassistant/components/isy994/number.py
|
||||
homeassistant/components/isy994/sensor.py
|
||||
homeassistant/components/isy994/services.py
|
||||
homeassistant/components/isy994/switch.py
|
||||
|
|
|
@ -16,6 +16,7 @@ from homeassistant.const import (
|
|||
CONF_PASSWORD,
|
||||
CONF_USERNAME,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import Event, HomeAssistant, callback
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
|
@ -141,7 +142,9 @@ async def async_setup_entry(
|
|||
for platform in PROGRAM_PLATFORMS:
|
||||
hass_isy_data[ISY994_PROGRAMS][platform] = []
|
||||
|
||||
hass_isy_data[ISY994_VARIABLES] = []
|
||||
hass_isy_data[ISY994_VARIABLES] = {}
|
||||
hass_isy_data[ISY994_VARIABLES][Platform.NUMBER] = []
|
||||
hass_isy_data[ISY994_VARIABLES][Platform.SENSOR] = []
|
||||
|
||||
isy_config = entry.data
|
||||
isy_options = entry.options
|
||||
|
@ -212,7 +215,12 @@ async def async_setup_entry(
|
|||
|
||||
_categorize_nodes(hass_isy_data, isy.nodes, ignore_identifier, sensor_identifier)
|
||||
_categorize_programs(hass_isy_data, isy.programs)
|
||||
# Categorize variables call to be removed with variable sensors in 2023.5.0
|
||||
_categorize_variables(hass_isy_data, isy.variables, variable_identifier)
|
||||
# Gather ISY Variables to be added. Identifier used to enable by default.
|
||||
numbers = hass_isy_data[ISY994_VARIABLES][Platform.NUMBER]
|
||||
for vtype, vname, vid in isy.variables.children:
|
||||
numbers.append((isy.variables[vtype][vid], variable_identifier in vname))
|
||||
if isy.configuration[ISY_CONF_NETWORKING]:
|
||||
for resource in isy.networking.nobjs:
|
||||
hass_isy_data[ISY994_NODES][PROTO_NETWORK_RESOURCE].append(resource)
|
||||
|
|
|
@ -82,6 +82,7 @@ PLATFORMS = [
|
|||
Platform.FAN,
|
||||
Platform.LIGHT,
|
||||
Platform.LOCK,
|
||||
Platform.NUMBER,
|
||||
Platform.SENSOR,
|
||||
Platform.SWITCH,
|
||||
]
|
||||
|
@ -307,6 +308,14 @@ NODE_FILTERS: dict[Platform, dict[str, list[str]]] = {
|
|||
FILTER_INSTEON_TYPE: ["4.8", TYPE_CATEGORY_CLIMATE],
|
||||
FILTER_ZWAVE_CAT: ["140"],
|
||||
},
|
||||
Platform.NUMBER: {
|
||||
# No devices automatically sorted as numbers at this time.
|
||||
FILTER_UOM: [],
|
||||
FILTER_STATES: [],
|
||||
FILTER_NODE_DEF_ID: [],
|
||||
FILTER_INSTEON_TYPE: [],
|
||||
FILTER_ZWAVE_CAT: [],
|
||||
},
|
||||
}
|
||||
|
||||
UOM_FRIENDLY_NAME = {
|
||||
|
|
|
@ -376,8 +376,9 @@ def _categorize_variables(
|
|||
except KeyError as err:
|
||||
_LOGGER.error("Error adding ISY Variables: %s", err)
|
||||
return
|
||||
variable_entities = hass_isy_data[ISY994_VARIABLES]
|
||||
for vtype, vname, vid in var_to_add:
|
||||
hass_isy_data[ISY994_VARIABLES].append((vname, variables[vtype][vid]))
|
||||
variable_entities[Platform.SENSOR].append((vname, variables[vtype][vid]))
|
||||
|
||||
|
||||
async def migrate_old_unique_ids(
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
"""Support for ISY number entities."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from pyisy import ISY
|
||||
from pyisy.helpers import EventListener, NodeProperty
|
||||
from pyisy.variables import Variable
|
||||
|
||||
from homeassistant.components.number import NumberEntity, NumberEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||
from homeassistant.helpers.entity import DeviceInfo, EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import _async_isy_to_configuration_url
|
||||
from .const import (
|
||||
DOMAIN as ISY994_DOMAIN,
|
||||
ISY994_ISY,
|
||||
ISY994_VARIABLES,
|
||||
ISY_CONF_FIRMWARE,
|
||||
ISY_CONF_MODEL,
|
||||
ISY_CONF_NAME,
|
||||
ISY_CONF_UUID,
|
||||
MANUFACTURER,
|
||||
)
|
||||
from .helpers import convert_isy_value_to_hass
|
||||
|
||||
ISY_MAX_SIZE = (2**32) / 2
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up ISY/IoX number entities from config entry."""
|
||||
hass_isy_data = hass.data[ISY994_DOMAIN][config_entry.entry_id]
|
||||
isy: ISY = hass_isy_data[ISY994_ISY]
|
||||
uuid = isy.configuration[ISY_CONF_UUID]
|
||||
entities: list[ISYVariableNumberEntity] = []
|
||||
|
||||
for node, enable_by_default in hass_isy_data[ISY994_VARIABLES][Platform.NUMBER]:
|
||||
step = 10 ** (-1 * node.prec)
|
||||
min_max = ISY_MAX_SIZE / (10**node.prec)
|
||||
description = NumberEntityDescription(
|
||||
key=node.address,
|
||||
name=node.name,
|
||||
icon="mdi:counter",
|
||||
entity_registry_enabled_default=enable_by_default,
|
||||
native_unit_of_measurement=None,
|
||||
native_step=step,
|
||||
native_min_value=-min_max,
|
||||
native_max_value=min_max,
|
||||
)
|
||||
description_init = NumberEntityDescription(
|
||||
key=f"{node.address}_init",
|
||||
name=f"{node.name} Initial Value",
|
||||
icon="mdi:counter",
|
||||
entity_registry_enabled_default=False,
|
||||
native_unit_of_measurement=None,
|
||||
native_step=step,
|
||||
native_min_value=-min_max,
|
||||
native_max_value=min_max,
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
)
|
||||
|
||||
entities.append(
|
||||
ISYVariableNumberEntity(
|
||||
node,
|
||||
unique_id=f"{uuid}_{node.address}",
|
||||
description=description,
|
||||
)
|
||||
)
|
||||
entities.append(
|
||||
ISYVariableNumberEntity(
|
||||
node=node,
|
||||
unique_id=f"{uuid}_{node.address}_init",
|
||||
description=description_init,
|
||||
init_entity=True,
|
||||
)
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class ISYVariableNumberEntity(NumberEntity):
|
||||
"""Representation of an ISY variable as a number entity device."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
_attr_should_poll = False
|
||||
_init_entity: bool
|
||||
_node: Variable
|
||||
entity_description: NumberEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
node: Variable,
|
||||
unique_id: str,
|
||||
description: NumberEntityDescription,
|
||||
init_entity: bool = False,
|
||||
) -> None:
|
||||
"""Initialize the ISY variable number."""
|
||||
self._node = node
|
||||
self._name = description.name
|
||||
self.entity_description = description
|
||||
self._change_handler: EventListener | None = None
|
||||
|
||||
# Two entities are created for each variable, one for current value and one for initial.
|
||||
# Initial value entities are disabled by default
|
||||
self._init_entity = init_entity
|
||||
|
||||
self._attr_unique_id = unique_id
|
||||
|
||||
url = _async_isy_to_configuration_url(node.isy)
|
||||
config = node.isy.configuration
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={
|
||||
(
|
||||
ISY994_DOMAIN,
|
||||
f"{config[ISY_CONF_UUID]}_variables",
|
||||
)
|
||||
},
|
||||
manufacturer=MANUFACTURER,
|
||||
name=f"{config[ISY_CONF_NAME]} Variables",
|
||||
model=config[ISY_CONF_MODEL],
|
||||
sw_version=config[ISY_CONF_FIRMWARE],
|
||||
configuration_url=url,
|
||||
via_device=(ISY994_DOMAIN, config[ISY_CONF_UUID]),
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Subscribe to the node change events."""
|
||||
self._change_handler = self._node.status_events.subscribe(self.async_on_update)
|
||||
|
||||
@callback
|
||||
def async_on_update(self, event: NodeProperty) -> None:
|
||||
"""Handle the update event from the ISY Node."""
|
||||
self.async_write_ha_state()
|
||||
|
||||
@property
|
||||
def native_value(self) -> float | int | None:
|
||||
"""Return the state of the variable."""
|
||||
return convert_isy_value_to_hass(
|
||||
self._node.init if self._init_entity else self._node.status,
|
||||
"",
|
||||
self._node.prec,
|
||||
)
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Get the state attributes for the device."""
|
||||
return {
|
||||
"last_edited": self._node.last_edited,
|
||||
}
|
||||
|
||||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Set new value."""
|
||||
await self._node.set_value(value, init=self._init_entity)
|
|
@ -132,7 +132,7 @@ async def async_setup_entry(
|
|||
# Any node in SENSOR_AUX can potentially have communication errors
|
||||
entities.append(ISYAuxSensorEntity(node, PROP_COMMS_ERROR, False))
|
||||
|
||||
for vname, vobj in hass_isy_data[ISY994_VARIABLES]:
|
||||
for vname, vobj in hass_isy_data[ISY994_VARIABLES][Platform.SENSOR]:
|
||||
entities.append(ISYSensorVariableEntity(vname, vobj))
|
||||
|
||||
await migrate_old_unique_ids(hass, Platform.SENSOR, entities)
|
||||
|
@ -269,6 +269,9 @@ class ISYAuxSensorEntity(ISYSensorEntity):
|
|||
class ISYSensorVariableEntity(ISYEntity, SensorEntity):
|
||||
"""Representation of an ISY variable as a sensor device."""
|
||||
|
||||
# Depreceted sensors, will be removed in 2023.5.0
|
||||
_attr_entity_registry_enabled_default = False
|
||||
|
||||
def __init__(self, vname: str, vobj: object) -> None:
|
||||
"""Initialize the ISY binary sensor program."""
|
||||
super().__init__(vobj)
|
||||
|
|
|
@ -307,6 +307,18 @@ def async_setup_services(hass: HomeAssistant) -> None: # noqa: C901
|
|||
variable = isy.variables.vobjs[vtype].get(address)
|
||||
if variable is not None:
|
||||
await variable.set_value(value, init)
|
||||
entity_registry = er.async_get(hass)
|
||||
async_log_deprecated_service_call(
|
||||
hass,
|
||||
call=service,
|
||||
alternate_service="number.set_value",
|
||||
alternate_target=entity_registry.async_get_entity_id(
|
||||
Platform.NUMBER,
|
||||
DOMAIN,
|
||||
f"{isy.configuration[ISY_CONF_UUID]}_{address}{'_init' if init else ''}",
|
||||
),
|
||||
breaks_in_ha_version="2023.5.0",
|
||||
)
|
||||
return
|
||||
_LOGGER.error("Could not set variable value; not found or enabled on the ISY")
|
||||
|
||||
|
|
|
@ -184,8 +184,8 @@ system_query:
|
|||
selector:
|
||||
text:
|
||||
set_variable:
|
||||
name: Set variable
|
||||
description: Set an ISY variable's current or initial value. Variables can be set by either type/address or by name.
|
||||
name: Set variable (Deprecated)
|
||||
description: "Set an ISY variable's current or initial value. Variables can be set by either type/address or by name. Deprecated: Use number entities instead."
|
||||
fields:
|
||||
address:
|
||||
name: Address
|
||||
|
|
Loading…
Reference in New Issue