mirror of
https://github.com/home-assistant/core.git
synced 2026-09-26 01:11:51 -04:00
Describe Z-Wave JS triggers for the automation editor (#181129)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
3f4cebe868
commit
aa6fc90ba4
@@ -120,5 +120,13 @@
|
||||
"set_value": {
|
||||
"service": "mdi:form-textbox"
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
"event": {
|
||||
"trigger": "mdi:z-wave"
|
||||
},
|
||||
"value_updated": {
|
||||
"trigger": "mdi:update"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,6 +426,137 @@
|
||||
}
|
||||
},
|
||||
"selector": {
|
||||
"command_class": {
|
||||
"options": {
|
||||
"0": "No Operation (0)",
|
||||
"32": "Basic (32)",
|
||||
"33": "Controller Replication (33)",
|
||||
"34": "Application Status (34)",
|
||||
"35": "Z/IP (35)",
|
||||
"37": "Binary Switch (37)",
|
||||
"38": "Multilevel Switch (38)",
|
||||
"39": "All Switch (39)",
|
||||
"40": "Binary Toggle Switch (40)",
|
||||
"41": "Multilevel Toggle Switch (41)",
|
||||
"43": "Scene Activation (43)",
|
||||
"44": "Scene Actuator Configuration (44)",
|
||||
"45": "Scene Controller Configuration (45)",
|
||||
"48": "Binary Sensor (48)",
|
||||
"49": "Multilevel Sensor (49)",
|
||||
"50": "Meter (50)",
|
||||
"51": "Color Switch (51)",
|
||||
"52": "Network Management Inclusion (52)",
|
||||
"53": "Pulse Meter (53)",
|
||||
"54": "Basic Tariff Information (54)",
|
||||
"55": "HRV Status (55)",
|
||||
"57": "HRV Control (57)",
|
||||
"58": "Demand Control Plan Configuration (58)",
|
||||
"59": "Demand Control Plan Monitor (59)",
|
||||
"60": "Meter Table Configuration (60)",
|
||||
"61": "Meter Table Monitor (61)",
|
||||
"62": "Meter Table Push Configuration (62)",
|
||||
"63": "Prepayment (63)",
|
||||
"64": "Thermostat Mode (64)",
|
||||
"65": "Prepayment Encapsulation (65)",
|
||||
"66": "Thermostat Operating State (66)",
|
||||
"67": "Thermostat Setpoint (67)",
|
||||
"68": "Thermostat Fan Mode (68)",
|
||||
"69": "Thermostat Fan State (69)",
|
||||
"70": "Climate Control Schedule (70)",
|
||||
"71": "Thermostat Setback (71)",
|
||||
"72": "Rate Table Configuration (72)",
|
||||
"73": "Rate Table Monitor (73)",
|
||||
"74": "Tariff Table Configuration (74)",
|
||||
"75": "Tariff Table Monitor (75)",
|
||||
"76": "Door Lock Logging (76)",
|
||||
"77": "Network Management Basic Node (77)",
|
||||
"78": "Schedule Entry Lock (78)",
|
||||
"79": "Z/IP 6LoWPAN (79)",
|
||||
"80": "Basic Window Covering (80)",
|
||||
"81": "Move To Position Window Covering (81)",
|
||||
"82": "Network Management Proxy (82)",
|
||||
"83": "Schedule (83)",
|
||||
"84": "Network Management Primary (84)",
|
||||
"85": "Transport Service (85)",
|
||||
"86": "CRC-16 Encapsulation (86)",
|
||||
"87": "Application Capability (87)",
|
||||
"88": "Z/IP ND (88)",
|
||||
"89": "Association Group Information (89)",
|
||||
"90": "Device Reset Locally (90)",
|
||||
"91": "Central Scene (91)",
|
||||
"92": "IP Association (92)",
|
||||
"93": "Anti-Theft (93)",
|
||||
"94": "Z-Wave Plus Info (94)",
|
||||
"95": "Z/IP Gateway (95)",
|
||||
"96": "Multi Channel (96)",
|
||||
"97": "Z/IP Portal (97)",
|
||||
"98": "Door Lock (98)",
|
||||
"99": "User Code (99)",
|
||||
"100": "Humidity Control Setpoint (100)",
|
||||
"102": "Barrier Operator (102)",
|
||||
"103": "Network Management Installation and Maintenance (103)",
|
||||
"104": "Z/IP Naming and Location (104)",
|
||||
"105": "Mailbox (105)",
|
||||
"106": "Window Covering (106)",
|
||||
"107": "Irrigation (107)",
|
||||
"108": "Supervision (108)",
|
||||
"109": "Humidity Control Mode (109)",
|
||||
"110": "Humidity Control Operating State (110)",
|
||||
"111": "Entry Control (111)",
|
||||
"112": "Configuration (112)",
|
||||
"113": "Notification (113)",
|
||||
"114": "Manufacturer Specific (114)",
|
||||
"115": "Powerlevel (115)",
|
||||
"116": "Inclusion Controller (116)",
|
||||
"117": "Protection (117)",
|
||||
"118": "Lock (118)",
|
||||
"119": "Node Naming and Location (119)",
|
||||
"120": "Node Provisioning (120)",
|
||||
"121": "Sound Switch (121)",
|
||||
"122": "Firmware Update Meta Data (122)",
|
||||
"123": "Grouping Name (123)",
|
||||
"124": "Remote Association Activation (124)",
|
||||
"125": "Remote Association Configuration (125)",
|
||||
"126": "Anti-Theft Unlock (126)",
|
||||
"128": "Battery (128)",
|
||||
"129": "Clock (129)",
|
||||
"130": "Hail (130)",
|
||||
"132": "Wake Up (132)",
|
||||
"133": "Association (133)",
|
||||
"134": "Version (134)",
|
||||
"135": "Indicator (135)",
|
||||
"136": "Proprietary (136)",
|
||||
"137": "Language (137)",
|
||||
"138": "Time (138)",
|
||||
"139": "Time Parameters (139)",
|
||||
"140": "Geographic Location (140)",
|
||||
"142": "Multi Channel Association (142)",
|
||||
"143": "Multi Command (143)",
|
||||
"144": "Energy Production (144)",
|
||||
"145": "Manufacturer Proprietary (145)",
|
||||
"146": "Screen Meta Data (146)",
|
||||
"147": "Screen Attributes (147)",
|
||||
"148": "Simple AV Control (148)",
|
||||
"152": "Security (152)",
|
||||
"154": "IP Configuration (154)",
|
||||
"155": "Association Command Configuration (155)",
|
||||
"156": "Alarm Sensor (156)",
|
||||
"157": "Alarm Silence (157)",
|
||||
"158": "Sensor Configuration (158)",
|
||||
"159": "Security 2 (159)",
|
||||
"160": "IR Repeater (160)",
|
||||
"161": "Authentication (161)",
|
||||
"162": "Authentication Media Write (162)",
|
||||
"163": "Generic Schedule (163)"
|
||||
}
|
||||
},
|
||||
"event_source": {
|
||||
"options": {
|
||||
"controller": "Controller",
|
||||
"driver": "Driver",
|
||||
"node": "Node"
|
||||
}
|
||||
},
|
||||
"network_type": {
|
||||
"options": {
|
||||
"existing": "It already exists",
|
||||
@@ -890,5 +1021,79 @@
|
||||
},
|
||||
"name": "Set a value"
|
||||
}
|
||||
},
|
||||
"triggers": {
|
||||
"event": {
|
||||
"description": "Triggers when a Z-Wave JS controller, driver, or node emits an event.",
|
||||
"fields": {
|
||||
"config_entry_id": {
|
||||
"description": "The Z-Wave JS config entry to listen to. Required for controller and driver events.",
|
||||
"name": "Config entry"
|
||||
},
|
||||
"device_id": {
|
||||
"description": "Devices whose node events to listen to. Node events need at least one device or entity, and controller or driver events must not have any.",
|
||||
"name": "Devices"
|
||||
},
|
||||
"entity_id": {
|
||||
"description": "Entities whose node events to listen to. Node events need at least one device or entity, and controller or driver events must not have any.",
|
||||
"name": "Entities"
|
||||
},
|
||||
"event": {
|
||||
"description": "Name of the Z-Wave JS event, for example `value notification`.",
|
||||
"name": "Event"
|
||||
},
|
||||
"event_data": {
|
||||
"description": "Key-value pairs the event data must contain for the trigger to fire.",
|
||||
"name": "Event data"
|
||||
},
|
||||
"event_source": {
|
||||
"description": "Whether the event is emitted by the controller, the driver, or a node.",
|
||||
"name": "Event source"
|
||||
},
|
||||
"partial_dict_match": {
|
||||
"description": "Match nested dictionaries in the event data on the given keys only, instead of requiring an exact match.",
|
||||
"name": "Partial dictionary match"
|
||||
}
|
||||
},
|
||||
"name": "Z-Wave JS event received"
|
||||
},
|
||||
"value_updated": {
|
||||
"description": "Triggers when a Z-Wave value on one or more nodes changes.",
|
||||
"fields": {
|
||||
"command_class": {
|
||||
"description": "Command class of the value.",
|
||||
"name": "Command class"
|
||||
},
|
||||
"device_id": {
|
||||
"description": "Devices whose values to watch. At least one device or entity is required.",
|
||||
"name": "Devices"
|
||||
},
|
||||
"endpoint": {
|
||||
"description": "Endpoint of the value.",
|
||||
"name": "Endpoint"
|
||||
},
|
||||
"entity_id": {
|
||||
"description": "Entities whose values to watch. At least one device or entity is required.",
|
||||
"name": "Entities"
|
||||
},
|
||||
"from": {
|
||||
"description": "Only trigger when the value changes from this value, or from any value in this list.",
|
||||
"name": "From"
|
||||
},
|
||||
"property": {
|
||||
"description": "Property of the value.",
|
||||
"name": "Property"
|
||||
},
|
||||
"property_key": {
|
||||
"description": "Property key of the value.",
|
||||
"name": "Property key"
|
||||
},
|
||||
"to": {
|
||||
"description": "Only trigger when the value changes to this value, or to any value in this list.",
|
||||
"name": "To"
|
||||
}
|
||||
},
|
||||
"name": "Z-Wave JS value updated"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
# Describes the format for available Z-Wave JS triggers
|
||||
|
||||
.device_id: &device_id
|
||||
required: false
|
||||
example: 8f4219cfa57e23f6f669c4616c2205e2
|
||||
selector:
|
||||
device:
|
||||
filter:
|
||||
- integration: zwave_js
|
||||
multiple: true
|
||||
|
||||
.entity_id: &entity_id
|
||||
required: false
|
||||
example: sensor.living_room_temperature
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- integration: zwave_js
|
||||
multiple: true
|
||||
|
||||
event:
|
||||
fields:
|
||||
event_source:
|
||||
required: true
|
||||
selector:
|
||||
select:
|
||||
translation_key: event_source
|
||||
options:
|
||||
- controller
|
||||
- driver
|
||||
- node
|
||||
config_entry_id:
|
||||
required: false
|
||||
selector:
|
||||
config_entry:
|
||||
integration: zwave_js
|
||||
device_id: *device_id
|
||||
entity_id: *entity_id
|
||||
event:
|
||||
required: true
|
||||
example: value notification
|
||||
selector:
|
||||
text:
|
||||
event_data:
|
||||
required: false
|
||||
selector:
|
||||
object:
|
||||
partial_dict_match:
|
||||
required: false
|
||||
default: false
|
||||
selector:
|
||||
boolean:
|
||||
|
||||
value_updated:
|
||||
fields:
|
||||
device_id: *device_id
|
||||
entity_id: *entity_id
|
||||
command_class:
|
||||
required: true
|
||||
selector:
|
||||
select:
|
||||
translation_key: command_class
|
||||
sort: true
|
||||
options:
|
||||
- "0"
|
||||
- "32"
|
||||
- "33"
|
||||
- "34"
|
||||
- "35"
|
||||
- "37"
|
||||
- "38"
|
||||
- "39"
|
||||
- "40"
|
||||
- "41"
|
||||
- "43"
|
||||
- "44"
|
||||
- "45"
|
||||
- "48"
|
||||
- "49"
|
||||
- "50"
|
||||
- "51"
|
||||
- "52"
|
||||
- "53"
|
||||
- "54"
|
||||
- "55"
|
||||
- "57"
|
||||
- "58"
|
||||
- "59"
|
||||
- "60"
|
||||
- "61"
|
||||
- "62"
|
||||
- "63"
|
||||
- "64"
|
||||
- "65"
|
||||
- "66"
|
||||
- "67"
|
||||
- "68"
|
||||
- "69"
|
||||
- "70"
|
||||
- "71"
|
||||
- "72"
|
||||
- "73"
|
||||
- "74"
|
||||
- "75"
|
||||
- "76"
|
||||
- "77"
|
||||
- "78"
|
||||
- "79"
|
||||
- "80"
|
||||
- "81"
|
||||
- "82"
|
||||
- "83"
|
||||
- "84"
|
||||
- "85"
|
||||
- "86"
|
||||
- "87"
|
||||
- "88"
|
||||
- "89"
|
||||
- "90"
|
||||
- "91"
|
||||
- "92"
|
||||
- "93"
|
||||
- "94"
|
||||
- "95"
|
||||
- "96"
|
||||
- "97"
|
||||
- "98"
|
||||
- "99"
|
||||
- "100"
|
||||
- "102"
|
||||
- "103"
|
||||
- "104"
|
||||
- "105"
|
||||
- "106"
|
||||
- "107"
|
||||
- "108"
|
||||
- "109"
|
||||
- "110"
|
||||
- "111"
|
||||
- "112"
|
||||
- "113"
|
||||
- "114"
|
||||
- "115"
|
||||
- "116"
|
||||
- "117"
|
||||
- "118"
|
||||
- "119"
|
||||
- "120"
|
||||
- "121"
|
||||
- "122"
|
||||
- "123"
|
||||
- "124"
|
||||
- "125"
|
||||
- "126"
|
||||
- "128"
|
||||
- "129"
|
||||
- "130"
|
||||
- "132"
|
||||
- "133"
|
||||
- "134"
|
||||
- "135"
|
||||
- "136"
|
||||
- "137"
|
||||
- "138"
|
||||
- "139"
|
||||
- "140"
|
||||
- "142"
|
||||
- "143"
|
||||
- "144"
|
||||
- "145"
|
||||
- "146"
|
||||
- "147"
|
||||
- "148"
|
||||
- "152"
|
||||
- "154"
|
||||
- "155"
|
||||
- "156"
|
||||
- "157"
|
||||
- "158"
|
||||
- "159"
|
||||
- "160"
|
||||
- "161"
|
||||
- "162"
|
||||
- "163"
|
||||
property:
|
||||
required: true
|
||||
example: currentValue
|
||||
selector:
|
||||
text:
|
||||
endpoint:
|
||||
required: false
|
||||
example: 1
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
mode: box
|
||||
property_key:
|
||||
required: false
|
||||
example: 1
|
||||
selector:
|
||||
text:
|
||||
from:
|
||||
required: false
|
||||
selector:
|
||||
object:
|
||||
to:
|
||||
required: false
|
||||
selector:
|
||||
object:
|
||||
@@ -51,11 +51,25 @@ RELATIVE_PLATFORM_TYPE = f"{__name__.rsplit('.', maxsplit=1)[-1]}"
|
||||
PLATFORM_TYPE = f"{DOMAIN}.{RELATIVE_PLATFORM_TYPE}"
|
||||
|
||||
|
||||
def validate_non_node_event_source(obj: dict) -> dict:
|
||||
"""Validate that a trigger for a non node event source has a config entry."""
|
||||
if obj[ATTR_EVENT_SOURCE] != "node" and ATTR_CONFIG_ENTRY_ID in obj:
|
||||
def validate_event_source_targets(obj: dict) -> dict:
|
||||
"""Validate that the targets match the event source."""
|
||||
if obj[ATTR_EVENT_SOURCE] == "node":
|
||||
if ATTR_DEVICE_ID not in obj and ATTR_ENTITY_ID not in obj:
|
||||
raise vol.Invalid(
|
||||
f"Node event triggers must contain {ATTR_DEVICE_ID} or "
|
||||
f"{ATTR_ENTITY_ID}."
|
||||
)
|
||||
return obj
|
||||
raise vol.Invalid(f"Non node event triggers must contain {ATTR_CONFIG_ENTRY_ID}.")
|
||||
if ATTR_CONFIG_ENTRY_ID not in obj:
|
||||
raise vol.Invalid(
|
||||
f"Non node event triggers must contain {ATTR_CONFIG_ENTRY_ID}."
|
||||
)
|
||||
if ATTR_DEVICE_ID in obj or ATTR_ENTITY_ID in obj:
|
||||
raise vol.Invalid(
|
||||
f"Non node event triggers must not contain {ATTR_DEVICE_ID} or "
|
||||
f"{ATTR_ENTITY_ID}."
|
||||
)
|
||||
return obj
|
||||
|
||||
|
||||
def validate_event_name(obj: dict) -> dict:
|
||||
@@ -112,10 +126,7 @@ _CONFIG_SCHEMA = vol.Schema(
|
||||
_OPTIONS_SCHEMA_DICT,
|
||||
validate_event_name,
|
||||
validate_event_data,
|
||||
vol.Any(
|
||||
validate_non_node_event_source,
|
||||
cv.has_at_least_one_key(ATTR_DEVICE_ID, ATTR_ENTITY_ID),
|
||||
),
|
||||
validate_event_source_targets,
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -158,7 +158,6 @@ NON_MIGRATED_INTEGRATIONS = {
|
||||
"webhook",
|
||||
"webostv",
|
||||
"zone",
|
||||
"zwave_js",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from copy import deepcopy
|
||||
from typing import Any
|
||||
|
||||
from zwave_js_server.const import CommandClass
|
||||
from zwave_js_server.model.node.data_model import NodeDataType
|
||||
|
||||
from homeassistant.components.zwave_js.helpers import (
|
||||
@@ -10,6 +11,9 @@ from homeassistant.components.zwave_js.helpers import (
|
||||
value_matches_matcher,
|
||||
)
|
||||
|
||||
# NIF markers listed in SDS13548 as "not an actual Command Class"
|
||||
COMMAND_CLASS_MARKERS = {CommandClass.MARK, CommandClass.SECURITY_SCHEME0_MARK}
|
||||
|
||||
AIR_TEMPERATURE_SENSOR = "sensor.multisensor_6_air_temperature"
|
||||
BATTERY_SENSOR = "sensor.multisensor_6_battery_level"
|
||||
TAMPER_SENSOR = "binary_sensor.multisensor_6_tampering_product_cover_removed"
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"""The tests for Z-Wave JS automation triggers."""
|
||||
|
||||
from contextlib import AbstractContextManager, nullcontext as does_not_raise
|
||||
import copy
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
@@ -13,17 +14,24 @@ from homeassistant.components import automation
|
||||
from homeassistant.components.zwave_js import DOMAIN
|
||||
from homeassistant.components.zwave_js.helpers import get_device_id
|
||||
from homeassistant.components.zwave_js.trigger import TRIGGERS
|
||||
from homeassistant.components.zwave_js.triggers.event import (
|
||||
_OPTIONS_SCHEMA_DICT as EVENT_OPTIONS_SCHEMA_DICT,
|
||||
)
|
||||
from homeassistant.components.zwave_js.triggers.trigger_helpers import (
|
||||
async_bypass_dynamic_config_validation,
|
||||
)
|
||||
from homeassistant.components.zwave_js.triggers.value_updated import (
|
||||
_OPTIONS_SCHEMA_DICT as VALUE_UPDATED_OPTIONS_SCHEMA_DICT,
|
||||
)
|
||||
from homeassistant.const import SERVICE_RELOAD
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers import device_registry as dr, trigger
|
||||
from homeassistant.helpers.translation import async_get_translations
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .common import SCHLAGE_BE469_LOCK_ENTITY
|
||||
from .common import COMMAND_CLASS_MARKERS, SCHLAGE_BE469_LOCK_ENTITY
|
||||
|
||||
from tests.common import async_capture_events
|
||||
from tests.common import MockConfigEntry, async_capture_events
|
||||
|
||||
|
||||
async def test_zwave_js_value_updated(
|
||||
@@ -1042,6 +1050,84 @@ async def test_invalid_trigger_configs(hass: HomeAssistant) -> None:
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("event_source", "event", "option_keys", "expectation"),
|
||||
[
|
||||
pytest.param(
|
||||
"controller",
|
||||
"inclusion started",
|
||||
["config_entry_id", "device_id"],
|
||||
pytest.raises(vol.Invalid, match="must not contain"),
|
||||
id="controller_with_device_id",
|
||||
),
|
||||
pytest.param(
|
||||
"driver",
|
||||
"logging",
|
||||
["config_entry_id", "entity_id"],
|
||||
pytest.raises(vol.Invalid, match="must not contain"),
|
||||
id="driver_with_entity_id",
|
||||
),
|
||||
pytest.param(
|
||||
"node",
|
||||
"interview stage completed",
|
||||
[],
|
||||
pytest.raises(vol.Invalid, match="must contain"),
|
||||
id="node_without_targets",
|
||||
),
|
||||
pytest.param(
|
||||
"controller",
|
||||
"inclusion started",
|
||||
["config_entry_id"],
|
||||
does_not_raise(),
|
||||
id="controller_without_targets",
|
||||
),
|
||||
pytest.param(
|
||||
"controller",
|
||||
"inclusion started",
|
||||
[],
|
||||
pytest.raises(vol.Invalid, match="must contain config_entry_id"),
|
||||
id="controller_without_config_entry",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_zwave_js_event_source_target_validation(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
client: MagicMock,
|
||||
lock_schlage_be469: Node,
|
||||
integration: MockConfigEntry,
|
||||
event_source: str,
|
||||
event: str,
|
||||
option_keys: list[str],
|
||||
expectation: AbstractContextManager,
|
||||
) -> None:
|
||||
"""Test that zwave_js.event targets are validated against the event source."""
|
||||
device = device_registry.async_get_device_by_identifier(
|
||||
get_device_id(client.driver, lock_schlage_be469), integration.entry_id
|
||||
)
|
||||
assert device
|
||||
options = {
|
||||
"config_entry_id": integration.entry_id,
|
||||
"device_id": device.id,
|
||||
"entity_id": SCHLAGE_BE469_LOCK_ENTITY,
|
||||
}
|
||||
|
||||
with expectation:
|
||||
await trigger.async_validate_trigger_config(
|
||||
hass,
|
||||
[
|
||||
{
|
||||
"platform": f"{DOMAIN}.event",
|
||||
"options": {
|
||||
"event_source": event_source,
|
||||
"event": event,
|
||||
**{key: options[key] for key in option_keys},
|
||||
},
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
async def test_zwave_js_trigger_config_entry_unloaded(
|
||||
hass: HomeAssistant,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
@@ -1495,3 +1581,46 @@ async def test_zwave_js_old_syntax(
|
||||
node.receive_event(event)
|
||||
await hass.async_block_till_done()
|
||||
assert len(zwavejs_value_updated) == 1
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("integration")
|
||||
async def test_value_updated_command_class_options(hass: HomeAssistant) -> None:
|
||||
"""Test the command class options and translations match the CommandClass enum."""
|
||||
expected = {str(cc.value) for cc in CommandClass if cc not in COMMAND_CLASS_MARKERS}
|
||||
|
||||
descriptions = await trigger.async_get_all_descriptions(hass)
|
||||
options = descriptions[f"{DOMAIN}.value_updated"]["fields"]["command_class"][
|
||||
"selector"
|
||||
]["select"]["options"]
|
||||
assert len(options) == len(expected)
|
||||
assert set(options) == expected
|
||||
|
||||
translations = await async_get_translations(hass, "en", "selector", {DOMAIN})
|
||||
prefix = f"component.{DOMAIN}.selector.command_class.options."
|
||||
assert {
|
||||
key.removeprefix(prefix) for key in translations if key.startswith(prefix)
|
||||
} == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("trigger_type", "options_schema"),
|
||||
[
|
||||
pytest.param(f"{DOMAIN}.event", EVENT_OPTIONS_SCHEMA_DICT, id="event"),
|
||||
pytest.param(
|
||||
f"{DOMAIN}.value_updated",
|
||||
VALUE_UPDATED_OPTIONS_SCHEMA_DICT,
|
||||
id="value_updated",
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("integration")
|
||||
async def test_trigger_description_fields_match_schema(
|
||||
hass: HomeAssistant, trigger_type: str, options_schema: dict[vol.Marker, object]
|
||||
) -> None:
|
||||
"""Test the described fields match the trigger's options schema."""
|
||||
descriptions = await trigger.async_get_all_descriptions(hass)
|
||||
fields = descriptions[trigger_type]["fields"]
|
||||
assert set(fields) == {str(key) for key in options_schema}
|
||||
assert {name for name, field in fields.items() if field["required"]} == {
|
||||
str(key) for key in options_schema if isinstance(key, vol.Required)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user