Bypass zwave_js config validation if driver not ready (#83410)

pull/83482/head
Martin Hjelmare 2022-12-06 18:41:09 +01:00 committed by Paulus Schoutsen
parent 048553cd02
commit 1cfd292075
4 changed files with 149 additions and 9 deletions

View File

@ -4,6 +4,7 @@ from __future__ import annotations
from typing import cast
import voluptuous as vol
from zwave_js_server.client import Client as ZwaveClient
from zwave_js_server.const import ConfigurationValueType
from zwave_js_server.model.node import Node
from zwave_js_server.model.value import ConfigurationValue
@ -12,7 +13,7 @@ from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import device_registry as dr
from .const import DOMAIN
from .const import DATA_CLIENT, DOMAIN
NODE_STATUSES = ["asleep", "awake", "dead", "alive"]
@ -66,4 +67,9 @@ def async_bypass_dynamic_config_validation(hass: HomeAssistant, device_id: str)
),
None,
)
return not entry
if not entry:
return True
# The driver may not be ready when the config entry is loaded.
client: ZwaveClient = hass.data[DOMAIN][entry.entry_id][DATA_CLIENT]
return client.driver is None

View File

@ -1,11 +1,13 @@
"""Helpers for Z-Wave JS custom triggers."""
from zwave_js_server.client import Client as ZwaveClient
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import ATTR_DEVICE_ID, ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.typing import ConfigType
from ..const import ATTR_CONFIG_ENTRY_ID, DOMAIN
from ..const import ATTR_CONFIG_ENTRY_ID, DATA_CLIENT, DOMAIN
@callback
@ -19,9 +21,8 @@ def async_bypass_dynamic_config_validation(
ent_reg = er.async_get(hass)
trigger_devices = config.get(ATTR_DEVICE_ID, [])
trigger_entities = config.get(ATTR_ENTITY_ID, [])
return any(
entry.state != ConfigEntryState.LOADED
and (
for entry in hass.config_entries.async_entries(DOMAIN):
if entry.state != ConfigEntryState.LOADED and (
entry.entry_id == config.get(ATTR_CONFIG_ENTRY_ID)
or any(
device.id in trigger_devices
@ -31,6 +32,12 @@ def async_bypass_dynamic_config_validation(
entity.entity_id in trigger_entities
for entity in er.async_entries_for_config_entry(ent_reg, entry.entry_id)
)
)
for entry in hass.config_entries.async_entries(DOMAIN)
)
):
return True
# The driver may not be ready when the config entry is loaded.
client: ZwaveClient = hass.data[DOMAIN][entry.entry_id][DATA_CLIENT]
if client.driver is None:
return True
return False

View File

@ -1080,6 +1080,74 @@ async def test_if_value_updated_value_fires(
)
async def test_value_updated_value_no_driver(
hass, client, lock_schlage_be469, integration, calls
):
"""Test zwave_js.value_updated.value trigger with missing driver."""
node: Node = lock_schlage_be469
dev_reg = async_get_dev_reg(hass)
device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
driver = client.driver
client.driver = None
assert await async_setup_component(
hass,
automation.DOMAIN,
{
automation.DOMAIN: [
{
"trigger": {
"platform": "device",
"domain": DOMAIN,
"device_id": device.id,
"type": "zwave_js.value_updated.value",
"command_class": CommandClass.DOOR_LOCK.value,
"property": "latchStatus",
"property_key": None,
"endpoint": None,
"from": "open",
},
"action": {
"service": "test.automation",
"data_template": {
"some": (
"zwave_js.value_updated.value - "
"{{ trigger.platform}} - "
"{{ trigger.previous_value }}"
)
},
},
},
]
},
)
await hass.async_block_till_done()
client.driver = driver
# No trigger as automation failed to setup.
event = Event(
type="value updated",
data={
"source": "node",
"event": "value updated",
"nodeId": node.node_id,
"args": {
"commandClassName": "Door Lock",
"commandClass": 98,
"endpoint": 0,
"property": "latchStatus",
"newValue": "closed",
"prevValue": "open",
"propertyName": "latchStatus",
},
},
)
node.receive_event(event)
await hass.async_block_till_done()
assert len(calls) == 0
async def test_get_trigger_capabilities_value_updated_value(
hass, client, lock_schlage_be469, integration
):

View File

@ -385,6 +385,65 @@ async def test_zwave_js_value_updated_bypass_dynamic_validation_no_nodes(
assert len(no_value_filter) == 0
async def test_zwave_js_value_updated_bypass_dynamic_validation_no_driver(
hass, client, lock_schlage_be469, integration
):
"""Test zwave_js.value_updated trigger without driver."""
trigger_type = f"{DOMAIN}.value_updated"
node: Node = lock_schlage_be469
driver = client.driver
client.driver = None
no_value_filter = async_capture_events(hass, "no_value_filter")
assert await async_setup_component(
hass,
automation.DOMAIN,
{
automation.DOMAIN: [
# no value filter
{
"trigger": {
"platform": trigger_type,
"entity_id": SCHLAGE_BE469_LOCK_ENTITY,
"command_class": CommandClass.DOOR_LOCK.value,
"property": "latchStatus",
},
"action": {
"event": "no_value_filter",
},
},
]
},
)
await hass.async_block_till_done()
client.driver = driver
# Test that no value filter is NOT triggered because automation failed setup
event = Event(
type="value updated",
data={
"source": "node",
"event": "value updated",
"nodeId": node.node_id,
"args": {
"commandClassName": "Door Lock",
"commandClass": 98,
"endpoint": 0,
"property": "latchStatus",
"newValue": "boo",
"prevValue": "hiss",
"propertyName": "latchStatus",
},
},
)
node.receive_event(event)
await hass.async_block_till_done()
assert len(no_value_filter) == 0
async def test_zwave_js_event(hass, client, lock_schlage_be469, integration):
"""Test for zwave_js.event automation trigger."""
trigger_type = f"{DOMAIN}.event"