Convert val to str when needed while calling zwave_js.set_value (#57216)

This commit is contained in:
Raman Gupta 2021-10-07 16:22:33 -04:00 committed by GitHub
parent 33b8130002
commit 3476b430db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 130 additions and 14 deletions

View File

@ -408,7 +408,7 @@ class ZWaveServices:
async def async_set_value(self, service: ServiceCall) -> None: async def async_set_value(self, service: ServiceCall) -> None:
"""Set a value on a node.""" """Set a value on a node."""
# pylint: disable=no-self-use # pylint: disable=no-self-use
nodes = service.data[const.ATTR_NODES] nodes: set[ZwaveNode] = service.data[const.ATTR_NODES]
command_class = service.data[const.ATTR_COMMAND_CLASS] command_class = service.data[const.ATTR_COMMAND_CLASS]
property_ = service.data[const.ATTR_PROPERTY] property_ = service.data[const.ATTR_PROPERTY]
property_key = service.data.get(const.ATTR_PROPERTY_KEY) property_key = service.data.get(const.ATTR_PROPERTY_KEY)
@ -418,15 +418,27 @@ class ZWaveServices:
options = service.data.get(const.ATTR_OPTIONS) options = service.data.get(const.ATTR_OPTIONS)
for node in nodes: for node in nodes:
success = await node.async_set_value( value_id = get_value_id(
get_value_id(
node, node,
command_class, command_class,
property_, property_,
endpoint=endpoint, endpoint=endpoint,
property_key=property_key, property_key=property_key,
), )
new_value, # If value has a string type but the new value is not a string, we need to
# convert it to one. We use new variable `new_value_` to convert the data
# so we can preserve the original `new_value` for every node.
if (
value_id in node.values
and node.values[value_id].metadata.type == "string"
and not isinstance(new_value, str)
):
new_value_ = str(new_value)
else:
new_value_ = new_value
success = await node.async_set_value(
value_id,
new_value_,
options=options, options=options,
wait_for_result=wait_for_result, wait_for_result=wait_for_result,
) )
@ -452,11 +464,16 @@ class ZWaveServices:
await self.async_set_value(service) await self.async_set_value(service)
return return
command_class = service.data[const.ATTR_COMMAND_CLASS]
property_ = service.data[const.ATTR_PROPERTY]
property_key = service.data.get(const.ATTR_PROPERTY_KEY)
endpoint = service.data.get(const.ATTR_ENDPOINT)
value = { value = {
"commandClass": service.data[const.ATTR_COMMAND_CLASS], "commandClass": command_class,
"property": service.data[const.ATTR_PROPERTY], "property": property_,
"propertyKey": service.data.get(const.ATTR_PROPERTY_KEY), "propertyKey": property_key,
"endpoint": service.data.get(const.ATTR_ENDPOINT), "endpoint": endpoint,
} }
new_value = service.data[const.ATTR_VALUE] new_value = service.data[const.ATTR_VALUE]
@ -464,12 +481,30 @@ class ZWaveServices:
# schema validation and can use that to get the client, otherwise we can just # schema validation and can use that to get the client, otherwise we can just
# get the client from the node. # get the client from the node.
client: ZwaveClient = None client: ZwaveClient = None
first_node = next((node for node in nodes), None) first_node: ZwaveNode = next((node for node in nodes), None)
if first_node: if first_node:
client = first_node.client client = first_node.client
else: else:
entry_id = self._hass.config_entries.async_entries(const.DOMAIN)[0].entry_id entry_id = self._hass.config_entries.async_entries(const.DOMAIN)[0].entry_id
client = self._hass.data[const.DOMAIN][entry_id][const.DATA_CLIENT] client = self._hass.data[const.DOMAIN][entry_id][const.DATA_CLIENT]
first_node = next(
node
for node in client.driver.controller.nodes.values()
if get_value_id(node, command_class, property_, endpoint, property_key)
in node.values
)
# If value has a string type but the new value is not a string, we need to
# convert it to one
value_id = get_value_id(
first_node, command_class, property_, endpoint, property_key
)
if (
value_id in first_node.values
and first_node.values[value_id].metadata.type == "string"
and not isinstance(new_value, str)
):
new_value = str(new_value)
success = await async_multicast_set_value( success = await async_multicast_set_value(
client=client, client=client,

View File

@ -43,6 +43,7 @@ from .common import (
CLIMATE_DANFOSS_LC13_ENTITY, CLIMATE_DANFOSS_LC13_ENTITY,
CLIMATE_EUROTRONICS_SPIRIT_Z_ENTITY, CLIMATE_EUROTRONICS_SPIRIT_Z_ENTITY,
CLIMATE_RADIO_THERMOSTAT_ENTITY, CLIMATE_RADIO_THERMOSTAT_ENTITY,
SCHLAGE_BE469_LOCK_ENTITY,
) )
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
@ -1021,6 +1022,51 @@ async def test_set_value(hass, client, climate_danfoss_lc_13, integration):
) )
async def test_set_value_string(
hass, client, climate_danfoss_lc_13, lock_schlage_be469, integration
):
"""Test set_value service converts number to string when needed."""
client.async_send_command.return_value = {"success": True}
# Test that number gets converted to a string when needed
await hass.services.async_call(
DOMAIN,
SERVICE_SET_VALUE,
{
ATTR_ENTITY_ID: SCHLAGE_BE469_LOCK_ENTITY,
ATTR_COMMAND_CLASS: 99,
ATTR_PROPERTY: "userCode",
ATTR_PROPERTY_KEY: 1,
ATTR_VALUE: 12345,
},
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"] == lock_schlage_be469.node_id
assert args["valueId"] == {
"commandClassName": "User Code",
"commandClass": 99,
"endpoint": 0,
"property": "userCode",
"propertyName": "userCode",
"propertyKey": 1,
"propertyKeyName": "1",
"metadata": {
"type": "string",
"readable": True,
"writeable": True,
"minLength": 4,
"maxLength": 10,
"label": "User Code (1)",
},
"value": "**********",
}
assert args["value"] == "12345"
async def test_set_value_options(hass, client, aeon_smart_switch_6, integration): async def test_set_value_options(hass, client, aeon_smart_switch_6, integration):
"""Test set_value service with options.""" """Test set_value service with options."""
await hass.services.async_call( await hass.services.async_call(
@ -1381,6 +1427,41 @@ async def test_multicast_set_value_options(
client.async_send_command.reset_mock() client.async_send_command.reset_mock()
async def test_multicast_set_value_string(
hass,
client,
lock_id_lock_as_id150,
lock_schlage_be469,
integration,
):
"""Test multicast_set_value service converts number to string when needed."""
client.async_send_command.return_value = {"success": True}
# Test that number gets converted to a string when needed
await hass.services.async_call(
DOMAIN,
SERVICE_MULTICAST_SET_VALUE,
{
ATTR_BROADCAST: True,
ATTR_COMMAND_CLASS: 99,
ATTR_PROPERTY: "userCode",
ATTR_PROPERTY_KEY: 1,
ATTR_VALUE: 12345,
},
blocking=True,
)
assert len(client.async_send_command.call_args_list) == 1
args = client.async_send_command.call_args[0][0]
assert args["command"] == "broadcast_node.set_value"
assert args["valueId"] == {
"commandClass": 99,
"property": "userCode",
"propertyKey": 1,
}
assert args["value"] == "12345"
async def test_ping( async def test_ping(
hass, hass,
client, client,