Add OZW support for set_config_parameter service (#37523)
* Add support for set_config_parameter service * Adjusted elif to if * More if/else cleanup * More if/else cleanup * Less nesting * End loop properly * Added byte type * Convert break to return
This commit is contained in:
parent
03ce1f46f6
commit
aa8f3ad307
4 changed files with 189 additions and 0 deletions
|
@ -25,6 +25,8 @@ PLATFORMS = [
|
|||
TOPIC_OPENZWAVE = "OpenZWave"
|
||||
|
||||
# Common Attributes
|
||||
ATTR_CONFIG_PARAMETER = "parameter"
|
||||
ATTR_CONFIG_VALUE = "value"
|
||||
ATTR_INSTANCE_ID = "instance_id"
|
||||
ATTR_SECURE = "secure"
|
||||
ATTR_NODE_ID = "node_id"
|
||||
|
@ -36,6 +38,7 @@ ATTR_SCENE_VALUE_LABEL = "scene_value_label"
|
|||
# Service specific
|
||||
SERVICE_ADD_NODE = "add_node"
|
||||
SERVICE_REMOVE_NODE = "remove_node"
|
||||
SERVICE_SET_CONFIG_PARAMETER = "set_config_parameter"
|
||||
|
||||
# Home Assistant Events
|
||||
EVENT_SCENE_ACTIVATED = f"{DOMAIN}.scene_activated"
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
"""Methods and classes related to executing Z-Wave commands and publishing these to hass."""
|
||||
import logging
|
||||
|
||||
from openzwavemqtt.const import CommandClass, ValueType
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import callback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from . import const
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ZWaveServices:
|
||||
"""Class that holds our services ( Zwave Commands) that should be published to hass."""
|
||||
|
@ -37,6 +43,98 @@ class ZWaveServices:
|
|||
),
|
||||
)
|
||||
|
||||
self._hass.services.async_register(
|
||||
const.DOMAIN,
|
||||
const.SERVICE_SET_CONFIG_PARAMETER,
|
||||
self.async_set_config_parameter,
|
||||
schema=vol.Schema(
|
||||
{
|
||||
vol.Optional(const.ATTR_INSTANCE_ID, default=1): vol.Coerce(int),
|
||||
vol.Required(const.ATTR_NODE_ID): vol.Coerce(int),
|
||||
vol.Required(const.ATTR_CONFIG_PARAMETER): vol.Coerce(int),
|
||||
vol.Required(const.ATTR_CONFIG_VALUE): vol.Any(
|
||||
vol.Coerce(int), cv.string
|
||||
),
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
@callback
|
||||
def async_set_config_parameter(self, service):
|
||||
"""Set a config parameter to a node."""
|
||||
instance_id = service.data[const.ATTR_INSTANCE_ID]
|
||||
node_id = service.data[const.ATTR_NODE_ID]
|
||||
param = service.data[const.ATTR_CONFIG_PARAMETER]
|
||||
selection = service.data[const.ATTR_CONFIG_VALUE]
|
||||
payload = None
|
||||
|
||||
node = self._manager.get_instance(instance_id).get_node(node_id).values()
|
||||
|
||||
for value in node:
|
||||
if (
|
||||
value.command_class != CommandClass.CONFIGURATION
|
||||
or value.index != param
|
||||
):
|
||||
continue
|
||||
|
||||
if value.type == ValueType.BOOL:
|
||||
payload = selection == "True"
|
||||
|
||||
if value.type == ValueType.LIST:
|
||||
# accept either string from the list value OR the int value
|
||||
if isinstance(selection, int):
|
||||
if selection > value.max or selection < value.min:
|
||||
_LOGGER.error(
|
||||
"Value %s out of range for parameter %s (Min: %s Max: %s)",
|
||||
selection,
|
||||
param,
|
||||
value.min,
|
||||
value.max,
|
||||
)
|
||||
return
|
||||
payload = int(selection)
|
||||
|
||||
# iterate list labels to get value
|
||||
for selected in value.value["List"]:
|
||||
if selected["Label"] != selection:
|
||||
continue
|
||||
payload = int(selected["Value"])
|
||||
|
||||
if payload is None:
|
||||
_LOGGER.error(
|
||||
"Invalid value %s for parameter %s", selection, param,
|
||||
)
|
||||
return
|
||||
|
||||
if value.type == ValueType.BUTTON:
|
||||
# Unsupported at this time
|
||||
_LOGGER.info("Button type not supported yet")
|
||||
return
|
||||
|
||||
if value.type == ValueType.STRING:
|
||||
payload = selection
|
||||
|
||||
if value.type == ValueType.INT or value.type == ValueType.BYTE:
|
||||
if selection > value.max or selection < value.min:
|
||||
_LOGGER.error(
|
||||
"Value %s out of range for parameter %s (Min: %s Max: %s)",
|
||||
selection,
|
||||
param,
|
||||
value.min,
|
||||
value.max,
|
||||
)
|
||||
return
|
||||
payload = int(selection)
|
||||
|
||||
value.send_value(payload) # send the payload
|
||||
_LOGGER.info(
|
||||
"Setting configuration parameter %s on Node %s with value %s",
|
||||
param,
|
||||
node_id,
|
||||
payload,
|
||||
)
|
||||
return
|
||||
|
||||
@callback
|
||||
def async_add_node(self, service):
|
||||
"""Enter inclusion mode on the controller."""
|
||||
|
|
|
@ -12,3 +12,18 @@ remove_node:
|
|||
fields:
|
||||
instance_id:
|
||||
description: (Optional) The OZW Instance/Controller to use, defaults to 1.
|
||||
|
||||
set_config_parameter:
|
||||
description: Set a config parameter to a node on the Z-Wave network.
|
||||
fields:
|
||||
node_id:
|
||||
description: Node id of the device to set config parameter to (integer).
|
||||
example: 10
|
||||
parameter:
|
||||
description: Parameter number to set (integer).
|
||||
example: 8
|
||||
value:
|
||||
description: Value to set for parameter. (String value for list and bool parameters, integer for others).
|
||||
example: 50268673
|
||||
instance_id:
|
||||
description: (Optional) The OZW Instance/Controller to use, defaults to 1.
|
||||
|
|
73
tests/components/ozw/test_services.py
Normal file
73
tests/components/ozw/test_services.py
Normal file
|
@ -0,0 +1,73 @@
|
|||
"""Test Z-Wave Services."""
|
||||
from .common import setup_ozw
|
||||
|
||||
|
||||
async def test_services(hass, lock_data, sent_messages, lock_msg, caplog):
|
||||
"""Test services on lock."""
|
||||
await setup_ozw(hass, fixture=lock_data)
|
||||
|
||||
# Test set_config_parameter list by label
|
||||
await hass.services.async_call(
|
||||
"ozw",
|
||||
"set_config_parameter",
|
||||
{"node_id": 10, "parameter": 1, "value": "Disabled"},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(sent_messages) == 1
|
||||
msg = sent_messages[0]
|
||||
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
|
||||
assert msg["payload"] == {"Value": 0, "ValueIDKey": 281475154706452}
|
||||
|
||||
# Test set_config_parameter list by index int
|
||||
await hass.services.async_call(
|
||||
"ozw",
|
||||
"set_config_parameter",
|
||||
{"node_id": 10, "parameter": 1, "value": 0},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(sent_messages) == 2
|
||||
msg = sent_messages[1]
|
||||
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
|
||||
assert msg["payload"] == {"Value": 0, "ValueIDKey": 281475154706452}
|
||||
|
||||
# Test set_config_parameter int
|
||||
await hass.services.async_call(
|
||||
"ozw",
|
||||
"set_config_parameter",
|
||||
{"node_id": 10, "parameter": 6, "value": 0},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(sent_messages) == 3
|
||||
msg = sent_messages[2]
|
||||
assert msg["topic"] == "OpenZWave/1/command/setvalue/"
|
||||
assert msg["payload"] == {"Value": 0, "ValueIDKey": 1688850038259731}
|
||||
|
||||
# Test set_config_parameter invalid list int
|
||||
await hass.services.async_call(
|
||||
"ozw",
|
||||
"set_config_parameter",
|
||||
{"node_id": 10, "parameter": 1, "value": 12},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(sent_messages) == 3
|
||||
assert "Value 12 out of range for parameter 1" in caplog.text
|
||||
|
||||
# Test set_config_parameter invalid list string
|
||||
await hass.services.async_call(
|
||||
"ozw",
|
||||
"set_config_parameter",
|
||||
{"node_id": 10, "parameter": 1, "value": "Blah"},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(sent_messages) == 3
|
||||
assert "Invalid value Blah for parameter 1" in caplog.text
|
||||
|
||||
# Test set_config_parameter int out of range
|
||||
await hass.services.async_call(
|
||||
"ozw",
|
||||
"set_config_parameter",
|
||||
{"node_id": 10, "parameter": 6, "value": 2147483657},
|
||||
blocking=True,
|
||||
)
|
||||
assert len(sent_messages) == 3
|
||||
assert "Value 12 out of range for parameter 1" in caplog.text
|
Loading…
Add table
Add a link
Reference in a new issue