Example #1
0
    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")
Example #2
0
    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")
Example #3
0
    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")
Example #4
0
    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"
                )
Example #5
0
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
            ],
Example #6
0
    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")
Example #7
0
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"