mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Add support for zwave_js event entities (#102285)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
a2c60d9015
commit
41b59b6990
@ -162,6 +162,8 @@ class ZWaveValueDiscoverySchema(DataclassMustHaveAtLeastOne):
|
|||||||
any_available_states: set[tuple[int, str]] | None = None
|
any_available_states: set[tuple[int, str]] | None = None
|
||||||
# [optional] the value's value must match this value
|
# [optional] the value's value must match this value
|
||||||
value: Any | None = None
|
value: Any | None = None
|
||||||
|
# [optional] the value's metadata_stateful must match this value
|
||||||
|
stateful: bool | None = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -1045,6 +1047,15 @@ DISCOVERY_SCHEMAS = [
|
|||||||
any_available_states={(0, "idle")},
|
any_available_states={(0, "idle")},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
# event
|
||||||
|
# stateful = False
|
||||||
|
ZWaveDiscoverySchema(
|
||||||
|
platform=Platform.EVENT,
|
||||||
|
hint="stateless",
|
||||||
|
primary_value=ZWaveValueDiscoverySchema(
|
||||||
|
stateful=False,
|
||||||
|
),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -1294,6 +1305,9 @@ def check_value(value: ZwaveValue, schema: ZWaveValueDiscoverySchema) -> bool:
|
|||||||
# check value
|
# check value
|
||||||
if schema.value is not None and value.value not in schema.value:
|
if schema.value is not None and value.value not in schema.value:
|
||||||
return False
|
return False
|
||||||
|
# check metadata_stateful
|
||||||
|
if schema.stateful is not None and value.metadata.stateful != schema.stateful:
|
||||||
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
98
homeassistant/components/zwave_js/event.py
Normal file
98
homeassistant/components/zwave_js/event.py
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
"""Support for Z-Wave controls using the event platform."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from zwave_js_server.client import Client as ZwaveClient
|
||||||
|
from zwave_js_server.model.driver import Driver
|
||||||
|
from zwave_js_server.model.value import Value, ValueNotification
|
||||||
|
|
||||||
|
from homeassistant.components.event import DOMAIN as EVENT_DOMAIN, EventEntity
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from .const import ATTR_VALUE, DATA_CLIENT, DOMAIN
|
||||||
|
from .discovery import ZwaveDiscoveryInfo
|
||||||
|
from .entity import ZWaveBaseEntity
|
||||||
|
|
||||||
|
PARALLEL_UPDATES = 0
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up Z-Wave Event entity from Config Entry."""
|
||||||
|
client: ZwaveClient = hass.data[DOMAIN][config_entry.entry_id][DATA_CLIENT]
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_add_event(info: ZwaveDiscoveryInfo) -> None:
|
||||||
|
"""Add Z-Wave event entity."""
|
||||||
|
driver = client.driver
|
||||||
|
assert driver is not None # Driver is ready before platforms are loaded.
|
||||||
|
entities: list[ZWaveBaseEntity] = [ZwaveEventEntity(config_entry, driver, info)]
|
||||||
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
config_entry.async_on_unload(
|
||||||
|
async_dispatcher_connect(
|
||||||
|
hass,
|
||||||
|
f"{DOMAIN}_{config_entry.entry_id}_add_{EVENT_DOMAIN}",
|
||||||
|
async_add_event,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _cc_and_label(value: Value) -> str:
|
||||||
|
"""Return a string with the command class and label."""
|
||||||
|
label = value.metadata.label
|
||||||
|
if label:
|
||||||
|
label = label.lower()
|
||||||
|
return f"{value.command_class_name.capitalize()} {label}".strip()
|
||||||
|
|
||||||
|
|
||||||
|
class ZwaveEventEntity(ZWaveBaseEntity, EventEntity):
|
||||||
|
"""Representation of a Z-Wave event entity."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, config_entry: ConfigEntry, driver: Driver, info: ZwaveDiscoveryInfo
|
||||||
|
) -> None:
|
||||||
|
"""Initialize a ZwaveEventEntity entity."""
|
||||||
|
super().__init__(config_entry, driver, info)
|
||||||
|
value = self.value = info.primary_value
|
||||||
|
self.states: dict[int, str] = {}
|
||||||
|
|
||||||
|
if states := value.metadata.states:
|
||||||
|
self._attr_event_types = sorted(states.values())
|
||||||
|
self.states = {int(k): v for k, v in states.items()}
|
||||||
|
else:
|
||||||
|
self._attr_event_types = [_cc_and_label(value)]
|
||||||
|
# Entity class attributes
|
||||||
|
self._attr_name = self.generate_name(include_value_name=True)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _async_handle_event(self, value_notification: ValueNotification) -> None:
|
||||||
|
"""Handle a value notification event."""
|
||||||
|
# If the notification doesn't match the value we are tracking, we can return
|
||||||
|
value = self.value
|
||||||
|
if (
|
||||||
|
value_notification.command_class != value.command_class
|
||||||
|
or value_notification.endpoint != value.endpoint
|
||||||
|
or value_notification.property_ != value.property_
|
||||||
|
or value_notification.property_key != value.property_key
|
||||||
|
or (notification_value := value_notification.value) is None
|
||||||
|
):
|
||||||
|
return
|
||||||
|
event_name = self.states.get(notification_value, _cc_and_label(value))
|
||||||
|
self._trigger_event(event_name, {ATTR_VALUE: notification_value})
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
async def async_added_to_hass(self) -> None:
|
||||||
|
"""Call when entity is added."""
|
||||||
|
await super().async_added_to_hass()
|
||||||
|
self.async_on_remove(
|
||||||
|
self.info.node.on(
|
||||||
|
"value notification",
|
||||||
|
lambda event: self._async_handle_event(event["value_notification"]),
|
||||||
|
)
|
||||||
|
)
|
@ -668,6 +668,12 @@ def climate_intermatic_pe653_state_fixture():
|
|||||||
return json.loads(load_fixture("zwave_js/climate_intermatic_pe653_state.json"))
|
return json.loads(load_fixture("zwave_js/climate_intermatic_pe653_state.json"))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="central_scene_node_state", scope="session")
|
||||||
|
def central_scene_node_state_fixture():
|
||||||
|
"""Load node with Central Scene CC node state fixture data."""
|
||||||
|
return json.loads(load_fixture("zwave_js/central_scene_node_state.json"))
|
||||||
|
|
||||||
|
|
||||||
# model fixtures
|
# model fixtures
|
||||||
|
|
||||||
|
|
||||||
@ -1304,3 +1310,11 @@ def climate_intermatic_pe653_fixture(client, climate_intermatic_pe653_state):
|
|||||||
node = Node(client, copy.deepcopy(climate_intermatic_pe653_state))
|
node = Node(client, copy.deepcopy(climate_intermatic_pe653_state))
|
||||||
client.driver.controller.nodes[node.node_id] = node
|
client.driver.controller.nodes[node.node_id] = node
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="central_scene_node")
|
||||||
|
def central_scene_node_fixture(client, central_scene_node_state):
|
||||||
|
"""Mock a node with the Central Scene CC."""
|
||||||
|
node = Node(client, copy.deepcopy(central_scene_node_state))
|
||||||
|
client.driver.controller.nodes[node.node_id] = node
|
||||||
|
return node
|
||||||
|
431
tests/components/zwave_js/fixtures/central_scene_node_state.json
Normal file
431
tests/components/zwave_js/fixtures/central_scene_node_state.json
Normal file
@ -0,0 +1,431 @@
|
|||||||
|
{
|
||||||
|
"nodeId": 51,
|
||||||
|
"index": 0,
|
||||||
|
"status": 4,
|
||||||
|
"ready": true,
|
||||||
|
"isListening": true,
|
||||||
|
"isRouting": true,
|
||||||
|
"isSecure": true,
|
||||||
|
"firmwareVersion": "1.3.0",
|
||||||
|
"interviewAttempts": 1,
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"nodeId": 51,
|
||||||
|
"index": 0,
|
||||||
|
"deviceClass": {
|
||||||
|
"basic": {
|
||||||
|
"key": 4,
|
||||||
|
"label": "Routing Slave"
|
||||||
|
},
|
||||||
|
"generic": {
|
||||||
|
"key": 24,
|
||||||
|
"label": "Wall Controller"
|
||||||
|
},
|
||||||
|
"specific": {
|
||||||
|
"key": 0,
|
||||||
|
"label": "Unused"
|
||||||
|
},
|
||||||
|
"mandatorySupportedCCs": [],
|
||||||
|
"mandatoryControlledCCs": []
|
||||||
|
},
|
||||||
|
"commandClasses": [
|
||||||
|
{
|
||||||
|
"id": 159,
|
||||||
|
"name": "Security 2",
|
||||||
|
"version": 1,
|
||||||
|
"isSecure": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 152,
|
||||||
|
"name": "Security",
|
||||||
|
"version": 1,
|
||||||
|
"isSecure": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 108,
|
||||||
|
"name": "Supervision",
|
||||||
|
"version": 1,
|
||||||
|
"isSecure": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 85,
|
||||||
|
"name": "Transport Service",
|
||||||
|
"version": 2,
|
||||||
|
"isSecure": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 134,
|
||||||
|
"name": "Version",
|
||||||
|
"version": 3,
|
||||||
|
"isSecure": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 133,
|
||||||
|
"name": "Association",
|
||||||
|
"version": 2,
|
||||||
|
"isSecure": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 89,
|
||||||
|
"name": "Association Group Information",
|
||||||
|
"version": 3,
|
||||||
|
"isSecure": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 91,
|
||||||
|
"name": "Central Scene",
|
||||||
|
"version": 3,
|
||||||
|
"isSecure": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 91,
|
||||||
|
"commandClassName": "Central Scene",
|
||||||
|
"property": "scene",
|
||||||
|
"propertyKey": "001",
|
||||||
|
"propertyName": "scene",
|
||||||
|
"propertyKeyName": "001",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Scene 001",
|
||||||
|
"min": 0,
|
||||||
|
"max": 255,
|
||||||
|
"states": {
|
||||||
|
"0": "KeyPressed"
|
||||||
|
},
|
||||||
|
"stateful": false,
|
||||||
|
"secret": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 91,
|
||||||
|
"commandClassName": "Central Scene",
|
||||||
|
"property": "scene",
|
||||||
|
"propertyKey": "002",
|
||||||
|
"propertyName": "scene",
|
||||||
|
"propertyKeyName": "002",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Scene 002",
|
||||||
|
"min": 0,
|
||||||
|
"max": 255,
|
||||||
|
"states": {
|
||||||
|
"0": "KeyPressed",
|
||||||
|
"1": "KeyReleased",
|
||||||
|
"2": "KeyHeldDown",
|
||||||
|
"3": "KeyPressed2x",
|
||||||
|
"4": "KeyPressed3x",
|
||||||
|
"5": "KeyPressed4x",
|
||||||
|
"6": "KeyPressed5x"
|
||||||
|
},
|
||||||
|
"stateful": false,
|
||||||
|
"secret": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 91,
|
||||||
|
"commandClassName": "Central Scene",
|
||||||
|
"property": "slowRefresh",
|
||||||
|
"propertyName": "slowRefresh",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "boolean",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": true,
|
||||||
|
"description": "When this is true, KeyHeldDown notifications are sent every 55s. When this is false, the notifications are sent every 200ms.",
|
||||||
|
"label": "Send held down notifications at a slow rate",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "libraryType",
|
||||||
|
"propertyName": "libraryType",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Library type",
|
||||||
|
"states": {
|
||||||
|
"0": "Unknown",
|
||||||
|
"1": "Static Controller",
|
||||||
|
"2": "Controller",
|
||||||
|
"3": "Enhanced Slave",
|
||||||
|
"4": "Slave",
|
||||||
|
"5": "Installer",
|
||||||
|
"6": "Routing Slave",
|
||||||
|
"7": "Bridge Controller",
|
||||||
|
"8": "Device under Test",
|
||||||
|
"9": "N/A",
|
||||||
|
"10": "AV Remote",
|
||||||
|
"11": "AV Device"
|
||||||
|
},
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "protocolVersion",
|
||||||
|
"propertyName": "protocolVersion",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "string",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Z-Wave protocol version",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": "6.81"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "firmwareVersions",
|
||||||
|
"propertyName": "firmwareVersions",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "string[]",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Z-Wave chip firmware versions",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": ["1.3"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "hardwareVersion",
|
||||||
|
"propertyName": "hardwareVersion",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Z-Wave chip hardware version",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "sdkVersion",
|
||||||
|
"propertyName": "sdkVersion",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "string",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "SDK version",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": "7.0.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "applicationFrameworkAPIVersion",
|
||||||
|
"propertyName": "applicationFrameworkAPIVersion",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "string",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Z-Wave application framework API version",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": "unused"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "applicationFrameworkBuildNumber",
|
||||||
|
"propertyName": "applicationFrameworkBuildNumber",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "string",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Z-Wave application framework API build number",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "hostInterfaceVersion",
|
||||||
|
"propertyName": "hostInterfaceVersion",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "string",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Serial API version",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": "unused"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "hostInterfaceBuildNumber",
|
||||||
|
"propertyName": "hostInterfaceBuildNumber",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "string",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Serial API build number",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "zWaveProtocolVersion",
|
||||||
|
"propertyName": "zWaveProtocolVersion",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "string",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Z-Wave protocol version",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": "6.81.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "zWaveProtocolBuildNumber",
|
||||||
|
"propertyName": "zWaveProtocolBuildNumber",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "string",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Z-Wave protocol build number",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": 255
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "applicationVersion",
|
||||||
|
"propertyName": "applicationVersion",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "string",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Application version",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": "1.3.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 134,
|
||||||
|
"commandClassName": "Version",
|
||||||
|
"property": "applicationBuildNumber",
|
||||||
|
"propertyName": "applicationBuildNumber",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "string",
|
||||||
|
"readable": true,
|
||||||
|
"writeable": false,
|
||||||
|
"label": "Application build number",
|
||||||
|
"stateful": true,
|
||||||
|
"secret": false
|
||||||
|
},
|
||||||
|
"value": 255
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isFrequentListening": false,
|
||||||
|
"maxDataRate": 100000,
|
||||||
|
"supportedDataRates": [40000, 100000],
|
||||||
|
"protocolVersion": 3,
|
||||||
|
"supportsBeaming": true,
|
||||||
|
"supportsSecurity": false,
|
||||||
|
"nodeType": 1,
|
||||||
|
"deviceClass": {
|
||||||
|
"basic": {
|
||||||
|
"key": 4,
|
||||||
|
"label": "Routing Slave"
|
||||||
|
},
|
||||||
|
"generic": {
|
||||||
|
"key": 24,
|
||||||
|
"label": "Wall Controller"
|
||||||
|
},
|
||||||
|
"specific": {
|
||||||
|
"key": 0,
|
||||||
|
"label": "Unused"
|
||||||
|
},
|
||||||
|
"mandatorySupportedCCs": [],
|
||||||
|
"mandatoryControlledCCs": []
|
||||||
|
},
|
||||||
|
"interviewStage": "Complete",
|
||||||
|
"statistics": {
|
||||||
|
"commandsTX": 42,
|
||||||
|
"commandsRX": 46,
|
||||||
|
"commandsDroppedRX": 0,
|
||||||
|
"commandsDroppedTX": 0,
|
||||||
|
"timeoutResponse": 0,
|
||||||
|
"rtt": 55.4,
|
||||||
|
"rssi": -72,
|
||||||
|
"lwr": {
|
||||||
|
"protocolDataRate": 3,
|
||||||
|
"repeaters": [],
|
||||||
|
"rssi": -72,
|
||||||
|
"repeaterRSSI": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"highestSecurityClass": 0,
|
||||||
|
"isControllerNode": false,
|
||||||
|
"keepAwake": false
|
||||||
|
}
|
175
tests/components/zwave_js/test_event.py
Normal file
175
tests/components/zwave_js/test_event.py
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
"""Test the Z-Wave JS event platform."""
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from freezegun import freeze_time
|
||||||
|
from zwave_js_server.event import Event
|
||||||
|
|
||||||
|
from homeassistant.components.event import ATTR_EVENT_TYPE
|
||||||
|
from homeassistant.components.zwave_js.const import ATTR_VALUE
|
||||||
|
from homeassistant.const import STATE_UNKNOWN
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
|
BASIC_EVENT_VALUE_ENTITY = "event.honeywell_in_wall_smart_fan_control_event_value"
|
||||||
|
CENTRAL_SCENE_ENTITY = "event.node_51_scene_002"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_basic(
|
||||||
|
hass: HomeAssistant, client, fan_honeywell_39358, integration
|
||||||
|
) -> None:
|
||||||
|
"""Test the Basic CC event entity."""
|
||||||
|
dt_util.now()
|
||||||
|
fut = dt_util.now() + timedelta(minutes=1)
|
||||||
|
node = fan_honeywell_39358
|
||||||
|
state = hass.states.get(BASIC_EVENT_VALUE_ENTITY)
|
||||||
|
|
||||||
|
assert state
|
||||||
|
assert state.state == STATE_UNKNOWN
|
||||||
|
|
||||||
|
event = Event(
|
||||||
|
type="value notification",
|
||||||
|
data={
|
||||||
|
"source": "node",
|
||||||
|
"event": "value notification",
|
||||||
|
"nodeId": node.node_id,
|
||||||
|
"args": {
|
||||||
|
"commandClassName": "Basic",
|
||||||
|
"commandClass": 32,
|
||||||
|
"endpoint": 0,
|
||||||
|
"property": "event",
|
||||||
|
"propertyName": "event",
|
||||||
|
"value": 255,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": True,
|
||||||
|
"writeable": False,
|
||||||
|
"min": 0,
|
||||||
|
"max": 255,
|
||||||
|
"label": "Event value",
|
||||||
|
},
|
||||||
|
"ccVersion": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
with freeze_time(fut):
|
||||||
|
node.receive_event(event)
|
||||||
|
|
||||||
|
state = hass.states.get(BASIC_EVENT_VALUE_ENTITY)
|
||||||
|
|
||||||
|
assert state
|
||||||
|
assert state.state == dt_util.as_utc(fut).isoformat(timespec="milliseconds")
|
||||||
|
attributes = state.attributes
|
||||||
|
assert attributes[ATTR_EVENT_TYPE] == "Basic event value"
|
||||||
|
assert attributes[ATTR_VALUE] == 255
|
||||||
|
|
||||||
|
|
||||||
|
async def test_central_scene(
|
||||||
|
hass: HomeAssistant, client, central_scene_node, integration
|
||||||
|
) -> None:
|
||||||
|
"""Test the Central Scene CC event entity."""
|
||||||
|
dt_util.now()
|
||||||
|
fut = dt_util.now() + timedelta(minutes=1)
|
||||||
|
node = central_scene_node
|
||||||
|
state = hass.states.get(CENTRAL_SCENE_ENTITY)
|
||||||
|
|
||||||
|
assert state
|
||||||
|
assert state.state == STATE_UNKNOWN
|
||||||
|
|
||||||
|
event = Event(
|
||||||
|
type="value notification",
|
||||||
|
data={
|
||||||
|
"source": "node",
|
||||||
|
"event": "value notification",
|
||||||
|
"nodeId": node.node_id,
|
||||||
|
"args": {
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 91,
|
||||||
|
"commandClassName": "Central Scene",
|
||||||
|
"property": "scene",
|
||||||
|
"propertyKey": "002",
|
||||||
|
"propertyName": "scene",
|
||||||
|
"propertyKeyName": "002",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": True,
|
||||||
|
"writeable": False,
|
||||||
|
"label": "Scene 002",
|
||||||
|
"min": 0,
|
||||||
|
"max": 255,
|
||||||
|
"states": {
|
||||||
|
"0": "KeyPressed",
|
||||||
|
"1": "KeyReleased",
|
||||||
|
"2": "KeyHeldDown",
|
||||||
|
"3": "KeyPressed2x",
|
||||||
|
"4": "KeyPressed3x",
|
||||||
|
"5": "KeyPressed4x",
|
||||||
|
"6": "KeyPressed5x",
|
||||||
|
},
|
||||||
|
"stateful": False,
|
||||||
|
"secret": False,
|
||||||
|
},
|
||||||
|
"value": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
with freeze_time(fut):
|
||||||
|
node.receive_event(event)
|
||||||
|
|
||||||
|
state = hass.states.get(CENTRAL_SCENE_ENTITY)
|
||||||
|
|
||||||
|
assert state
|
||||||
|
assert state.state == dt_util.as_utc(fut).isoformat(timespec="milliseconds")
|
||||||
|
attributes = state.attributes
|
||||||
|
assert attributes[ATTR_EVENT_TYPE] == "KeyReleased"
|
||||||
|
assert attributes[ATTR_VALUE] == 1
|
||||||
|
|
||||||
|
# Try invalid value
|
||||||
|
event = Event(
|
||||||
|
type="value notification",
|
||||||
|
data={
|
||||||
|
"source": "node",
|
||||||
|
"event": "value notification",
|
||||||
|
"nodeId": node.node_id,
|
||||||
|
"args": {
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 91,
|
||||||
|
"commandClassName": "Central Scene",
|
||||||
|
"property": "scene",
|
||||||
|
"propertyKey": "002",
|
||||||
|
"propertyName": "scene",
|
||||||
|
"propertyKeyName": "002",
|
||||||
|
"ccVersion": 3,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": True,
|
||||||
|
"writeable": False,
|
||||||
|
"label": "Scene 002",
|
||||||
|
"min": 0,
|
||||||
|
"max": 255,
|
||||||
|
"states": {
|
||||||
|
"0": "KeyPressed",
|
||||||
|
"1": "KeyReleased",
|
||||||
|
"2": "KeyHeldDown",
|
||||||
|
"3": "KeyPressed2x",
|
||||||
|
"4": "KeyPressed3x",
|
||||||
|
"5": "KeyPressed4x",
|
||||||
|
"6": "KeyPressed5x",
|
||||||
|
},
|
||||||
|
"stateful": False,
|
||||||
|
"secret": False,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
with freeze_time(fut + timedelta(minutes=10)):
|
||||||
|
node.receive_event(event)
|
||||||
|
|
||||||
|
# Nothing should have changed even though the time has changed
|
||||||
|
state = hass.states.get(CENTRAL_SCENE_ENTITY)
|
||||||
|
|
||||||
|
assert state
|
||||||
|
assert state.state == dt_util.as_utc(fut).isoformat(timespec="milliseconds")
|
||||||
|
attributes = state.attributes
|
||||||
|
assert attributes[ATTR_EVENT_TYPE] == "KeyReleased"
|
||||||
|
assert attributes[ATTR_VALUE] == 1
|
@ -1,4 +1,4 @@
|
|||||||
"""Test Z-Wave JS (value notification) events."""
|
"""Test Z-Wave JS events."""
|
||||||
from unittest.mock import AsyncMock
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
Loading…
x
Reference in New Issue
Block a user