From 3b8a2a72043c383568cabb999fca5244608c9282 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 15 Nov 2017 13:39:36 -0800 Subject: [PATCH 1/4] Fire events for ISY994 control events This allows hass to react directly to Insteon button presses (on switches and remotes), including presses, double-presses, and long holds --- homeassistant/components/isy994.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/homeassistant/components/isy994.py b/homeassistant/components/isy994.py index 7686eb7dc7de8..3942d61702f1f 100644 --- a/homeassistant/components/isy994.py +++ b/homeassistant/components/isy994.py @@ -231,11 +231,22 @@ def __init__(self, node) -> None: self._change_handler = self._node.status.subscribe( 'changed', self.on_update) + if hasattr(self._node, 'controlEvents'): + self._control_handler = self._node.controlEvents.subscribe( + self.on_control) + # pylint: disable=unused-argument def on_update(self, event: object) -> None: """Handle the update event from the ISY994 Node.""" self.schedule_update_ha_state() + def on_control(self, event: object) -> None: + """Handle a control event from the ISY994 Node.""" + self.hass.bus.fire('isy994_control', { + 'entity_id': self.entity_id, + 'control': event + }) + @property def domain(self) -> str: """Get the domain of the device.""" From 72bbd5d8464bd6b50c96e2f318c180c485a729de Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 25 Nov 2017 21:51:59 -0800 Subject: [PATCH 2/4] Move change event subscription to after entity is added to hass The event handler method requires `self.hass` to exist, which doesn't have a value until the async_added_to_hass method is called. Should eliminate a race condition. --- homeassistant/components/isy994.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/homeassistant/components/isy994.py b/homeassistant/components/isy994.py index 3942d61702f1f..dbdb294912f93 100644 --- a/homeassistant/components/isy994.py +++ b/homeassistant/components/isy994.py @@ -4,6 +4,7 @@ For configuration details please visit the documentation for this component at https://home-assistant.io/components/isy994/ """ +import asyncio from collections import namedtuple import logging from urllib.parse import urlparse @@ -227,7 +228,12 @@ class ISYDevice(Entity): def __init__(self, node) -> None: """Initialize the insteon device.""" self._node = node + self._change_handler = None + self._control_handler = None + @asyncio.coroutine + def async_added_to_hass(self) -> None: + """Subscribe to the node change events.""" self._change_handler = self._node.status.subscribe( 'changed', self.on_update) From 624ee066474e7df9bf60b7631fa221d7d33435c5 Mon Sep 17 00:00:00 2001 From: Greg Laabs Date: Wed, 6 Dec 2017 14:22:37 -0800 Subject: [PATCH 3/4] Add support for Unknown state, which is being added in next PyISY PyISY will report unknown states as the number "-inf". This is implemented in the base ISY994 component, but subcomponents that override the `state` method needed some extra logic to handle it as well. --- homeassistant/components/cover/isy994.py | 5 ++++- homeassistant/components/isy994.py | 18 +++++++++++++++++- homeassistant/components/lock/isy994.py | 5 ++++- homeassistant/components/sensor/isy994.py | 3 +++ homeassistant/components/switch/isy994.py | 5 ++++- 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/cover/isy994.py b/homeassistant/components/cover/isy994.py index 1e83038278cea..4dd1c9be364a1 100644 --- a/homeassistant/components/cover/isy994.py +++ b/homeassistant/components/cover/isy994.py @@ -69,7 +69,10 @@ def is_closed(self) -> bool: @property def state(self) -> str: """Get the state of the ISY994 cover device.""" - return VALUE_TO_STATE.get(self.value, STATE_OPEN) + if self.is_unknown(): + return None + else: + return VALUE_TO_STATE.get(self.value, STATE_OPEN) def open_cover(self, **kwargs) -> None: """Send the open cover command to the ISY994 cover device.""" diff --git a/homeassistant/components/isy994.py b/homeassistant/components/isy994.py index dbdb294912f93..b034e9439e70e 100644 --- a/homeassistant/components/isy994.py +++ b/homeassistant/components/isy994.py @@ -107,7 +107,8 @@ def _categorize_nodes(hidden_identifier: str, sensor_identifier: str) -> None: hidden = hidden_identifier in path or hidden_identifier in node.name if hidden: node.name += hidden_identifier - if sensor_identifier in path or sensor_identifier in node.name: + if (sensor_identifier in path or sensor_identifier in node.name) \ + and isinstance(node, PYISY.Nodes.Node): SENSOR_NODES.append(node) elif isinstance(node, PYISY.Nodes.Node): NODES.append(node) @@ -287,6 +288,21 @@ def value(self) -> object: # pylint: disable=protected-access return self._node.status._val + def is_unknown(self) -> bool: + """Get whether or not the value of this Entity's node is unknown. + + PyISY reports unknown values as -inf + """ + return self.value == -1 * float('inf') + + @property + def state(self): + """Return the state of the ISY device.""" + if self.is_unknown(): + return None + else: + return super().state + @property def device_state_attributes(self) -> Dict: """Get the state attributes for the device.""" diff --git a/homeassistant/components/lock/isy994.py b/homeassistant/components/lock/isy994.py index edbb8a34f240f..63272b90b1fa8 100644 --- a/homeassistant/components/lock/isy994.py +++ b/homeassistant/components/lock/isy994.py @@ -66,7 +66,10 @@ def is_locked(self) -> bool: @property def state(self) -> str: """Get the state of the lock.""" - return VALUE_TO_STATE.get(self.value, STATE_UNKNOWN) + if self.is_unknown(): + return None + else: + return VALUE_TO_STATE.get(self.value, STATE_UNKNOWN) def lock(self, **kwargs) -> None: """Send the lock command to the ISY994 device.""" diff --git a/homeassistant/components/sensor/isy994.py b/homeassistant/components/sensor/isy994.py index f64fa6191e225..e961c63a1b511 100644 --- a/homeassistant/components/sensor/isy994.py +++ b/homeassistant/components/sensor/isy994.py @@ -282,6 +282,9 @@ def raw_unit_of_measurement(self) -> str: @property def state(self) -> str: """Get the state of the ISY994 sensor device.""" + if self.is_unknown(): + return None + if len(self._node.uom) == 1: if self._node.uom[0] in UOM_TO_STATES: states = UOM_TO_STATES.get(self._node.uom[0]) diff --git a/homeassistant/components/switch/isy994.py b/homeassistant/components/switch/isy994.py index b930bedc2c7a4..0f1ec62eaeef0 100644 --- a/homeassistant/components/switch/isy994.py +++ b/homeassistant/components/switch/isy994.py @@ -69,7 +69,10 @@ def is_on(self) -> bool: @property def state(self) -> str: """Get the state of the ISY994 device.""" - return VALUE_TO_STATE.get(bool(self.value), STATE_UNKNOWN) + if self.is_unknown(): + return None + else: + return VALUE_TO_STATE.get(bool(self.value), STATE_UNKNOWN) def turn_off(self, **kwargs) -> None: """Send the turn on command to the ISY994 switch.""" From e5da5bce3ca14ee5282d7d1c5bf5130dd76e7ed1 Mon Sep 17 00:00:00 2001 From: Greg Laabs Date: Thu, 7 Dec 2017 23:52:58 -0800 Subject: [PATCH 4/4] Bump PyISY to 1.1.0, now that it has been published! --- homeassistant/components/isy994.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/isy994.py b/homeassistant/components/isy994.py index b034e9439e70e..9012989e180ee 100644 --- a/homeassistant/components/isy994.py +++ b/homeassistant/components/isy994.py @@ -18,7 +18,7 @@ from homeassistant.helpers.entity import Entity from homeassistant.helpers.typing import ConfigType, Dict # noqa -REQUIREMENTS = ['PyISY==1.0.8'] +REQUIREMENTS = ['PyISY==1.1.0'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 840ed5a834ac7..3d1d99180b1ca 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -23,7 +23,7 @@ certifi>=2017.4.17 DoorBirdPy==0.1.0 # homeassistant.components.isy994 -PyISY==1.0.8 +PyISY==1.1.0 # homeassistant.components.notify.html5 PyJWT==1.5.3