async def async_multicast_set_value(self, service: ServiceCall) -> None: """Set a value via multicast to multiple nodes.""" nodes = service.data[const.ATTR_NODES] broadcast: bool = service.data[const.ATTR_BROADCAST] value = { "commandClass": service.data[const.ATTR_COMMAND_CLASS], "property": service.data[const.ATTR_PROPERTY], "propertyKey": service.data.get(const.ATTR_PROPERTY_KEY), "endpoint": service.data.get(const.ATTR_ENDPOINT), } new_value = service.data[const.ATTR_VALUE] # If there are no nodes, we can assume there is only one config entry due to # schema validation and can use that to get the client, otherwise we can just # get the client from the node. client: ZwaveClient = None first_node = next((node for node in nodes), None) if first_node: client = first_node.client else: entry_id = self._hass.config_entries.async_entries( const.DOMAIN)[0].entry_id client = self._hass.data[const.DOMAIN][entry_id][const.DATA_CLIENT] success = await async_multicast_set_value( client, new_value, {k: v for k, v in value.items() if v is not None}, None if broadcast else list(nodes), ) if success is False: raise SetValueFailed("Unable to set value via multicast")
async def async_set_value(self, service: ServiceCall) -> None: """Set a value on a node.""" nodes = service.data[const.ATTR_NODES] 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) new_value = service.data[const.ATTR_VALUE] wait_for_result = service.data.get(const.ATTR_WAIT_FOR_RESULT) for node in nodes: success = await node.async_set_value( get_value_id( node, command_class, property_, endpoint=endpoint, property_key=property_key, ), new_value, wait_for_result=wait_for_result, ) if success is False: raise SetValueFailed( "Unable to set value, refer to " "https://zwave-js.github.io/node-zwave-js/#/api/node?id=setvalue " "for possible reasons")
async def async_set_value(self, service: ServiceCall) -> None: """Set a value on a node.""" # pylint: disable=no-self-use nodes: set[ZwaveNode] = service.data[const.ATTR_NODES] 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) new_value = service.data[const.ATTR_VALUE] wait_for_result = service.data.get(const.ATTR_WAIT_FOR_RESULT) options = service.data.get(const.ATTR_OPTIONS) for node in nodes: value_id = get_value_id( node, command_class, property_, endpoint=endpoint, property_key=property_key, ) # 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, wait_for_result=wait_for_result, ) if success is False: raise SetValueFailed( "Unable to set value, refer to " "https://zwave-js.github.io/node-zwave-js/#/api/node?id=setvalue " "for possible reasons")
async def async_set_value(self, service: ServiceCall) -> None: """Set a value on a node.""" nodes: set[ZwaveNode] = set() if ATTR_ENTITY_ID in service.data: nodes |= { async_get_node_from_entity_id(self._opp, entity_id) for entity_id in service.data[ATTR_ENTITY_ID] } if ATTR_DEVICE_ID in service.data: nodes |= { async_get_node_from_device_id(self._opp, device_id) for device_id in service.data[ATTR_DEVICE_ID] } 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) new_value = service.data[const.ATTR_VALUE] wait_for_result = service.data.get(const.ATTR_WAIT_FOR_RESULT) for node in nodes: success = await node.async_set_value( get_value_id( node, command_class, property_, endpoint=endpoint, property_key=property_key, ), new_value, wait_for_result=wait_for_result, ) if success is False: raise SetValueFailed( "Unable to set value, refer to " "https://zwave-js.github.io/node-zwave-js/#/api/node?id=setvalue " "for possible reasons" )
from homeassistant.helpers.dispatcher import async_dispatcher_send from . import const from .config_validation import BITMASK_SCHEMA, VALUE_SCHEMA from .helpers import ( async_get_node_from_device_id, async_get_node_from_entity_id, async_get_nodes_from_area_id, async_get_nodes_from_targets, get_value_id_from_unique_id, ) _LOGGER = logging.getLogger(__name__) SET_VALUE_FAILED_EXC = SetValueFailed( "Unable to set value, refer to " "https://zwave-js.github.io/node-zwave-js/#/api/node?id=setvalue for " "possible reasons") def parameter_name_does_not_need_bitmask( val: dict[str, int | str | list[str]]) -> dict[str, int | str | list[str]]: """Validate that if a parameter name is provided, bitmask is not as well.""" if (isinstance(val[const.ATTR_CONFIG_PARAMETER], str) and const.ATTR_CONFIG_PARAMETER_BITMASK in val): raise vol.Invalid( "Don't include a bitmask when a parameter name is specified", path=[ const.ATTR_CONFIG_PARAMETER, const.ATTR_CONFIG_PARAMETER_BITMASK ],
async def async_multicast_set_value(self, service: ServiceCall) -> None: """Set a value via multicast to multiple nodes.""" nodes = service.data[const.ATTR_NODES] broadcast: bool = service.data[const.ATTR_BROADCAST] options = service.data.get(const.ATTR_OPTIONS) if not broadcast and len(nodes) == 1: const.LOGGER.info( "Passing the zwave_js.multicast_set_value service call to the " "zwave_js.set_value service since only one node was targeted") await self.async_set_value(service) 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 = { "commandClass": command_class, "property": property_, "propertyKey": property_key, "endpoint": endpoint, } new_value = service.data[const.ATTR_VALUE] # If there are no nodes, we can assume there is only one config entry due to # schema validation and can use that to get the client, otherwise we can just # get the client from the node. client: ZwaveClient = None first_node: ZwaveNode = next((node for node in nodes), None) if first_node: client = first_node.client else: entry_id = self._hass.config_entries.async_entries( const.DOMAIN)[0].entry_id 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( client=client, new_value=new_value, value_data={k: v for k, v in value.items() if v is not None}, nodes=None if broadcast else list(nodes), options=options, ) if success is False: raise SetValueFailed("Unable to set value via multicast")
async def test_set_config_parameter(hass, client, hass_ws_client, multisensor_6, integration): """Test the set_config_parameter service.""" entry = integration ws_client = await hass_ws_client(hass) client.async_send_command.return_value = {"success": True} await ws_client.send_json({ ID: 1, TYPE: "zwave_js/set_config_parameter", ENTRY_ID: entry.entry_id, NODE_ID: 52, PROPERTY: 102, PROPERTY_KEY: 1, VALUE: 1, }) msg = await ws_client.receive_json() assert msg["result"] 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"] == 52 assert args["valueId"] == { "commandClassName": "Configuration", "commandClass": 112, "endpoint": 0, "property": 102, "propertyName": "Group 2: Send battery reports", "propertyKey": 1, "metadata": { "type": "number", "readable": True, "writeable": True, "valueSize": 4, "min": 0, "max": 1, "default": 1, "format": 0, "allowManualEntry": True, "label": "Group 2: Send battery reports", "description": "Include battery information in periodic reports to Group 2", "isFromConfig": True, }, "value": 0, } assert args["value"] == 1 client.async_send_command.reset_mock() with patch( "homeassistant.components.zwave_js.api.async_set_config_parameter", ) as set_param_mock: set_param_mock.side_effect = InvalidNewValue("test") await ws_client.send_json({ ID: 2, TYPE: "zwave_js/set_config_parameter", ENTRY_ID: entry.entry_id, NODE_ID: 52, PROPERTY: 102, PROPERTY_KEY: 1, VALUE: 1, }) msg = await ws_client.receive_json() assert len(client.async_send_command.call_args_list) == 0 assert not msg["success"] assert msg["error"]["code"] == "not_supported" assert msg["error"]["message"] == "test" set_param_mock.side_effect = NotFoundError("test") await ws_client.send_json({ ID: 3, TYPE: "zwave_js/set_config_parameter", ENTRY_ID: entry.entry_id, NODE_ID: 52, PROPERTY: 102, PROPERTY_KEY: 1, VALUE: 1, }) msg = await ws_client.receive_json() assert len(client.async_send_command.call_args_list) == 0 assert not msg["success"] assert msg["error"]["code"] == "not_found" assert msg["error"]["message"] == "test" set_param_mock.side_effect = SetValueFailed("test") await ws_client.send_json({ ID: 4, TYPE: "zwave_js/set_config_parameter", ENTRY_ID: entry.entry_id, NODE_ID: 52, PROPERTY: 102, PROPERTY_KEY: 1, VALUE: 1, }) msg = await ws_client.receive_json() assert len(client.async_send_command.call_args_list) == 0 assert not msg["success"] assert msg["error"]["code"] == "unknown_error" assert msg["error"]["message"] == "test"