mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 02:37:08 +00:00
Bump zwave-js-server-python to 0.23.0 to support zwave-js 7 (#48094)
* Bump zwave-js-server-python to 0.23.0 and update integration to support schema changes * refactor notification evenets a bit * fix tests and bug fixes * additional changes due to new PR * add command class and command name * use new event names so we can retain event property names * handle command status being returned from async_set_config_parameter * bump dependency version * adjust log message to be consistent * disable pylint warning * Update homeassistant/components/zwave_js/services.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * add test for awake node * switch async_get_registry to async_get Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
cf6352e93c
commit
dda9f957b6
@ -8,7 +8,10 @@ from async_timeout import timeout
|
|||||||
from zwave_js_server.client import Client as ZwaveClient
|
from zwave_js_server.client import Client as ZwaveClient
|
||||||
from zwave_js_server.exceptions import BaseZwaveJSServerError, InvalidServerVersion
|
from zwave_js_server.exceptions import BaseZwaveJSServerError, InvalidServerVersion
|
||||||
from zwave_js_server.model.node import Node as ZwaveNode
|
from zwave_js_server.model.node import Node as ZwaveNode
|
||||||
from zwave_js_server.model.notification import Notification
|
from zwave_js_server.model.notification import (
|
||||||
|
EntryControlNotification,
|
||||||
|
NotificationNotification,
|
||||||
|
)
|
||||||
from zwave_js_server.model.value import ValueNotification
|
from zwave_js_server.model.value import ValueNotification
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
@ -29,7 +32,12 @@ from .api import async_register_api
|
|||||||
from .const import (
|
from .const import (
|
||||||
ATTR_COMMAND_CLASS,
|
ATTR_COMMAND_CLASS,
|
||||||
ATTR_COMMAND_CLASS_NAME,
|
ATTR_COMMAND_CLASS_NAME,
|
||||||
|
ATTR_DATA_TYPE,
|
||||||
ATTR_ENDPOINT,
|
ATTR_ENDPOINT,
|
||||||
|
ATTR_EVENT,
|
||||||
|
ATTR_EVENT_DATA,
|
||||||
|
ATTR_EVENT_LABEL,
|
||||||
|
ATTR_EVENT_TYPE,
|
||||||
ATTR_HOME_ID,
|
ATTR_HOME_ID,
|
||||||
ATTR_LABEL,
|
ATTR_LABEL,
|
||||||
ATTR_NODE_ID,
|
ATTR_NODE_ID,
|
||||||
@ -51,7 +59,8 @@ from .const import (
|
|||||||
EVENT_DEVICE_ADDED_TO_REGISTRY,
|
EVENT_DEVICE_ADDED_TO_REGISTRY,
|
||||||
LOGGER,
|
LOGGER,
|
||||||
PLATFORMS,
|
PLATFORMS,
|
||||||
ZWAVE_JS_EVENT,
|
ZWAVE_JS_NOTIFICATION_EVENT,
|
||||||
|
ZWAVE_JS_VALUE_NOTIFICATION_EVENT,
|
||||||
)
|
)
|
||||||
from .discovery import async_discover_values
|
from .discovery import async_discover_values
|
||||||
from .helpers import get_device_id
|
from .helpers import get_device_id
|
||||||
@ -102,7 +111,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
await async_ensure_addon_running(hass, entry)
|
await async_ensure_addon_running(hass, entry)
|
||||||
|
|
||||||
client = ZwaveClient(entry.data[CONF_URL], async_get_clientsession(hass))
|
client = ZwaveClient(entry.data[CONF_URL], async_get_clientsession(hass))
|
||||||
dev_reg = await device_registry.async_get_registry(hass)
|
dev_reg = device_registry.async_get(hass)
|
||||||
ent_reg = entity_registry.async_get(hass)
|
ent_reg = entity_registry.async_get(hass)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@ -169,9 +178,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
if notification.metadata.states:
|
if notification.metadata.states:
|
||||||
value = notification.metadata.states.get(str(value), value)
|
value = notification.metadata.states.get(str(value), value)
|
||||||
hass.bus.async_fire(
|
hass.bus.async_fire(
|
||||||
ZWAVE_JS_EVENT,
|
ZWAVE_JS_VALUE_NOTIFICATION_EVENT,
|
||||||
{
|
{
|
||||||
ATTR_TYPE: "value_notification",
|
|
||||||
ATTR_DOMAIN: DOMAIN,
|
ATTR_DOMAIN: DOMAIN,
|
||||||
ATTR_NODE_ID: notification.node.node_id,
|
ATTR_NODE_ID: notification.node.node_id,
|
||||||
ATTR_HOME_ID: client.driver.controller.home_id,
|
ATTR_HOME_ID: client.driver.controller.home_id,
|
||||||
@ -190,21 +198,41 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_on_notification(notification: Notification) -> None:
|
def async_on_notification(
|
||||||
|
notification: EntryControlNotification | NotificationNotification,
|
||||||
|
) -> None:
|
||||||
"""Relay stateless notification events from Z-Wave nodes to hass."""
|
"""Relay stateless notification events from Z-Wave nodes to hass."""
|
||||||
device = dev_reg.async_get_device({get_device_id(client, notification.node)})
|
device = dev_reg.async_get_device({get_device_id(client, notification.node)})
|
||||||
hass.bus.async_fire(
|
event_data = {
|
||||||
ZWAVE_JS_EVENT,
|
ATTR_DOMAIN: DOMAIN,
|
||||||
{
|
ATTR_NODE_ID: notification.node.node_id,
|
||||||
ATTR_TYPE: "notification",
|
ATTR_HOME_ID: client.driver.controller.home_id,
|
||||||
ATTR_DOMAIN: DOMAIN,
|
ATTR_DEVICE_ID: device.id, # type: ignore
|
||||||
ATTR_NODE_ID: notification.node.node_id,
|
ATTR_COMMAND_CLASS: notification.command_class,
|
||||||
ATTR_HOME_ID: client.driver.controller.home_id,
|
}
|
||||||
ATTR_DEVICE_ID: device.id, # type: ignore
|
|
||||||
ATTR_LABEL: notification.notification_label,
|
if isinstance(notification, EntryControlNotification):
|
||||||
ATTR_PARAMETERS: notification.parameters,
|
event_data.update(
|
||||||
},
|
{
|
||||||
)
|
ATTR_COMMAND_CLASS_NAME: "Entry Control",
|
||||||
|
ATTR_EVENT_TYPE: notification.event_type,
|
||||||
|
ATTR_DATA_TYPE: notification.data_type,
|
||||||
|
ATTR_EVENT_DATA: notification.event_data,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
event_data.update(
|
||||||
|
{
|
||||||
|
ATTR_COMMAND_CLASS_NAME: "Notification",
|
||||||
|
ATTR_LABEL: notification.label,
|
||||||
|
ATTR_TYPE: notification.type_,
|
||||||
|
ATTR_EVENT: notification.event,
|
||||||
|
ATTR_EVENT_LABEL: notification.event_label,
|
||||||
|
ATTR_PARAMETERS: notification.parameters,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.bus.async_fire(ZWAVE_JS_NOTIFICATION_EVENT, event_data)
|
||||||
|
|
||||||
entry_hass_data: dict = hass.data[DOMAIN].setdefault(entry.entry_id, {})
|
entry_hass_data: dict = hass.data[DOMAIN].setdefault(entry.entry_id, {})
|
||||||
# connect and throw error if connection failed
|
# connect and throw error if connection failed
|
||||||
|
@ -46,6 +46,10 @@ FILENAME = "filename"
|
|||||||
ENABLED = "enabled"
|
ENABLED = "enabled"
|
||||||
FORCE_CONSOLE = "force_console"
|
FORCE_CONSOLE = "force_console"
|
||||||
|
|
||||||
|
# constants for setting config parameters
|
||||||
|
VALUE_ID = "value_id"
|
||||||
|
STATUS = "status"
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_register_api(hass: HomeAssistant) -> None:
|
def async_register_api(hass: HomeAssistant) -> None:
|
||||||
@ -321,7 +325,7 @@ async def websocket_set_config_parameter(
|
|||||||
client = hass.data[DOMAIN][entry_id][DATA_CLIENT]
|
client = hass.data[DOMAIN][entry_id][DATA_CLIENT]
|
||||||
node = client.driver.controller.nodes[node_id]
|
node = client.driver.controller.nodes[node_id]
|
||||||
try:
|
try:
|
||||||
result = await async_set_config_parameter(
|
zwave_value, cmd_status = await async_set_config_parameter(
|
||||||
node, value, property_, property_key=property_key
|
node, value, property_, property_key=property_key
|
||||||
)
|
)
|
||||||
except (InvalidNewValue, NotFoundError, NotImplementedError, SetValueFailed) as err:
|
except (InvalidNewValue, NotFoundError, NotImplementedError, SetValueFailed) as err:
|
||||||
@ -340,7 +344,10 @@ async def websocket_set_config_parameter(
|
|||||||
|
|
||||||
connection.send_result(
|
connection.send_result(
|
||||||
msg[ID],
|
msg[ID],
|
||||||
str(result),
|
{
|
||||||
|
VALUE_ID: zwave_value.value_id,
|
||||||
|
STATUS: cmd_status,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -395,11 +402,6 @@ def websocket_get_config_parameters(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def convert_log_level_to_enum(value: str) -> LogLevel:
|
|
||||||
"""Convert log level string to LogLevel enum."""
|
|
||||||
return LogLevel[value.upper()]
|
|
||||||
|
|
||||||
|
|
||||||
def filename_is_present_if_logging_to_file(obj: dict) -> dict:
|
def filename_is_present_if_logging_to_file(obj: dict) -> dict:
|
||||||
"""Validate that filename is provided if log_to_file is True."""
|
"""Validate that filename is provided if log_to_file is True."""
|
||||||
if obj.get(LOG_TO_FILE, False) and FILENAME not in obj:
|
if obj.get(LOG_TO_FILE, False) and FILENAME not in obj:
|
||||||
@ -420,8 +422,8 @@ def filename_is_present_if_logging_to_file(obj: dict) -> dict:
|
|||||||
vol.Optional(LEVEL): vol.All(
|
vol.Optional(LEVEL): vol.All(
|
||||||
cv.string,
|
cv.string,
|
||||||
vol.Lower,
|
vol.Lower,
|
||||||
vol.In([log_level.name.lower() for log_level in LogLevel]),
|
vol.In([log_level.value for log_level in LogLevel]),
|
||||||
lambda val: LogLevel[val.upper()],
|
lambda val: LogLevel(val), # pylint: disable=unnecessary-lambda
|
||||||
),
|
),
|
||||||
vol.Optional(LOG_TO_FILE): cv.boolean,
|
vol.Optional(LOG_TO_FILE): cv.boolean,
|
||||||
vol.Optional(FILENAME): cv.string,
|
vol.Optional(FILENAME): cv.string,
|
||||||
|
@ -135,7 +135,7 @@ class ZWaveClimate(ZWaveBaseEntity, ClimateEntity):
|
|||||||
self._setpoint_values[enum] = self.get_zwave_value(
|
self._setpoint_values[enum] = self.get_zwave_value(
|
||||||
THERMOSTAT_SETPOINT_PROPERTY,
|
THERMOSTAT_SETPOINT_PROPERTY,
|
||||||
command_class=CommandClass.THERMOSTAT_SETPOINT,
|
command_class=CommandClass.THERMOSTAT_SETPOINT,
|
||||||
value_property_key=enum.value.key,
|
value_property_key=enum.value,
|
||||||
add_to_watched_value_ids=True,
|
add_to_watched_value_ids=True,
|
||||||
)
|
)
|
||||||
# Use the first found non N/A setpoint value to always determine the
|
# Use the first found non N/A setpoint value to always determine the
|
||||||
|
@ -28,7 +28,8 @@ EVENT_DEVICE_ADDED_TO_REGISTRY = f"{DOMAIN}_device_added_to_registry"
|
|||||||
LOGGER = logging.getLogger(__package__)
|
LOGGER = logging.getLogger(__package__)
|
||||||
|
|
||||||
# constants for events
|
# constants for events
|
||||||
ZWAVE_JS_EVENT = f"{DOMAIN}_event"
|
ZWAVE_JS_VALUE_NOTIFICATION_EVENT = f"{DOMAIN}_value_notification"
|
||||||
|
ZWAVE_JS_NOTIFICATION_EVENT = f"{DOMAIN}_notification"
|
||||||
ATTR_NODE_ID = "node_id"
|
ATTR_NODE_ID = "node_id"
|
||||||
ATTR_HOME_ID = "home_id"
|
ATTR_HOME_ID = "home_id"
|
||||||
ATTR_ENDPOINT = "endpoint"
|
ATTR_ENDPOINT = "endpoint"
|
||||||
@ -43,6 +44,11 @@ ATTR_PROPERTY_KEY_NAME = "property_key_name"
|
|||||||
ATTR_PROPERTY = "property"
|
ATTR_PROPERTY = "property"
|
||||||
ATTR_PROPERTY_KEY = "property_key"
|
ATTR_PROPERTY_KEY = "property_key"
|
||||||
ATTR_PARAMETERS = "parameters"
|
ATTR_PARAMETERS = "parameters"
|
||||||
|
ATTR_EVENT = "event"
|
||||||
|
ATTR_EVENT_LABEL = "event_label"
|
||||||
|
ATTR_EVENT_TYPE = "event_type"
|
||||||
|
ATTR_EVENT_DATA = "event_data"
|
||||||
|
ATTR_DATA_TYPE = "data_type"
|
||||||
|
|
||||||
# service constants
|
# service constants
|
||||||
SERVICE_SET_CONFIG_PARAMETER = "set_config_parameter"
|
SERVICE_SET_CONFIG_PARAMETER = "set_config_parameter"
|
||||||
|
@ -247,12 +247,11 @@ class ZwaveLight(ZWaveBaseEntity, LightEntity):
|
|||||||
|
|
||||||
async def _async_set_color(self, color: ColorComponent, new_value: int) -> None:
|
async def _async_set_color(self, color: ColorComponent, new_value: int) -> None:
|
||||||
"""Set defined color to given value."""
|
"""Set defined color to given value."""
|
||||||
property_key = color.value
|
|
||||||
# actually set the new color value
|
# actually set the new color value
|
||||||
target_zwave_value = self.get_zwave_value(
|
target_zwave_value = self.get_zwave_value(
|
||||||
"targetColor",
|
"targetColor",
|
||||||
CommandClass.SWITCH_COLOR,
|
CommandClass.SWITCH_COLOR,
|
||||||
value_property_key=property_key.key,
|
value_property_key=color.value,
|
||||||
)
|
)
|
||||||
if target_zwave_value is None:
|
if target_zwave_value is None:
|
||||||
# guard for unsupported color
|
# guard for unsupported color
|
||||||
@ -315,27 +314,27 @@ class ZwaveLight(ZWaveBaseEntity, LightEntity):
|
|||||||
red_val = self.get_zwave_value(
|
red_val = self.get_zwave_value(
|
||||||
"currentColor",
|
"currentColor",
|
||||||
CommandClass.SWITCH_COLOR,
|
CommandClass.SWITCH_COLOR,
|
||||||
value_property_key=ColorComponent.RED.value.key,
|
value_property_key=ColorComponent.RED.value,
|
||||||
)
|
)
|
||||||
green_val = self.get_zwave_value(
|
green_val = self.get_zwave_value(
|
||||||
"currentColor",
|
"currentColor",
|
||||||
CommandClass.SWITCH_COLOR,
|
CommandClass.SWITCH_COLOR,
|
||||||
value_property_key=ColorComponent.GREEN.value.key,
|
value_property_key=ColorComponent.GREEN.value,
|
||||||
)
|
)
|
||||||
blue_val = self.get_zwave_value(
|
blue_val = self.get_zwave_value(
|
||||||
"currentColor",
|
"currentColor",
|
||||||
CommandClass.SWITCH_COLOR,
|
CommandClass.SWITCH_COLOR,
|
||||||
value_property_key=ColorComponent.BLUE.value.key,
|
value_property_key=ColorComponent.BLUE.value,
|
||||||
)
|
)
|
||||||
ww_val = self.get_zwave_value(
|
ww_val = self.get_zwave_value(
|
||||||
"currentColor",
|
"currentColor",
|
||||||
CommandClass.SWITCH_COLOR,
|
CommandClass.SWITCH_COLOR,
|
||||||
value_property_key=ColorComponent.WARM_WHITE.value.key,
|
value_property_key=ColorComponent.WARM_WHITE.value,
|
||||||
)
|
)
|
||||||
cw_val = self.get_zwave_value(
|
cw_val = self.get_zwave_value(
|
||||||
"currentColor",
|
"currentColor",
|
||||||
CommandClass.SWITCH_COLOR,
|
CommandClass.SWITCH_COLOR,
|
||||||
value_property_key=ColorComponent.COLD_WHITE.value.key,
|
value_property_key=ColorComponent.COLD_WHITE.value,
|
||||||
)
|
)
|
||||||
# prefer the (new) combined color property
|
# prefer the (new) combined color property
|
||||||
# https://github.com/zwave-js/node-zwave-js/pull/1782
|
# https://github.com/zwave-js/node-zwave-js/pull/1782
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Z-Wave JS",
|
"name": "Z-Wave JS",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/zwave_js",
|
"documentation": "https://www.home-assistant.io/integrations/zwave_js",
|
||||||
"requirements": ["zwave-js-server-python==0.22.0"],
|
"requirements": ["zwave-js-server-python==0.23.0"],
|
||||||
"codeowners": ["@home-assistant/z-wave"],
|
"codeowners": ["@home-assistant/z-wave"],
|
||||||
"dependencies": ["http", "websocket_api"]
|
"dependencies": ["http", "websocket_api"]
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
from zwave_js_server.const import CommandStatus
|
||||||
from zwave_js_server.model.node import Node as ZwaveNode
|
from zwave_js_server.model.node import Node as ZwaveNode
|
||||||
from zwave_js_server.util.node import async_set_config_parameter
|
from zwave_js_server.util.node import async_set_config_parameter
|
||||||
|
|
||||||
@ -104,26 +105,23 @@ class ZWaveServices:
|
|||||||
new_value = service.data[const.ATTR_CONFIG_VALUE]
|
new_value = service.data[const.ATTR_CONFIG_VALUE]
|
||||||
|
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
zwave_value = await async_set_config_parameter(
|
zwave_value, cmd_status = await async_set_config_parameter(
|
||||||
node,
|
node,
|
||||||
new_value,
|
new_value,
|
||||||
property_or_property_name,
|
property_or_property_name,
|
||||||
property_key=property_key,
|
property_key=property_key,
|
||||||
)
|
)
|
||||||
|
|
||||||
if zwave_value:
|
if cmd_status == CommandStatus.ACCEPTED:
|
||||||
_LOGGER.info(
|
msg = "Set configuration parameter %s on Node %s with value %s"
|
||||||
"Set configuration parameter %s on Node %s with value %s",
|
|
||||||
zwave_value,
|
|
||||||
node,
|
|
||||||
new_value,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
msg = (
|
||||||
f"Unable to set configuration parameter on Node {node} with "
|
"Added command to queue to set configuration parameter %s on Node "
|
||||||
f"value {new_value}"
|
"%s with value %s. Parameter will be set when the device wakes up"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_LOGGER.info(msg, zwave_value, node, new_value)
|
||||||
|
|
||||||
async def async_poll_value(self, service: ServiceCall) -> None:
|
async def async_poll_value(self, service: ServiceCall) -> None:
|
||||||
"""Poll value on a node."""
|
"""Poll value on a node."""
|
||||||
for entity_id in service.data[ATTR_ENTITY_ID]:
|
for entity_id in service.data[ATTR_ENTITY_ID]:
|
||||||
|
@ -2402,4 +2402,4 @@ zigpy==0.33.0
|
|||||||
zm-py==0.5.2
|
zm-py==0.5.2
|
||||||
|
|
||||||
# homeassistant.components.zwave_js
|
# homeassistant.components.zwave_js
|
||||||
zwave-js-server-python==0.22.0
|
zwave-js-server-python==0.23.0
|
||||||
|
@ -1251,4 +1251,4 @@ zigpy-znp==0.4.0
|
|||||||
zigpy==0.33.0
|
zigpy==0.33.0
|
||||||
|
|
||||||
# homeassistant.components.zwave_js
|
# homeassistant.components.zwave_js
|
||||||
zwave-js-server-python==0.22.0
|
zwave-js-server-python==0.23.0
|
||||||
|
@ -381,7 +381,7 @@ async def test_update_log_config(hass, client, integration, hass_ws_client):
|
|||||||
assert len(client.async_send_command.call_args_list) == 1
|
assert len(client.async_send_command.call_args_list) == 1
|
||||||
args = client.async_send_command.call_args[0][0]
|
args = client.async_send_command.call_args[0][0]
|
||||||
assert args["command"] == "update_log_config"
|
assert args["command"] == "update_log_config"
|
||||||
assert args["config"] == {"level": 0}
|
assert args["config"] == {"level": "error"}
|
||||||
|
|
||||||
client.async_send_command.reset_mock()
|
client.async_send_command.reset_mock()
|
||||||
|
|
||||||
@ -428,7 +428,7 @@ async def test_update_log_config(hass, client, integration, hass_ws_client):
|
|||||||
args = client.async_send_command.call_args[0][0]
|
args = client.async_send_command.call_args[0][0]
|
||||||
assert args["command"] == "update_log_config"
|
assert args["command"] == "update_log_config"
|
||||||
assert args["config"] == {
|
assert args["config"] == {
|
||||||
"level": 0,
|
"level": "error",
|
||||||
"logToFile": True,
|
"logToFile": True,
|
||||||
"filename": "/test",
|
"filename": "/test",
|
||||||
"forceConsole": True,
|
"forceConsole": True,
|
||||||
@ -490,7 +490,7 @@ async def test_get_log_config(hass, client, integration, hass_ws_client):
|
|||||||
"success": True,
|
"success": True,
|
||||||
"config": {
|
"config": {
|
||||||
"enabled": True,
|
"enabled": True,
|
||||||
"level": 0,
|
"level": "error",
|
||||||
"logToFile": False,
|
"logToFile": False,
|
||||||
"filename": "/test.txt",
|
"filename": "/test.txt",
|
||||||
"forceConsole": False,
|
"forceConsole": False,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
"""Test Z-Wave JS (value notification) events."""
|
"""Test Z-Wave JS (value notification) events."""
|
||||||
|
from zwave_js_server.const import CommandClass
|
||||||
from zwave_js_server.event import Event
|
from zwave_js_server.event import Event
|
||||||
|
|
||||||
from tests.common import async_capture_events
|
from tests.common import async_capture_events
|
||||||
@ -8,7 +9,7 @@ async def test_scenes(hass, hank_binary_switch, integration, client):
|
|||||||
"""Test scene events."""
|
"""Test scene events."""
|
||||||
# just pick a random node to fake the value notification events
|
# just pick a random node to fake the value notification events
|
||||||
node = hank_binary_switch
|
node = hank_binary_switch
|
||||||
events = async_capture_events(hass, "zwave_js_event")
|
events = async_capture_events(hass, "zwave_js_value_notification")
|
||||||
|
|
||||||
# Publish fake Basic Set value notification
|
# Publish fake Basic Set value notification
|
||||||
event = Event(
|
event = Event(
|
||||||
@ -137,25 +138,59 @@ async def test_notifications(hass, hank_binary_switch, integration, client):
|
|||||||
"""Test notification events."""
|
"""Test notification events."""
|
||||||
# just pick a random node to fake the value notification events
|
# just pick a random node to fake the value notification events
|
||||||
node = hank_binary_switch
|
node = hank_binary_switch
|
||||||
events = async_capture_events(hass, "zwave_js_event")
|
events = async_capture_events(hass, "zwave_js_notification")
|
||||||
|
|
||||||
# Publish fake Basic Set value notification
|
# Publish fake Notification CC notification
|
||||||
event = Event(
|
event = Event(
|
||||||
type="notification",
|
type="notification",
|
||||||
data={
|
data={
|
||||||
"source": "node",
|
"source": "node",
|
||||||
"event": "notification",
|
"event": "notification",
|
||||||
"nodeId": 23,
|
"nodeId": 32,
|
||||||
"notificationLabel": "Keypad lock operation",
|
"ccId": 113,
|
||||||
"parameters": {"userId": 1},
|
"args": {
|
||||||
|
"type": 6,
|
||||||
|
"event": 5,
|
||||||
|
"label": "Access Control",
|
||||||
|
"eventLabel": "Keypad lock operation",
|
||||||
|
"parameters": {"userId": 1},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
node.receive_event(event)
|
node.receive_event(event)
|
||||||
# wait for the event
|
# wait for the event
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
assert events[0].data["type"] == "notification"
|
|
||||||
assert events[0].data["home_id"] == client.driver.controller.home_id
|
assert events[0].data["home_id"] == client.driver.controller.home_id
|
||||||
assert events[0].data["node_id"] == 32
|
assert events[0].data["node_id"] == 32
|
||||||
assert events[0].data["label"] == "Keypad lock operation"
|
assert events[0].data["type"] == 6
|
||||||
|
assert events[0].data["event"] == 5
|
||||||
|
assert events[0].data["label"] == "Access Control"
|
||||||
|
assert events[0].data["event_label"] == "Keypad lock operation"
|
||||||
assert events[0].data["parameters"]["userId"] == 1
|
assert events[0].data["parameters"]["userId"] == 1
|
||||||
|
assert events[0].data["command_class"] == CommandClass.NOTIFICATION
|
||||||
|
assert events[0].data["command_class_name"] == "Notification"
|
||||||
|
|
||||||
|
# Publish fake Entry Control CC notification
|
||||||
|
event = Event(
|
||||||
|
type="notification",
|
||||||
|
data={
|
||||||
|
"source": "node",
|
||||||
|
"event": "notification",
|
||||||
|
"nodeId": 32,
|
||||||
|
"ccId": 111,
|
||||||
|
"args": {"eventType": 5, "dataType": 2, "eventData": "555"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
node.receive_event(event)
|
||||||
|
# wait for the event
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(events) == 2
|
||||||
|
assert events[1].data["home_id"] == client.driver.controller.home_id
|
||||||
|
assert events[1].data["node_id"] == 32
|
||||||
|
assert events[1].data["event_type"] == 5
|
||||||
|
assert events[1].data["data_type"] == 2
|
||||||
|
assert events[1].data["event_data"] == "555"
|
||||||
|
assert events[1].data["command_class"] == CommandClass.ENTRY_CONTROL
|
||||||
|
assert events[1].data["command_class_name"] == "Entry Control"
|
||||||
|
@ -296,6 +296,52 @@ async def test_set_config_parameter(hass, client, multisensor_6, integration):
|
|||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Test that when a device is awake, we call async_send_command instead of
|
||||||
|
# async_send_command_no_wait
|
||||||
|
multisensor_6.handle_wake_up(None)
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SET_CONFIG_PARAMETER,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR,
|
||||||
|
ATTR_CONFIG_PARAMETER: 102,
|
||||||
|
ATTR_CONFIG_PARAMETER_BITMASK: 1,
|
||||||
|
ATTR_CONFIG_VALUE: 1,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(client.async_send_command.call_args_list) == 1
|
||||||
|
args = client.async_send_command.call_args[0][0]
|
||||||
|
assert args["command"] == "node.set_value"
|
||||||
|
assert args["nodeId"] == 52
|
||||||
|
assert args["valueId"] == {
|
||||||
|
"commandClassName": "Configuration",
|
||||||
|
"commandClass": 112,
|
||||||
|
"endpoint": 0,
|
||||||
|
"property": 102,
|
||||||
|
"propertyName": "Group 2: Send battery reports",
|
||||||
|
"propertyKey": 1,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": True,
|
||||||
|
"writeable": True,
|
||||||
|
"valueSize": 4,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"default": 1,
|
||||||
|
"format": 0,
|
||||||
|
"allowManualEntry": True,
|
||||||
|
"label": "Group 2: Send battery reports",
|
||||||
|
"description": "Include battery information in periodic reports to Group 2",
|
||||||
|
"isFromConfig": True,
|
||||||
|
},
|
||||||
|
"value": 0,
|
||||||
|
}
|
||||||
|
assert args["value"] == 1
|
||||||
|
|
||||||
|
client.async_send_command.reset_mock()
|
||||||
|
|
||||||
|
|
||||||
async def test_poll_value(
|
async def test_poll_value(
|
||||||
hass, client, climate_radio_thermostat_ct100_plus_different_endpoints, integration
|
hass, client, climate_radio_thermostat_ct100_plus_different_endpoints, integration
|
||||||
|
Loading…
x
Reference in New Issue
Block a user