Add support for ISY994 Variables as Sensors (#35453)

* Update tests, add missing constant

* ISY994 Add support for ISY Variables as sensors
This commit is contained in:
shbatm 2020-05-10 09:40:19 -05:00 committed by GitHub
parent f302c6fd65
commit 799cdbe64d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 79 additions and 5 deletions

View File

@ -20,19 +20,22 @@ from .const import (
CONF_RESTORE_LIGHT_STATE,
CONF_SENSOR_STRING,
CONF_TLS_VER,
CONF_VAR_SENSOR_STRING,
DEFAULT_IGNORE_STRING,
DEFAULT_RESTORE_LIGHT_STATE,
DEFAULT_SENSOR_STRING,
DEFAULT_VAR_SENSOR_STRING,
DOMAIN,
ISY994_ISY,
ISY994_NODES,
ISY994_PROGRAMS,
ISY994_VARIABLES,
MANUFACTURER,
SUPPORTED_PLATFORMS,
SUPPORTED_PROGRAM_PLATFORMS,
UNDO_UPDATE_LISTENER,
)
from .helpers import _categorize_nodes, _categorize_programs
from .helpers import _categorize_nodes, _categorize_programs, _categorize_variables
CONFIG_SCHEMA = vol.Schema(
{
@ -48,6 +51,9 @@ CONFIG_SCHEMA = vol.Schema(
vol.Optional(
CONF_SENSOR_STRING, default=DEFAULT_SENSOR_STRING
): cv.string,
vol.Optional(
CONF_VAR_SENSOR_STRING, default=DEFAULT_VAR_SENSOR_STRING
): cv.string,
vol.Required(
CONF_RESTORE_LIGHT_STATE, default=DEFAULT_RESTORE_LIGHT_STATE
): bool,
@ -111,6 +117,8 @@ async def async_setup_entry(
for platform in SUPPORTED_PROGRAM_PLATFORMS:
hass_isy_data[ISY994_PROGRAMS][platform] = []
hass_isy_data[ISY994_VARIABLES] = []
isy_config = entry.data
isy_options = entry.options
@ -123,6 +131,9 @@ async def async_setup_entry(
tls_version = isy_config.get(CONF_TLS_VER)
ignore_identifier = isy_options.get(CONF_IGNORE_STRING, DEFAULT_IGNORE_STRING)
sensor_identifier = isy_options.get(CONF_SENSOR_STRING, DEFAULT_SENSOR_STRING)
variable_identifier = isy_options.get(
CONF_VAR_SENSOR_STRING, DEFAULT_VAR_SENSOR_STRING
)
if host.scheme == "http":
https = False
@ -153,6 +164,7 @@ 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)
# Dump ISY Clock Information. Future: Add ISY as sensor to Hass with attrs
_LOGGER.info(repr(isy.clock))

View File

@ -15,10 +15,12 @@ from .const import (
CONF_RESTORE_LIGHT_STATE,
CONF_SENSOR_STRING,
CONF_TLS_VER,
CONF_VAR_SENSOR_STRING,
DEFAULT_IGNORE_STRING,
DEFAULT_RESTORE_LIGHT_STATE,
DEFAULT_SENSOR_STRING,
DEFAULT_TLS_VERSION,
DEFAULT_VAR_SENSOR_STRING,
)
from .const import DOMAIN # pylint:disable=unused-import
@ -154,11 +156,15 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
)
ignore_string = options.get(CONF_IGNORE_STRING, DEFAULT_IGNORE_STRING)
sensor_string = options.get(CONF_SENSOR_STRING, DEFAULT_SENSOR_STRING)
var_sensor_string = options.get(
CONF_VAR_SENSOR_STRING, DEFAULT_VAR_SENSOR_STRING
)
options_schema = vol.Schema(
{
vol.Optional(CONF_IGNORE_STRING, default=ignore_string): str,
vol.Optional(CONF_SENSOR_STRING, default=sensor_string): str,
vol.Optional(CONF_VAR_SENSOR_STRING, default=var_sensor_string): str,
vol.Required(
CONF_RESTORE_LIGHT_STATE, default=restore_light_state
): bool,

View File

@ -98,6 +98,7 @@ MANUFACTURER = "Universal Devices, Inc"
CONF_IGNORE_STRING = "ignore_string"
CONF_SENSOR_STRING = "sensor_string"
CONF_VAR_SENSOR_STRING = "variable_sensor_string"
CONF_TLS_VER = "tls"
CONF_RESTORE_LIGHT_STATE = "restore_light_state"
@ -106,6 +107,7 @@ DEFAULT_SENSOR_STRING = "sensor"
DEFAULT_RESTORE_LIGHT_STATE = False
DEFAULT_TLS_VERSION = 1.1
DEFAULT_PROGRAM_STRING = "HA."
DEFAULT_VAR_SENSOR_STRING = "HA."
KEY_ACTIONS = "actions"
KEY_STATUS = "status"
@ -122,6 +124,7 @@ ISY_GROUP_PLATFORM = SWITCH
ISY994_ISY = "isy"
ISY994_NODES = "isy994_nodes"
ISY994_PROGRAMS = "isy994_programs"
ISY994_VARIABLES = "isy994_variables"
FILTER_UOM = "uom"
FILTER_STATES = "states"

View File

@ -10,6 +10,7 @@ from pyisy.constants import (
)
from pyisy.nodes import Group, Node, Nodes
from pyisy.programs import Programs
from pyisy.variables import Variables
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR
from homeassistant.components.climate.const import DOMAIN as CLIMATE
@ -31,6 +32,7 @@ from .const import (
FILTER_ZWAVE_CAT,
ISY994_NODES,
ISY994_PROGRAMS,
ISY994_VARIABLES,
ISY_GROUP_PLATFORM,
KEY_ACTIONS,
KEY_STATUS,
@ -345,6 +347,23 @@ 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 ISY994 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: HomeAssistantType, platform: str, devices: Optional[List[Any]]
) -> None:

View File

@ -1,5 +1,5 @@
"""Support for ISY994 sensors."""
from typing import Callable
from typing import Callable, Dict
from pyisy.constants import ISY_VALUE_UNKNOWN
@ -12,10 +12,11 @@ from .const import (
_LOGGER,
DOMAIN as ISY994_DOMAIN,
ISY994_NODES,
ISY994_VARIABLES,
UOM_FRIENDLY_NAME,
UOM_TO_STATES,
)
from .entity import ISYNodeEntity
from .entity import ISYEntity, ISYNodeEntity
from .helpers import migrate_old_unique_ids
@ -32,6 +33,9 @@ async def async_setup_entry(
_LOGGER.debug("Loading %s", node.name)
devices.append(ISYSensorEntity(node))
for vname, vobj in hass_isy_data[ISY994_VARIABLES]:
devices.append(ISYSensorVariableEntity(vname, vobj))
await migrate_old_unique_ids(hass, SENSOR, devices)
async_add_entities(devices)
@ -84,3 +88,27 @@ class ISYSensorEntity(ISYNodeEntity):
if raw_units in (TEMP_FAHRENHEIT, TEMP_CELSIUS):
return self.hass.config.units.temperature_unit
return raw_units
class ISYSensorVariableEntity(ISYEntity):
"""Representation of an ISY994 variable as a sensor device."""
def __init__(self, vname: str, vobj: object) -> None:
"""Initialize the ISY994 binary sensor program."""
super().__init__(vobj)
self._name = vname
@property
def state(self):
"""Return the state of the variable."""
return self.value
@property
def device_state_attributes(self) -> Dict:
"""Get the state attributes for the device."""
return {"init_value": int(self._node.init)}
@property
def icon(self):
"""Return the icon."""
return "mdi:counter"

View File

@ -27,10 +27,11 @@
"step": {
"init": {
"title": "ISY994 Options",
"description": "Set the options for the ISY Integration: \n • Node Sensor String: Any device or folder that contains 'Node Sensor String' in the name will be treated as a sensor or binary sensor. \n • Ignore String: Any device with 'Ignore String' in the name will be ignored. \n • Restore Light Brightness: If enabled, the previous brightness will be restored when turning on a light instead of the device's built-in On-Level.",
"description": "Set the options for the ISY Integration: \n • Node Sensor String: Any device or folder that contains 'Node Sensor String' in the name will be treated as a sensor or binary sensor. \n • Ignore String: Any device with 'Ignore String' in the name will be ignored. \n • Variable Sensor String: Any variable that contains 'Variable Sensor String' will be added as a sensor. \n • Restore Light Brightness: If enabled, the previous brightness will be restored when turning on a light instead of the device's built-in On-Level.",
"data": {
"sensor_string": "Node Sensor String",
"ignore_string": "Ignore String",
"variable_sensor_string": "Variable Sensor String",
"restore_light_state": "Restore Light Brightness"
}
}

View File

@ -27,10 +27,11 @@
"step": {
"init": {
"title": "ISY994 Options",
"description": "Set the options for the ISY Integration: \n • Node Sensor String: Any device or folder that contains 'Node Sensor String' in the name will be treated as a sensor or binary sensor. \n • Ignore String: Any device with 'Ignore String' in the name will be ignored. \n • Restore Light Brightness: If enabled, the previous brightness will be restored when turning on a light instead of the device's built-in On-Level.",
"description": "Set the options for the ISY Integration: \n • Node Sensor String: Any device or folder that contains 'Node Sensor String' in the name will be treated as a sensor or binary sensor. \n • Ignore String: Any device with 'Ignore String' in the name will be ignored. \n • Variable Sensor String: Any variable that contains 'Variable Sensor String' will be added as a sensor. \n • Restore Light Brightness: If enabled, the previous brightness will be restored when turning on a light instead of the device's built-in On-Level.",
"data": {
"sensor_string": "Node Sensor String",
"ignore_string": "Ignore String",
"variable_sensor_string" : "Variable Sensor String",
"restore_light_state": "Restore Light Brightness"
}
}

View File

@ -7,6 +7,7 @@ from homeassistant.components.isy994.const import (
CONF_RESTORE_LIGHT_STATE,
CONF_SENSOR_STRING,
CONF_TLS_VER,
CONF_VAR_SENSOR_STRING,
DOMAIN,
)
from homeassistant.config_entries import SOURCE_IMPORT
@ -25,6 +26,7 @@ MOCK_TLS_VERSION = 1.2
MOCK_IGNORE_STRING = "{IGNOREME}"
MOCK_RESTORE_LIGHT_STATE = True
MOCK_SENSOR_STRING = "IMASENSOR"
MOCK_VARIABLE_SENSOR_STRING = "HomeAssistant."
MOCK_USER_INPUT = {
"host": f"http://{MOCK_HOSTNAME}",
@ -45,6 +47,7 @@ MOCK_IMPORT_FULL_CONFIG = {
CONF_RESTORE_LIGHT_STATE: MOCK_RESTORE_LIGHT_STATE,
CONF_SENSOR_STRING: MOCK_SENSOR_STRING,
CONF_TLS_VER: MOCK_TLS_VERSION,
CONF_VAR_SENSOR_STRING: MOCK_VARIABLE_SENSOR_STRING,
}
MOCK_DEVICE_NAME = "Name of the device"
@ -203,4 +206,5 @@ async def test_import_flow_all_fields(hass: HomeAssistantType) -> None:
assert result["data"][CONF_IGNORE_STRING] == MOCK_IGNORE_STRING
assert result["data"][CONF_RESTORE_LIGHT_STATE] == MOCK_RESTORE_LIGHT_STATE
assert result["data"][CONF_SENSOR_STRING] == MOCK_SENSOR_STRING
assert result["data"][CONF_VAR_SENSOR_STRING] == MOCK_VARIABLE_SENSOR_STRING
assert result["data"][CONF_TLS_VER] == MOCK_TLS_VERSION