Mark entities for dead zwave_js nodes as unavailable (#48017)

* Don't create any devices or entities for dead zwave_js nodes

* mark entities for dead nodes as unavailable

* add test

* watch for node status updates

* update tests to handle node status changes as well
This commit is contained in:
Raman Gupta 2021-07-03 22:06:07 -04:00 committed by GitHub
parent 378b5f75ec
commit 8f186957ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 3 deletions

View File

@ -4,6 +4,7 @@ from __future__ import annotations
import logging
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.model.node import NodeStatus
from zwave_js_server.model.value import Value as ZwaveValue, get_value_id
from homeassistant.config_entries import ConfigEntry
@ -18,6 +19,8 @@ from .helpers import get_device_id, get_unique_id
LOGGER = logging.getLogger(__name__)
EVENT_VALUE_UPDATED = "value updated"
EVENT_DEAD = "dead"
EVENT_ALIVE = "alive"
class ZWaveBaseEntity(Entity):
@ -90,6 +93,11 @@ class ZWaveBaseEntity(Entity):
self.async_on_remove(
self.info.node.on(EVENT_VALUE_UPDATED, self._value_changed)
)
for status_event in (EVENT_ALIVE, EVENT_DEAD):
self.async_on_remove(
self.info.node.on(status_event, self._node_status_alive_or_dead)
)
self.async_on_remove(
async_dispatcher_connect(
self.hass,
@ -135,7 +143,20 @@ class ZWaveBaseEntity(Entity):
@property
def available(self) -> bool:
"""Return entity availability."""
return self.client.connected and bool(self.info.node.ready)
return (
self.client.connected
and bool(self.info.node.ready)
and self.info.node.status != NodeStatus.DEAD
)
@callback
def _node_status_alive_or_dead(self, event_data: dict) -> None:
"""
Call when node status changes to alive or dead.
Should not be overridden by subclasses.
"""
self.async_write_ha_state()
@callback
def _value_changed(self, event_data: dict) -> None:

View File

@ -22,6 +22,7 @@ CLIMATE_MAIN_HEAT_ACTIONNER = "climate.main_heat_actionner"
BULB_6_MULTI_COLOR_LIGHT_ENTITY = "light.bulb_6_multi_color"
EATON_RF9640_ENTITY = "light.allloaddimmer"
AEON_SMART_SWITCH_LIGHT_ENTITY = "light.smart_switch_6"
SCHLAGE_BE469_LOCK_ENTITY = "lock.touchscreen_deadbolt"
ID_LOCK_CONFIG_PARAMETER_SENSOR = (
"sensor.z_wave_module_for_id_lock_150_and_101_config_parameter_door_lock_mode"
)

View File

@ -1,6 +1,7 @@
"""Test the Z-Wave JS lock platform."""
from zwave_js_server.const import ATTR_CODE_SLOT, ATTR_USERCODE
from zwave_js_server.event import Event
from zwave_js_server.model.node import NodeStatus
from homeassistant.components.lock import (
DOMAIN as LOCK_DOMAIN,
@ -12,9 +13,14 @@ from homeassistant.components.zwave_js.lock import (
SERVICE_CLEAR_LOCK_USERCODE,
SERVICE_SET_LOCK_USERCODE,
)
from homeassistant.const import ATTR_ENTITY_ID, STATE_LOCKED, STATE_UNLOCKED
from homeassistant.const import (
ATTR_ENTITY_ID,
STATE_LOCKED,
STATE_UNAVAILABLE,
STATE_UNLOCKED,
)
SCHLAGE_BE469_LOCK_ENTITY = "lock.touchscreen_deadbolt"
from .common import SCHLAGE_BE469_LOCK_ENTITY
async def test_door_lock(hass, client, lock_schlage_be469, integration):
@ -203,3 +209,16 @@ async def test_door_lock(hass, client, lock_schlage_be469, integration):
"value": 1,
}
assert args["value"] == 0
event = Event(
type="dead",
data={
"source": "node",
"event": "dead",
"nodeId": 20,
},
)
node.receive_event(event)
assert node.status == NodeStatus.DEAD
assert hass.states.get(SCHLAGE_BE469_LOCK_ENTITY).state == STATE_UNAVAILABLE