async def websocket_playerqueue_settings(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    mass: MusicAssistant,
) -> None:
    """Set PlayerQueue setting/preference."""
    if player_queue := mass.players.get_player_queue(msg[QUEUE_ID]):
        for key, value in msg["settings"].items():
            setattr(player_queue.settings, key, value)

        connection.send_result(
            msg[ID],
            "OK",
        )
        return
Exemple #2
0
async def websocket_check_for_config_updates(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    entry: ConfigEntry,
    client: Client,
) -> None:
    """Check for config updates."""
    config_update = await client.driver.async_check_for_config_updates()
    connection.send_result(
        msg[ID],
        {
            "update_available": config_update.update_available,
            "new_version": config_update.new_version,
        },
    )
async def websocket_add_playlist_tracks(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    mass: MusicAssistant,
) -> None:
    """Add playlist tracks command."""
    if isinstance(msg[URI], list):
        await mass.music.playlists.add_playlist_tracks(msg[ITEM_ID], msg[URI])
    else:
        await mass.music.playlists.add_playlist_track(msg[ITEM_ID], msg[URI])

    connection.send_result(
        msg[ID],
        "OK",
    )
Exemple #4
0
async def websocket_get_version(
    hass: HomeAssistant, connection: ActiveConnection, msg: dict
) -> None:
    """Handle get version command."""
    integration = await async_get_integration(hass, "frontend")

    frontend = None

    for req in integration.requirements:
        if req.startswith("home-assistant-frontend=="):
            frontend = req.split("==", 1)[1]

    if frontend is None:
        connection.send_error(msg["id"], "unknown_version", "Version not found")
    else:
        connection.send_result(msg["id"], {"version": frontend})
async def websocket_playlists(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    mass: MusicAssistant,
) -> None:
    """Return playlists."""
    result = [
        item.to_dict()
        for item in await mass.music.playlists.library(limit=msg[LIMIT],
                                                       offset=msg[OFFSET])
    ]
    connection.send_result(
        msg[ID],
        result,
    )
async def websocket_remove_playlist_tracks(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    mass: MusicAssistant,
) -> None:
    """Add playlist tracks command."""
    positions = msg[POSITION]
    if isinstance(msg[POSITION], int):
        positions = [msg[POSITION]]
    await mass.music.playlists.remove_playlist_tracks(msg[ITEM_ID], positions)

    connection.send_result(
        msg[ID],
        "OK",
    )
Exemple #7
0
async def websocket_remove_node(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    entry: ConfigEntry,
    client: Client,
) -> None:
    """Remove a node from the Z-Wave network."""
    controller = client.driver.controller

    @callback
    def async_cleanup() -> None:
        """Remove signal listeners."""
        for unsub in unsubs:
            unsub()

    @callback
    def forward_event(event: dict) -> None:
        connection.send_message(
            websocket_api.event_message(msg[ID], {"event": event["event"]}))

    @callback
    def node_removed(event: dict) -> None:
        node = event["node"]
        node_details = {
            "node_id": node.node_id,
        }

        connection.send_message(
            websocket_api.event_message(msg[ID], {
                "event": "node removed",
                "node": node_details
            }))

    connection.subscriptions[msg["id"]] = async_cleanup
    msg[DATA_UNSUBSCRIBE] = unsubs = [
        controller.on("exclusion started", forward_event),
        controller.on("exclusion failed", forward_event),
        controller.on("exclusion stopped", forward_event),
        controller.on("node removed", node_removed),
    ]

    result = await controller.async_begin_exclusion()
    connection.send_result(
        msg[ID],
        result,
    )
Exemple #8
0
async def websocket_device_cluster_commands(
    hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
) -> None:
    """Return a list of cluster commands."""
    zha_gateway: ZHAGateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY]
    ieee: EUI64 = msg[ATTR_IEEE]
    endpoint_id: int = msg[ATTR_ENDPOINT_ID]
    cluster_id: int = msg[ATTR_CLUSTER_ID]
    cluster_type: str = msg[ATTR_CLUSTER_TYPE]
    zha_device = zha_gateway.get_device(ieee)
    cluster_commands: list[dict[str, Any]] = []
    commands = None
    if zha_device is not None:
        commands = zha_device.async_get_cluster_commands(
            endpoint_id, cluster_id, cluster_type
        )

        if commands is not None:
            for cmd_id, cmd in commands[CLUSTER_COMMANDS_CLIENT].items():
                cluster_commands.append(
                    {
                        TYPE: CLIENT,
                        ID: cmd_id,
                        ATTR_NAME: cmd.name,
                    }
                )
            for cmd_id, cmd in commands[CLUSTER_COMMANDS_SERVER].items():
                cluster_commands.append(
                    {
                        TYPE: CLUSTER_COMMAND_SERVER,
                        ID: cmd_id,
                        ATTR_NAME: cmd.name,
                    }
                )
    _LOGGER.debug(
        "Requested commands for: %s: %s, %s: '%s', %s: %s, %s: %s",
        ATTR_CLUSTER_ID,
        cluster_id,
        ATTR_CLUSTER_TYPE,
        cluster_type,
        ATTR_ENDPOINT_ID,
        endpoint_id,
        RESPONSE,
        cluster_commands,
    )

    connection.send_result(msg[ID], cluster_commands)
Exemple #9
0
async def websocket_subscribe_firmware_update_status(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    node: Node,
) -> None:
    """Subsribe to the status of a firmware update."""
    @callback
    def async_cleanup() -> None:
        """Remove signal listeners."""
        for unsub in unsubs:
            unsub()

    @callback
    def forward_progress(event: dict) -> None:
        progress: FirmwareUpdateProgress = event["firmware_update_progress"]
        connection.send_message(
            websocket_api.event_message(
                msg[ID],
                {
                    "event": event["event"],
                    "sent_fragments": progress.sent_fragments,
                    "total_fragments": progress.total_fragments,
                },
            ))

    @callback
    def forward_finished(event: dict) -> None:
        finished: FirmwareUpdateFinished = event["firmware_update_finished"]
        connection.send_message(
            websocket_api.event_message(
                msg[ID],
                {
                    "event": event["event"],
                    "status": finished.status,
                    "wait_time": finished.wait_time,
                },
            ))

    unsubs = [
        node.on("firmware update progress", forward_progress),
        node.on("firmware update finished", forward_finished),
    ]
    connection.subscriptions[msg["id"]] = async_cleanup

    connection.send_result(msg[ID])
async def websocket_library_remove(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    mass: MusicAssistant,
) -> None:
    """Remove item from library."""
    item = await mass.music.get_item_by_uri(msg[URI])
    if not item:
        connection.send_error(msg[ID], ERR_NOT_FOUND, f"Item not found: {msg[URI]}")

    await mass.music.remove_from_library(item.media_type, item.item_id, item.provider)

    connection.send_result(
        msg[ID],
        "OK",
    )
Exemple #11
0
async def websocket_update_data_collection_preference(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    entry: ConfigEntry,
    client: Client,
) -> None:
    """Update preference for data collection and enable/disable collection."""
    opted_in = msg[OPTED_IN]
    update_data_collection_preference(hass, entry, opted_in)

    if opted_in:
        await async_enable_statistics(client)
    else:
        await client.driver.async_disable_statistics()

    connection.send_result(msg[ID], )
Exemple #12
0
async def websocket_version_info(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    entry: ConfigEntry,
    client: Client,
) -> None:
    """Get version info from the Z-Wave JS server."""
    version_info = {
        "driver_version": client.version.driver_version,
        "server_version": client.version.server_version,
        "min_schema_version": client.version.min_schema_version,
        "max_schema_version": client.version.max_schema_version,
    }
    connection.send_result(
        msg[ID],
        version_info,
    )
Exemple #13
0
def websocket_node_status(hass: HomeAssistant, connection: ActiveConnection,
                          msg: dict) -> None:
    """Get the status of a Z-Wave JS node."""
    entry_id = msg[ENTRY_ID]
    client = hass.data[DOMAIN][entry_id][DATA_CLIENT]
    node_id = msg[NODE_ID]
    node = client.driver.controller.nodes[node_id]
    data = {
        "node_id": node.node_id,
        "is_routing": node.is_routing,
        "status": node.status,
        "is_secure": node.is_secure,
        "ready": node.ready,
    }
    connection.send_result(
        msg[ID],
        data,
    )
Exemple #14
0
async def websocket_node_status(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    node: Node,
) -> None:
    """Get the status of a Z-Wave JS node."""
    data = {
        "node_id": node.node_id,
        "is_routing": node.is_routing,
        "status": node.status,
        "is_secure": node.is_secure,
        "ready": node.ready,
    }
    connection.send_result(
        msg[ID],
        data,
    )
async def websocket_playerqueue(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    mass: MusicAssistant,
) -> None:
    """Return single player queue details by id."""
    item = mass.players.get_player_queue(msg[QUEUE_ID])
    if item is None:
        connection.send_error(msg[ID], ERR_NOT_FOUND,
                              f"Queue not found: {msg[QUEUE_ID]}")
        return
    result = item.to_dict()

    connection.send_result(
        msg[ID],
        result,
    )
Exemple #16
0
async def websocket_refresh_node_cc_values(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    node: Node,
) -> None:
    """Refresh node values for a particular CommandClass."""
    command_class_id = msg[COMMAND_CLASS_ID]

    try:
        command_class = CommandClass(command_class_id)
    except ValueError:
        connection.send_error(msg[ID], ERR_NOT_FOUND,
                              f"Command class {command_class_id} not found")
        return

    await node.async_refresh_cc_values(command_class)
    connection.send_result(msg[ID])
Exemple #17
0
async def websocket_network_status(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    entry: ConfigEntry,
    client: Client,
) -> None:
    """Get the status of the Z-Wave JS network."""
    controller = client.driver.controller
    data = {
        "client": {
            "ws_server_url": client.ws_server_url,
            "state": "connected" if client.connected else "disconnected",
            "driver_version": client.version.driver_version,
            "server_version": client.version.server_version,
        },
        "controller": {
            "home_id": controller.home_id,
            "library_version": controller.library_version,
            "type": controller.controller_type,
            "own_node_id": controller.own_node_id,
            "is_secondary": controller.is_secondary,
            "is_using_home_id_from_other_network":
            controller.is_using_home_id_from_other_network,
            "is_sis_present": controller.is_SIS_present,
            "was_real_primary": controller.was_real_primary,
            "is_static_update_controller":
            controller.is_static_update_controller,
            "is_slave": controller.is_slave,
            "serial_api_version": controller.serial_api_version,
            "manufacturer_id": controller.manufacturer_id,
            "product_id": controller.product_id,
            "product_type": controller.product_type,
            "supported_function_types": controller.supported_function_types,
            "suc_node_id": controller.suc_node_id,
            "supports_timers": controller.supports_timers,
            "is_heal_network_active": controller.is_heal_network_active,
            "nodes": list(client.driver.controller.nodes),
        },
    }
    connection.send_result(
        msg[ID],
        data,
    )
Exemple #18
0
async def websocket_update_zha_configuration(hass: HomeAssistant,
                                             connection: ActiveConnection,
                                             msg: dict[str, Any]) -> None:
    """Update the ZHA configuration."""
    zha_gateway: ZHAGateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY]
    options = zha_gateway.config_entry.options
    data_to_save = {**options, **{CUSTOM_CONFIGURATION: msg["data"]}}

    _LOGGER.info(
        "Updating ZHA custom configuration options from %s to %s",
        options,
        data_to_save,
    )

    hass.config_entries.async_update_entry(zha_gateway.config_entry,
                                           options=data_to_save)
    status = await hass.config_entries.async_reload(
        zha_gateway.config_entry.entry_id)
    connection.send_result(msg[ID], status)
Exemple #19
0
async def websocket_read_zigbee_cluster_attributes(
        hass: HomeAssistant, connection: ActiveConnection,
        msg: dict[str, Any]) -> None:
    """Read zigbee attribute for cluster on zha entity."""
    zha_gateway: ZHAGateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY]
    ieee: EUI64 = msg[ATTR_IEEE]
    endpoint_id: int = msg[ATTR_ENDPOINT_ID]
    cluster_id: int = msg[ATTR_CLUSTER_ID]
    cluster_type: str = msg[ATTR_CLUSTER_TYPE]
    attribute: int = msg[ATTR_ATTRIBUTE]
    manufacturer: int | None = msg.get(ATTR_MANUFACTURER)
    zha_device = zha_gateway.get_device(ieee)
    success = {}
    failure = {}
    if zha_device is not None:
        if cluster_id >= MFG_CLUSTER_ID_START and manufacturer is None:
            manufacturer = zha_device.manufacturer_code
        cluster = zha_device.async_get_cluster(endpoint_id,
                                               cluster_id,
                                               cluster_type=cluster_type)
        success, failure = await cluster.read_attributes(
            [attribute],
            allow_cache=False,
            only_cache=False,
            manufacturer=manufacturer)
    _LOGGER.debug(
        "Read attribute for: %s: [%s] %s: [%s] %s: [%s] %s: [%s] %s: [%s] %s: [%s] %s: [%s],",
        ATTR_CLUSTER_ID,
        cluster_id,
        ATTR_CLUSTER_TYPE,
        cluster_type,
        ATTR_ENDPOINT_ID,
        endpoint_id,
        ATTR_ATTRIBUTE,
        attribute,
        ATTR_MANUFACTURER,
        manufacturer,
        RESPONSE,
        str(success.get(attribute)),
        "failure",
        failure,
    )
    connection.send_result(msg[ID], str(success.get(attribute)))
Exemple #20
0
def websocket_get_config_parameters(hass: HomeAssistant,
                                    connection: ActiveConnection,
                                    msg: dict) -> None:
    """Get a list of configuration parameters for a Z-Wave node."""
    entry_id = msg[ENTRY_ID]
    node_id = msg[NODE_ID]
    client = hass.data[DOMAIN][entry_id][DATA_CLIENT]
    node = client.driver.controller.nodes.get(node_id)

    if node is None:
        connection.send_error(msg[ID], ERR_NOT_FOUND,
                              f"Node {node_id} not found")
        return

    values = node.get_configuration_values()
    result = {}
    for value_id, zwave_value in values.items():
        metadata = zwave_value.metadata
        result[value_id] = {
            "property": zwave_value.property_,
            "property_key": zwave_value.property_key,
            "configuration_value_type":
            zwave_value.configuration_value_type.value,
            "metadata": {
                "description": metadata.description,
                "label": metadata.label,
                "type": metadata.type,
                "min": metadata.min,
                "max": metadata.max,
                "unit": metadata.unit,
                "writeable": metadata.writeable,
                "readable": metadata.readable,
            },
            "value": zwave_value.value,
        }
        if zwave_value.metadata.states:
            result[value_id]["metadata"][
                "states"] = zwave_value.metadata.states

    connection.send_result(
        msg[ID],
        result,
    )
Exemple #21
0
async def websocket_permit_devices(hass: HomeAssistant,
                                   connection: ActiveConnection,
                                   msg: dict[str, Any]) -> None:
    """Permit ZHA zigbee devices."""
    zha_gateway: ZHAGateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY]
    duration: int = msg[ATTR_DURATION]
    ieee: EUI64 | None = msg.get(ATTR_IEEE)

    async def forward_messages(data):
        """Forward events to websocket."""
        connection.send_message(websocket_api.event_message(msg["id"], data))

    remove_dispatcher_function = async_dispatcher_connect(
        hass, "zha_gateway_message", forward_messages)

    @callback
    def async_cleanup() -> None:
        """Remove signal listener and turn off debug mode."""
        zha_gateway.async_disable_debug_mode()
        remove_dispatcher_function()

    connection.subscriptions[msg["id"]] = async_cleanup
    zha_gateway.async_enable_debug_mode()
    src_ieee: EUI64
    code: bytes
    if ATTR_SOURCE_IEEE in msg:
        src_ieee = msg[ATTR_SOURCE_IEEE]
        code = msg[ATTR_INSTALL_CODE]
        _LOGGER.debug("Allowing join for %s device with install code",
                      src_ieee)
        await zha_gateway.application_controller.permit_with_key(
            time_s=duration, node=src_ieee, code=code)
    elif ATTR_QR_CODE in msg:
        src_ieee, code = msg[ATTR_QR_CODE]
        _LOGGER.debug("Allowing join for %s device with install code",
                      src_ieee)
        await zha_gateway.application_controller.permit_with_key(
            time_s=duration, node=src_ieee, code=code)
    else:
        await zha_gateway.application_controller.permit(time_s=duration,
                                                        node=ieee)
    connection.send_result(msg["id"])
Exemple #22
0
async def websocket_node_metadata(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    node: Node,
) -> None:
    """Get the metadata of a Z-Wave JS node."""
    data = {
        "node_id": node.node_id,
        "exclusion": node.device_config.metadata.exclusion,
        "inclusion": node.device_config.metadata.inclusion,
        "manual": node.device_config.metadata.manual,
        "wakeup": node.device_config.metadata.wakeup,
        "reset": node.device_config.metadata.reset,
        "device_database_url": node.device_database_url,
    }
    connection.send_result(
        msg[ID],
        data,
    )
Exemple #23
0
async def websocket_supervisor_api(
    hass: HomeAssistant, connection: ActiveConnection, msg: dict
):
    """Websocket handler to call Supervisor API."""
    supervisor: HassIO = hass.data[DOMAIN]
    result = False
    try:
        result = await supervisor.send_command(
            msg[ATTR_ENDPOINT],
            method=msg[ATTR_METHOD],
            timeout=msg.get(ATTR_TIMEOUT, 10),
            payload=msg.get(ATTR_DATA, {}),
        )
    except hass.components.hassio.HassioAPIError as err:
        _LOGGER.error("Failed to to call %s - %s", msg[ATTR_ENDPOINT], err)
        connection.send_error(
            msg[WS_ID], code=websocket_api.ERR_UNKNOWN_ERROR, message=str(err)
        )
    else:
        connection.send_result(msg[WS_ID], result.get(ATTR_DATA, {}))
Exemple #24
0
def websocket_network_status(hass: HomeAssistant, connection: ActiveConnection,
                             msg: dict) -> None:
    """Get the status of the Z-Wave JS network."""
    entry_id = msg[ENTRY_ID]
    client = hass.data[DOMAIN][entry_id][DATA_CLIENT]
    data = {
        "client": {
            "ws_server_url": client.ws_server_url,
            "state": "connected" if client.connected else "disconnected",
            "driver_version": client.version.driver_version,
            "server_version": client.version.server_version,
        },
        "controller": {
            "home_id": client.driver.controller.data["homeId"],
            "nodes": list(client.driver.controller.nodes),
        },
    }
    connection.send_result(
        msg[ID],
        data,
    )
async def websocket_playlist(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    mass: MusicAssistant,
) -> None:
    """Return track."""
    item = await mass.music.playlists.get(
        msg[ITEM_ID], msg[PROVIDER], lazy=msg[LAZY], force_refresh=msg[REFRESH]
    )
    if item is None:
        connection.send_error(
            msg[ID],
            ERR_NOT_FOUND,
            f"playlist not found: {msg[PROVIDER]}/{msg[ITEM_ID]}",
        )
        return
    connection.send_result(
        msg[ID],
        item.to_dict(),
    )
async def websocket_stats(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    mass: MusicAssistant,
) -> None:
    """Return some statistics and generic info."""
    result = {
        "providers": {x.id: x.to_dict()
                      for x in mass.music.providers},
        "count": {
            "artists": await mass.music.artists.count(),
            "albums": await mass.music.albums.count(),
            "tracks": await mass.music.tracks.count(),
            "playlists": await mass.music.playlists.count(),
            "radios": await mass.music.radio.count(),
        },
    }
    connection.send_result(
        msg[ID],
        result,
    )
Exemple #27
0
async def websocket_subscribe_controller_statistics(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    entry: ConfigEntry,
    client: Client,
) -> None:
    """Subsribe to the statistics updates for a controller."""

    @callback
    def async_cleanup() -> None:
        """Remove signal listeners."""
        for unsub in unsubs:
            unsub()

    @callback
    def forward_stats(event: dict) -> None:
        statistics: ControllerStatistics = event["statistics_updated"]
        connection.send_message(
            websocket_api.event_message(
                msg[ID],
                {
                    "event": event["event"],
                    "source": "controller",
                    **_get_controller_statistics_dict(statistics),
                },
            )
        )

    controller = client.driver.controller

    msg[DATA_UNSUBSCRIBE] = unsubs = [
        controller.on("statistics updated", forward_stats)
    ]
    connection.subscriptions[msg["id"]] = async_cleanup

    connection.send_result(
        msg[ID], _get_controller_statistics_dict(controller.statistics)
    )
Exemple #28
0
async def websocket_refresh_node_info(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    node: Node,
) -> None:
    """Re-interview a node."""

    @callback
    def async_cleanup() -> None:
        """Remove signal listeners."""
        for unsub in unsubs:
            unsub()

    @callback
    def forward_event(event: dict) -> None:
        connection.send_message(
            websocket_api.event_message(msg[ID], {"event": event["event"]})
        )

    @callback
    def forward_stage(event: dict) -> None:
        connection.send_message(
            websocket_api.event_message(
                msg[ID], {"event": event["event"], "stage": event["stageName"]}
            )
        )

    connection.subscriptions[msg["id"]] = async_cleanup
    msg[DATA_UNSUBSCRIBE] = unsubs = [
        node.on("interview started", forward_event),
        node.on("interview completed", forward_event),
        node.on("interview stage completed", forward_stage),
        node.on("interview failed", forward_event),
    ]

    result = await node.async_refresh_info()
    connection.send_result(msg[ID], result)
Exemple #29
0
async def websocket_remove_failed_node(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    entry: ConfigEntry,
    client: Client,
) -> None:
    """Remove a failed node from the Z-Wave network."""
    controller = client.driver.controller
    node_id = msg[NODE_ID]

    @callback
    def async_cleanup() -> None:
        """Remove signal listeners."""
        unsub()

    @callback
    def node_removed(event: dict) -> None:
        node = event["node"]
        node_details = {
            "node_id": node.node_id,
        }

        connection.send_message(
            websocket_api.event_message(msg[ID], {
                "event": "node removed",
                "node": node_details
            }))

    connection.subscriptions[msg["id"]] = async_cleanup
    unsub = controller.on("node removed", node_removed)

    result = await controller.async_remove_failed_node(node_id)
    connection.send_result(
        msg[ID],
        result,
    )
Exemple #30
0
async def websocket_set_config_parameter(
    hass: HomeAssistant,
    connection: ActiveConnection,
    msg: dict,
    node: Node,
) -> None:
    """Set a config parameter value for a Z-Wave node."""
    property_ = msg[PROPERTY]
    property_key = msg.get(PROPERTY_KEY)
    value = msg[VALUE]

    try:
        zwave_value, cmd_status = await async_set_config_parameter(
            node, value, property_, property_key=property_key)
    except (InvalidNewValue, NotFoundError, NotImplementedError,
            SetValueFailed) as err:
        code = ERR_UNKNOWN_ERROR
        if isinstance(err, NotFoundError):
            code = ERR_NOT_FOUND
        elif isinstance(err, (InvalidNewValue, NotImplementedError)):
            code = ERR_NOT_SUPPORTED

        connection.send_error(
            msg[ID],
            code,
            str(err),
        )
        return

    connection.send_result(
        msg[ID],
        {
            VALUE_ID: zwave_value.value_id,
            STATUS: cmd_status,
        },
    )