From c294e2b5e37974280522b802707bcd608d414214 Mon Sep 17 00:00:00 2001 From: shbatm Date: Sun, 8 Jan 2023 19:17:11 +0000 Subject: [PATCH 1/7] Add ISY994 variables as number entities --- .coveragerc | 1 + homeassistant/components/isy994/__init__.py | 9 +- homeassistant/components/isy994/const.py | 9 + homeassistant/components/isy994/helpers.py | 19 --- homeassistant/components/isy994/number.py | 158 ++++++++++++++++++ homeassistant/components/isy994/sensor.py | 37 +--- homeassistant/components/isy994/services.py | 12 ++ homeassistant/components/isy994/services.yaml | 4 +- 8 files changed, 191 insertions(+), 58 deletions(-) create mode 100644 homeassistant/components/isy994/number.py diff --git a/.coveragerc b/.coveragerc index 8170fec993ed9d..0a15bf21223ae2 100644 --- a/.coveragerc +++ b/.coveragerc @@ -606,6 +606,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 diff --git a/homeassistant/components/isy994/__init__.py b/homeassistant/components/isy994/__init__.py index be2948c7aa2b4c..b075dccc6c4ebc 100644 --- a/homeassistant/components/isy994/__init__.py +++ b/homeassistant/components/isy994/__init__.py @@ -54,7 +54,7 @@ SCHEME_HTTPS, SENSOR_AUX, ) -from .helpers import _categorize_nodes, _categorize_programs, _categorize_variables +from .helpers import _categorize_nodes, _categorize_programs from .services import async_setup_services, async_unload_services from .util import unique_ids_for_config_entry_id @@ -212,7 +212,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(hass_isy_data, isy.variables, variable_identifier) + + # Gather ISY Variables to be added. Identifier used to enable by default. + for vtype, vname, vid in isy.variables.children: + hass_isy_data[ISY994_VARIABLES].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) diff --git a/homeassistant/components/isy994/const.py b/homeassistant/components/isy994/const.py index 402086ddec11bb..3df11f078eacab 100644 --- a/homeassistant/components/isy994/const.py +++ b/homeassistant/components/isy994/const.py @@ -82,6 +82,7 @@ Platform.FAN, Platform.LIGHT, Platform.LOCK, + Platform.NUMBER, Platform.SENSOR, Platform.SWITCH, ] @@ -307,6 +308,14 @@ 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 = { diff --git a/homeassistant/components/isy994/helpers.py b/homeassistant/components/isy994/helpers.py index 54d2890c84c499..bf9dd190f4c1ee 100644 --- a/homeassistant/components/isy994/helpers.py +++ b/homeassistant/components/isy994/helpers.py @@ -14,7 +14,6 @@ ) from pyisy.nodes import Group, Node, Nodes from pyisy.programs import Programs -from pyisy.variables import Variables from homeassistant.const import Platform from homeassistant.core import HomeAssistant @@ -31,7 +30,6 @@ FILTER_ZWAVE_CAT, ISY994_NODES, ISY994_PROGRAMS, - ISY994_VARIABLES, ISY_GROUP_PLATFORM, KEY_ACTIONS, KEY_STATUS, @@ -363,23 +361,6 @@ def _categorize_programs(hass_isy_data: dict, programs: Programs) -> None: hass_isy_data[ISY994_PROGRAMS][platform].append(entity) -def _categorize_variables( - hass_isy_data: dict, variables: Variables, identifier: str -) -> None: - """Gather the ISY Variables to be added as sensors.""" - try: - var_to_add = [ - (vtype, vname, vid) - for (vtype, vname, vid) in variables.children - if identifier in vname - ] - except KeyError as err: - _LOGGER.error("Error adding ISY Variables: %s", err) - return - for vtype, vname, vid in var_to_add: - hass_isy_data[ISY994_VARIABLES].append((vname, variables[vtype][vid])) - - async def migrate_old_unique_ids( hass: HomeAssistant, platform: str, entities: Sequence[ISYEntity] ) -> None: diff --git a/homeassistant/components/isy994/number.py b/homeassistant/components/isy994/number.py new file mode 100644 index 00000000000000..42537730581c93 --- /dev/null +++ b/homeassistant/components/isy994/number.py @@ -0,0 +1,158 @@ +"""GoodWe PV inverter numeric settings 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.core import HomeAssistant, callback +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]: + description = NumberEntityDescription( + key=node.address, + name=node.name, + icon="mdi:counter", + native_unit_of_measurement=None, + native_step=10 ** (-1 * node.prec), + native_min_value=-ISY_MAX_SIZE / (10**node.prec), + native_max_value=ISY_MAX_SIZE / (10**node.prec), + ) + description_init = NumberEntityDescription( + key=f"{node.address}_init", + name=f"{node.name} Initial Value", + icon="mdi:counter", + native_unit_of_measurement=None, + native_step=10 ** (-1 * node.prec), + native_min_value=-ISY_MAX_SIZE / (10**node.prec), + native_max_value=ISY_MAX_SIZE / (10**node.prec), + entity_category=EntityCategory.CONFIG, + ) + + entities.append( + ISYVariableNumberEntity( + node, + unique_id=f"{uuid}_{node.address}", + description=description, + enable_by_default=enable_by_default, + ) + ) + entities.append( + ISYVariableNumberEntity( + node=node, + unique_id=f"{uuid}_{node.address}_init", + description=description_init, + enable_by_default=False, + 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, + enable_by_default: bool, + init_entity: bool = False, + ) -> None: + """Initialize the ISY binary sensor program.""" + 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_entity_registry_enabled_default = enable_by_default + + self._attr_unique_id = unique_id + + url = _async_isy_to_configuration_url(node.isy) + self._attr_device_info = DeviceInfo( + identifiers={ + ( + ISY994_DOMAIN, + f"{node.isy.configuration[ISY_CONF_UUID]}_variables", + ) + }, + manufacturer=MANUFACTURER, + name=f"{node.isy.configuration[ISY_CONF_NAME]} Variables", + model=node.isy.configuration[ISY_CONF_MODEL], + sw_version=node.isy.configuration[ISY_CONF_FIRMWARE], + configuration_url=url, + via_device=(ISY994_DOMAIN, node.isy.configuration[ISY_CONF_UUID]), + ) + + 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) diff --git a/homeassistant/components/isy994/sensor.py b/homeassistant/components/isy994/sensor.py index 727600edea2802..5840562c5fbed5 100644 --- a/homeassistant/components/isy994/sensor.py +++ b/homeassistant/components/isy994/sensor.py @@ -35,7 +35,6 @@ _LOGGER, DOMAIN as ISY994_DOMAIN, ISY994_NODES, - ISY994_VARIABLES, ISY_CONF_UUID, SENSOR_AUX, UOM_DOUBLE_TEMP, @@ -44,7 +43,7 @@ UOM_ON_OFF, UOM_TO_STATES, ) -from .entity import ISYEntity, ISYNodeEntity +from .entity import ISYNodeEntity from .helpers import convert_isy_value_to_hass, migrate_old_unique_ids # Disable general purpose and redundant sensors by default @@ -111,7 +110,7 @@ async def async_setup_entry( ) -> None: """Set up the ISY sensor platform.""" hass_isy_data = hass.data[ISY994_DOMAIN][entry.entry_id] - entities: list[ISYSensorEntity | ISYSensorVariableEntity] = [] + entities: list[ISYSensorEntity] = [] for node in hass_isy_data[ISY994_NODES][Platform.SENSOR]: _LOGGER.debug("Loading %s", node.name) @@ -132,9 +131,6 @@ 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]: - entities.append(ISYSensorVariableEntity(vname, vobj)) - await migrate_old_unique_ids(hass, Platform.SENSOR, entities) async_add_entities(entities) @@ -264,32 +260,3 @@ def name(self) -> str: base_name = self._name or str(self._node.name) name = COMMAND_FRIENDLY_NAME.get(self._control, self._control) return f"{base_name} {name.replace('_', ' ').title()}" - - -class ISYSensorVariableEntity(ISYEntity, SensorEntity): - """Representation of an ISY variable as a sensor device.""" - - def __init__(self, vname: str, vobj: object) -> None: - """Initialize the ISY binary sensor program.""" - super().__init__(vobj) - self._name = vname - - @property - def native_value(self) -> float | int | None: - """Return the state of the variable.""" - return convert_isy_value_to_hass(self._node.status, "", self._node.prec) - - @property - def extra_state_attributes(self) -> dict[str, Any]: - """Get the state attributes for the device.""" - return { - "init_value": convert_isy_value_to_hass( - self._node.init, "", self._node.prec - ), - "last_edited": self._node.last_edited, - } - - @property - def icon(self) -> str: - """Return the icon.""" - return "mdi:counter" diff --git a/homeassistant/components/isy994/services.py b/homeassistant/components/isy994/services.py index ff7fdb965c71d5..bd49478905f19d 100644 --- a/homeassistant/components/isy994/services.py +++ b/homeassistant/components/isy994/services.py @@ -307,6 +307,18 @@ async def async_set_variable_service_handler(service: ServiceCall) -> None: 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") diff --git a/homeassistant/components/isy994/services.yaml b/homeassistant/components/isy994/services.yaml index 8d1aa8c58ef5cb..c9daa828970542 100644 --- a/homeassistant/components/isy994/services.yaml +++ b/homeassistant/components/isy994/services.yaml @@ -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 From 5a19706164275199ef3eee7eb7333bac633e4848 Mon Sep 17 00:00:00 2001 From: shbatm Date: Mon, 9 Jan 2023 01:39:33 +0000 Subject: [PATCH 2/7] Cleanup based on other reviews --- homeassistant/components/isy994/number.py | 31 ++++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/isy994/number.py b/homeassistant/components/isy994/number.py index 42537730581c93..de628504e62625 100644 --- a/homeassistant/components/isy994/number.py +++ b/homeassistant/components/isy994/number.py @@ -41,23 +41,27 @@ async def async_setup_entry( entities: list[ISYVariableNumberEntity] = [] for node, enable_by_default in hass_isy_data[ISY994_VARIABLES]: + 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=10 ** (-1 * node.prec), - native_min_value=-ISY_MAX_SIZE / (10**node.prec), - native_max_value=ISY_MAX_SIZE / (10**node.prec), + 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=10 ** (-1 * node.prec), - native_min_value=-ISY_MAX_SIZE / (10**node.prec), - native_max_value=ISY_MAX_SIZE / (10**node.prec), + native_step=step, + native_min_value=-min_max, + native_max_value=min_max, entity_category=EntityCategory.CONFIG, ) @@ -66,7 +70,6 @@ async def async_setup_entry( node, unique_id=f"{uuid}_{node.address}", description=description, - enable_by_default=enable_by_default, ) ) entities.append( @@ -74,7 +77,6 @@ async def async_setup_entry( node=node, unique_id=f"{uuid}_{node.address}_init", description=description_init, - enable_by_default=False, init_entity=True, ) ) @@ -96,7 +98,6 @@ def __init__( node: Variable, unique_id: str, description: NumberEntityDescription, - enable_by_default: bool, init_entity: bool = False, ) -> None: """Initialize the ISY binary sensor program.""" @@ -108,24 +109,24 @@ def __init__( # 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_entity_registry_enabled_default = enable_by_default 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"{node.isy.configuration[ISY_CONF_UUID]}_variables", + f"{config[ISY_CONF_UUID]}_variables", ) }, manufacturer=MANUFACTURER, - name=f"{node.isy.configuration[ISY_CONF_NAME]} Variables", - model=node.isy.configuration[ISY_CONF_MODEL], - sw_version=node.isy.configuration[ISY_CONF_FIRMWARE], + 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, node.isy.configuration[ISY_CONF_UUID]), + via_device=(ISY994_DOMAIN, config[ISY_CONF_UUID]), ) async def async_added_to_hass(self) -> None: From e713b45dc2f58b5e21d070db802229da675f2114 Mon Sep 17 00:00:00 2001 From: shbatm Date: Mon, 9 Jan 2023 23:21:11 +0000 Subject: [PATCH 3/7] Changes requested in review --- homeassistant/components/isy994/__init__.py | 10 ++++-- homeassistant/components/isy994/helpers.py | 20 +++++++++++ homeassistant/components/isy994/number.py | 7 ++-- homeassistant/components/isy994/sensor.py | 40 +++++++++++++++++++-- 4 files changed, 70 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/isy994/__init__.py b/homeassistant/components/isy994/__init__.py index b075dccc6c4ebc..ae07bfe2dace8a 100644 --- a/homeassistant/components/isy994/__init__.py +++ b/homeassistant/components/isy994/__init__.py @@ -16,6 +16,7 @@ CONF_PASSWORD, CONF_USERNAME, EVENT_HOMEASSISTANT_STOP, + Platform, ) from homeassistant.core import Event, HomeAssistant, callback from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady @@ -54,7 +55,7 @@ SCHEME_HTTPS, SENSOR_AUX, ) -from .helpers import _categorize_nodes, _categorize_programs +from .helpers import _categorize_nodes, _categorize_programs, _categorize_variables from .services import async_setup_services, async_unload_services from .util import unique_ids_for_config_entry_id @@ -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,8 @@ 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. for vtype, vname, vid in isy.variables.children: hass_isy_data[ISY994_VARIABLES].append( diff --git a/homeassistant/components/isy994/helpers.py b/homeassistant/components/isy994/helpers.py index bf9dd190f4c1ee..cc602a49777d03 100644 --- a/homeassistant/components/isy994/helpers.py +++ b/homeassistant/components/isy994/helpers.py @@ -14,6 +14,7 @@ ) from pyisy.nodes import Group, Node, Nodes from pyisy.programs import Programs +from pyisy.variables import Variables from homeassistant.const import Platform from homeassistant.core import HomeAssistant @@ -30,6 +31,7 @@ FILTER_ZWAVE_CAT, ISY994_NODES, ISY994_PROGRAMS, + ISY994_VARIABLES, ISY_GROUP_PLATFORM, KEY_ACTIONS, KEY_STATUS, @@ -361,6 +363,24 @@ def _categorize_programs(hass_isy_data: dict, programs: Programs) -> None: hass_isy_data[ISY994_PROGRAMS][platform].append(entity) +def _categorize_variables( + hass_isy_data: dict, variables: Variables, identifier: str +) -> None: + """Gather the ISY Variables to be added as sensors.""" + try: + var_to_add = [ + (vtype, vname, vid) + for (vtype, vname, vid) in variables.children + if identifier in vname + ] + 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: + variable_entities[Platform.SENSOR].append((vname, variables[vtype][vid])) + + async def migrate_old_unique_ids( hass: HomeAssistant, platform: str, entities: Sequence[ISYEntity] ) -> None: diff --git a/homeassistant/components/isy994/number.py b/homeassistant/components/isy994/number.py index de628504e62625..d1c667fe33e8f3 100644 --- a/homeassistant/components/isy994/number.py +++ b/homeassistant/components/isy994/number.py @@ -1,4 +1,4 @@ -"""GoodWe PV inverter numeric settings entities.""" +"""Support for ISY number entities.""" from __future__ import annotations from typing import Any @@ -9,7 +9,9 @@ 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 @@ -40,7 +42,7 @@ async def async_setup_entry( uuid = isy.configuration[ISY_CONF_UUID] entities: list[ISYVariableNumberEntity] = [] - for node, enable_by_default in hass_isy_data[ISY994_VARIABLES]: + 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( @@ -127,6 +129,7 @@ def __init__( 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: diff --git a/homeassistant/components/isy994/sensor.py b/homeassistant/components/isy994/sensor.py index 5840562c5fbed5..e3e812d1b261d2 100644 --- a/homeassistant/components/isy994/sensor.py +++ b/homeassistant/components/isy994/sensor.py @@ -35,6 +35,7 @@ _LOGGER, DOMAIN as ISY994_DOMAIN, ISY994_NODES, + ISY994_VARIABLES, ISY_CONF_UUID, SENSOR_AUX, UOM_DOUBLE_TEMP, @@ -43,7 +44,7 @@ UOM_ON_OFF, UOM_TO_STATES, ) -from .entity import ISYNodeEntity +from .entity import ISYEntity, ISYNodeEntity from .helpers import convert_isy_value_to_hass, migrate_old_unique_ids # Disable general purpose and redundant sensors by default @@ -110,7 +111,7 @@ async def async_setup_entry( ) -> None: """Set up the ISY sensor platform.""" hass_isy_data = hass.data[ISY994_DOMAIN][entry.entry_id] - entities: list[ISYSensorEntity] = [] + entities: list[ISYSensorEntity | ISYSensorVariableEntity] = [] for node in hass_isy_data[ISY994_NODES][Platform.SENSOR]: _LOGGER.debug("Loading %s", node.name) @@ -131,6 +132,9 @@ 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][Platform.SENSOR]: + entities.append(ISYSensorVariableEntity(vname, vobj)) + await migrate_old_unique_ids(hass, Platform.SENSOR, entities) async_add_entities(entities) @@ -260,3 +264,35 @@ def name(self) -> str: base_name = self._name or str(self._node.name) name = COMMAND_FRIENDLY_NAME.get(self._control, self._control) return f"{base_name} {name.replace('_', ' ').title()}" + + +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) + self._name = vname + + @property + def native_value(self) -> float | int | None: + """Return the state of the variable.""" + return convert_isy_value_to_hass(self._node.status, "", self._node.prec) + + @property + def extra_state_attributes(self) -> dict[str, Any]: + """Get the state attributes for the device.""" + return { + "init_value": convert_isy_value_to_hass( + self._node.init, "", self._node.prec + ), + "last_edited": self._node.last_edited, + } + + @property + def icon(self) -> str: + """Return the icon.""" + return "mdi:counter" From 8ff0b042a661b95cfc916ba694ddc9dbdbd0beeb Mon Sep 17 00:00:00 2001 From: shbatm Date: Mon, 9 Jan 2023 23:24:57 +0000 Subject: [PATCH 4/7] Fix nesting of data dict --- homeassistant/components/isy994/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/isy994/__init__.py b/homeassistant/components/isy994/__init__.py index ae07bfe2dace8a..9bb2a85240bb1e 100644 --- a/homeassistant/components/isy994/__init__.py +++ b/homeassistant/components/isy994/__init__.py @@ -219,7 +219,7 @@ async def async_setup_entry( _categorize_variables(hass_isy_data, isy.variables, variable_identifier) # Gather ISY Variables to be added. Identifier used to enable by default. for vtype, vname, vid in isy.variables.children: - hass_isy_data[ISY994_VARIABLES].append( + hass_isy_data[ISY994_VARIABLES][Platform.NUMBER].append( (isy.variables[vtype][vid], variable_identifier in vname) ) if isy.configuration[ISY_CONF_NETWORKING]: From 5f4e318a3f771567da96a8dca6d9d9b1f4ba8546 Mon Sep 17 00:00:00 2001 From: shbatm Date: Tue, 10 Jan 2023 15:58:30 -0600 Subject: [PATCH 5/7] avoid the dict lookups every loop Co-authored-by: J. Nick Koston --- homeassistant/components/isy994/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/isy994/__init__.py b/homeassistant/components/isy994/__init__.py index 9bb2a85240bb1e..23ea6ea90bddb8 100644 --- a/homeassistant/components/isy994/__init__.py +++ b/homeassistant/components/isy994/__init__.py @@ -218,8 +218,9 @@ async def async_setup_entry( # 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: - hass_isy_data[ISY994_VARIABLES][Platform.NUMBER].append( + numbers.append( (isy.variables[vtype][vid], variable_identifier in vname) ) if isy.configuration[ISY_CONF_NETWORKING]: From 05fa0a5d9b4bd8ce9839ef8b9d434edd1c50833e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 10 Jan 2023 12:15:11 -1000 Subject: [PATCH 6/7] lint --- homeassistant/components/isy994/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/homeassistant/components/isy994/__init__.py b/homeassistant/components/isy994/__init__.py index 23ea6ea90bddb8..a8b3d4e239e9c1 100644 --- a/homeassistant/components/isy994/__init__.py +++ b/homeassistant/components/isy994/__init__.py @@ -220,9 +220,7 @@ async def async_setup_entry( # 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) - ) + 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) From c10ea7d81b1f4b51fc12c60070cc25d11d622b4c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 10 Jan 2023 12:24:35 -1000 Subject: [PATCH 7/7] Update homeassistant/components/isy994/number.py --- homeassistant/components/isy994/number.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/isy994/number.py b/homeassistant/components/isy994/number.py index d1c667fe33e8f3..064b6c6e60aeaf 100644 --- a/homeassistant/components/isy994/number.py +++ b/homeassistant/components/isy994/number.py @@ -102,7 +102,7 @@ def __init__( description: NumberEntityDescription, init_entity: bool = False, ) -> None: - """Initialize the ISY binary sensor program.""" + """Initialize the ISY variable number.""" self._node = node self._name = description.name self.entity_description = description