Add zwave_js Protection CC select entities (#54717)
* Add Protection CC select entities comment * Disable entity by default * use class attribute * Enable protection entity by default * add guard for none
This commit is contained in:
parent
35f563e23e
commit
cff6883b5c
3 changed files with 146 additions and 0 deletions
|
@ -646,6 +646,16 @@ DISCOVERY_SCHEMAS = [
|
||||||
),
|
),
|
||||||
required_values=[SIREN_TONE_SCHEMA],
|
required_values=[SIREN_TONE_SCHEMA],
|
||||||
),
|
),
|
||||||
|
# select
|
||||||
|
# protection CC
|
||||||
|
ZWaveDiscoverySchema(
|
||||||
|
platform="select",
|
||||||
|
primary_value=ZWaveValueDiscoverySchema(
|
||||||
|
command_class={CommandClass.PROTECTION},
|
||||||
|
property={"local", "rf"},
|
||||||
|
type={"number"},
|
||||||
|
),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@ async def async_setup_entry(
|
||||||
entities: list[ZWaveBaseEntity] = []
|
entities: list[ZWaveBaseEntity] = []
|
||||||
if info.platform_hint == "Default tone":
|
if info.platform_hint == "Default tone":
|
||||||
entities.append(ZwaveDefaultToneSelectEntity(config_entry, client, info))
|
entities.append(ZwaveDefaultToneSelectEntity(config_entry, client, info))
|
||||||
|
else:
|
||||||
|
entities.append(ZwaveSelectEntity(config_entry, client, info))
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
config_entry.async_on_unload(
|
config_entry.async_on_unload(
|
||||||
|
@ -40,6 +42,40 @@ async def async_setup_entry(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ZwaveSelectEntity(ZWaveBaseEntity, SelectEntity):
|
||||||
|
"""Representation of a Z-Wave select entity."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, config_entry: ConfigEntry, client: ZwaveClient, info: ZwaveDiscoveryInfo
|
||||||
|
) -> None:
|
||||||
|
"""Initialize a ZwaveSelectEntity entity."""
|
||||||
|
super().__init__(config_entry, client, info)
|
||||||
|
|
||||||
|
# Entity class attributes
|
||||||
|
self._attr_name = self.generate_name(include_value_name=True)
|
||||||
|
self._attr_options = list(self.info.primary_value.metadata.states.values())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_option(self) -> str | None:
|
||||||
|
"""Return the selected entity option to represent the entity state."""
|
||||||
|
if self.info.primary_value.value is None:
|
||||||
|
return None
|
||||||
|
return str(
|
||||||
|
self.info.primary_value.metadata.states.get(
|
||||||
|
str(self.info.primary_value.value), self.info.primary_value.value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_select_option(self, option: str | int) -> None:
|
||||||
|
"""Change the selected option."""
|
||||||
|
key = next(
|
||||||
|
key
|
||||||
|
for key, val in self.info.primary_value.metadata.states.items()
|
||||||
|
if val == option
|
||||||
|
)
|
||||||
|
await self.info.node.async_set_value(self.info.primary_value, int(key))
|
||||||
|
|
||||||
|
|
||||||
class ZwaveDefaultToneSelectEntity(ZWaveBaseEntity, SelectEntity):
|
class ZwaveDefaultToneSelectEntity(ZWaveBaseEntity, SelectEntity):
|
||||||
"""Representation of a Z-Wave default tone select entity."""
|
"""Representation of a Z-Wave default tone select entity."""
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
"""Test the Z-Wave JS number platform."""
|
"""Test the Z-Wave JS number platform."""
|
||||||
from zwave_js_server.event import Event
|
from zwave_js_server.event import Event
|
||||||
|
|
||||||
|
from homeassistant.const import STATE_UNKNOWN
|
||||||
|
|
||||||
DEFAULT_TONE_SELECT_ENTITY = "select.indoor_siren_6_default_tone_2"
|
DEFAULT_TONE_SELECT_ENTITY = "select.indoor_siren_6_default_tone_2"
|
||||||
|
PROTECTION_SELECT_ENTITY = "select.family_room_combo_local_protection_state"
|
||||||
|
|
||||||
|
|
||||||
async def test_default_tone_select(hass, client, aeotec_zw164_siren, integration):
|
async def test_default_tone_select(hass, client, aeotec_zw164_siren, integration):
|
||||||
|
@ -99,3 +102,100 @@ async def test_default_tone_select(hass, client, aeotec_zw164_siren, integration
|
||||||
|
|
||||||
state = hass.states.get(DEFAULT_TONE_SELECT_ENTITY)
|
state = hass.states.get(DEFAULT_TONE_SELECT_ENTITY)
|
||||||
assert state.state == "30DOOR~1 (27 sec)"
|
assert state.state == "30DOOR~1 (27 sec)"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_protection_select(hass, client, inovelli_lzw36, integration):
|
||||||
|
"""Test the default tone select entity."""
|
||||||
|
node = inovelli_lzw36
|
||||||
|
state = hass.states.get(PROTECTION_SELECT_ENTITY)
|
||||||
|
|
||||||
|
assert state
|
||||||
|
assert state.state == "Unprotected"
|
||||||
|
attr = state.attributes
|
||||||
|
assert attr["options"] == [
|
||||||
|
"Unprotected",
|
||||||
|
"ProtectedBySequence",
|
||||||
|
"NoOperationPossible",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Test select option with string value
|
||||||
|
await hass.services.async_call(
|
||||||
|
"select",
|
||||||
|
"select_option",
|
||||||
|
{"entity_id": PROTECTION_SELECT_ENTITY, "option": "ProtectedBySequence"},
|
||||||
|
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"] == node.node_id
|
||||||
|
assert args["valueId"] == {
|
||||||
|
"endpoint": 0,
|
||||||
|
"commandClass": 117,
|
||||||
|
"commandClassName": "Protection",
|
||||||
|
"property": "local",
|
||||||
|
"propertyName": "local",
|
||||||
|
"ccVersion": 2,
|
||||||
|
"metadata": {
|
||||||
|
"type": "number",
|
||||||
|
"readable": True,
|
||||||
|
"writeable": True,
|
||||||
|
"label": "Local protection state",
|
||||||
|
"states": {
|
||||||
|
"0": "Unprotected",
|
||||||
|
"1": "ProtectedBySequence",
|
||||||
|
"2": "NoOperationPossible",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"value": 0,
|
||||||
|
}
|
||||||
|
assert args["value"] == 1
|
||||||
|
|
||||||
|
client.async_send_command.reset_mock()
|
||||||
|
|
||||||
|
# Test value update from value updated event
|
||||||
|
event = Event(
|
||||||
|
type="value updated",
|
||||||
|
data={
|
||||||
|
"source": "node",
|
||||||
|
"event": "value updated",
|
||||||
|
"nodeId": node.node_id,
|
||||||
|
"args": {
|
||||||
|
"commandClassName": "Protection",
|
||||||
|
"commandClass": 117,
|
||||||
|
"endpoint": 0,
|
||||||
|
"property": "local",
|
||||||
|
"newValue": 1,
|
||||||
|
"prevValue": 0,
|
||||||
|
"propertyName": "local",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
node.receive_event(event)
|
||||||
|
|
||||||
|
state = hass.states.get(PROTECTION_SELECT_ENTITY)
|
||||||
|
assert state.state == "ProtectedBySequence"
|
||||||
|
|
||||||
|
# Test null value
|
||||||
|
event = Event(
|
||||||
|
type="value updated",
|
||||||
|
data={
|
||||||
|
"source": "node",
|
||||||
|
"event": "value updated",
|
||||||
|
"nodeId": node.node_id,
|
||||||
|
"args": {
|
||||||
|
"commandClassName": "Protection",
|
||||||
|
"commandClass": 117,
|
||||||
|
"endpoint": 0,
|
||||||
|
"property": "local",
|
||||||
|
"newValue": None,
|
||||||
|
"prevValue": 1,
|
||||||
|
"propertyName": "local",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
node.receive_event(event)
|
||||||
|
|
||||||
|
state = hass.states.get(PROTECTION_SELECT_ENTITY)
|
||||||
|
assert state.state == STATE_UNKNOWN
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue