Z-Wave JS Server

repository·master·Indexed 41 days ago

https://github.com/zwave-js/zwave-js-server

A lightweight wrapper that exposes Z-Wave JS driver functionality over a WebSocket API, enabling remote access and integration. It provides a standardized messaging protocol for managing Z-Wave controllers and nodes, including support for firmware updates (OTW), NVM operations, and real-time event listening. Version 3.10.2.

Tokens
25.7K
Snippets
80
Records
120
Agent score
51%

What's inside Z-Wave JS Server

  1. Overview of Z-Wave JS Server

    master
    Z-Wave JS Server is a small server wrapper around Z-Wave JS that allows you to access Z-Wave functionality via a WebSocket interface. It is designed to bridge the Z-Wave JS driver to external clients using a standardized messaging protocol.
  2. Unified Credential Management API

    master

    Exposes the unified credential management API from Z-Wave JS under the endpoint.access_control.* namespace. This is compatible with schema version 48+.

    Workflow: Before using credential commands, applications should check if the endpoint supports the unified access control API using endpoint.access_control.is_supported. The response contains a supported: boolean field.

    Supported Commands:

    • endpoint.access_control.is_supported (Check support)
    • endpoint.access_control.get_user_capabilities_cached / get_credential_capabilities_cached (Get capabilities)
    • endpoint.access_control.get_user / get_user_cached / get_users / get_users_cached (Get users)
    • endpoint.access_control.set_user / delete_user / delete_all_users (Manage users)
    • endpoint.access_control.get_credential / get_credential_cached / get_credentials / get_credentials_cached / get_credentials_by_type / get_credentials_by_type_cached / get_all_credentials / get_all_credentials_cached (Get credentials)
    • endpoint.access_control.assign_credential (Reassign credential)
    • endpoint.access_control.set_credential / delete_credential (Manage credentials)
    • endpoint.access_control.start_credential_learn / cancel_credential_learn (Credential learning)
    • endpoint.access_control.get_admin_code / set_admin_code (Admin code management)

    Mutating Command Results: Mutating commands return a result field with specific enum values:

    • set_user, delete_user, delete_all_users $\rightarrow$ SetUserResult
    • set_credential, delete_credential $\rightarrow$ SetCredentialResult
    • assign_credential $\rightarrow$ AssignCredentialResult

    Examples:

    Set a credential:

    {
      "messageId": "string",
      "command": "endpoint.access_control.set_credential",
      "nodeId": number,
      "endpoint": number,
      "userId": number,
      "credentialType": number,
      "credentialSlot": number,
      "data": "string" | { "type": "Buffer", "data": number[] }
    }

    Create or modify a user:

    {
      "messageId": "string",
      "command": "endpoint.access_control.set_user",
      "nodeId": number,
      "endpoint": number,
      "userId": number,
      "options": {
        "active": boolean,
        "userType": number,
        "userName": "string",
        "credentialRule": number,
        "expiringTimeoutMinutes": number
      }
    }
  3. How Multicasting works in Z-Wave JS Server

    master

    Multicasting allows you to send commands to multiple nodes simultaneously. The command prefix determines the scope:

    1. Broadcast to all nodes: Use the broadcast_node prefix.
    2. Multicast to a subset of nodes: Use the multicast_group prefix and provide a nodeIDs array as an input parameter.

    For broadcast_node commands, you can include a longRange boolean flag to target Long Range nodes instead of classic Z-Wave nodes.

    // Example: Multicasting a set_value command to a group of nodes
    {
      "messageId": "string",
      "command": "multicast_group.set_value",
      "nodeIDs": [1, 2, 3],
      "valueId": {
        "commandClass": "COMMAND_CLASS_SWITCH_BINARY",
        "endpoint": 0,
        "property": "switch"
      },
      "value": true
    }
  4. Handle Z-Wave Specific Errors

    master

    If the error code is zwave_error, the response includes additional context from the Z-Wave JS driver via the zwaveErrorCode and zwaveErrorMessage keys.

    {
      "type": "result",
      "success": false,
      "messageId": 1,
      "errorCode": "zwave_error",
      "zwaveErrorCode": 18,
      "zwaveErrorMessage": "The message cannot be sent because node 61 is dead"
    }
  5. Listen to forwarded `zwave-js` events

    master

    The Z-Wave JS Server forwards all standard zwave-js events to clients that have issued the start_listening command. These events include updates from the driver, controller, node, or zniffer sources.

    interface {
      type: "event";
      event: {
        source: "driver" | "controller" | "node" | "zniffer";
        event: string;
        ... // Additional parameters dependent on the event
      }
    }
  6. Understand Z-Wave JS Server API Schema versions

    master

    The Z-Wave JS Server API evolves through versioned schemas. Each schema version introduces new commands, state properties, or changes to existing data structures. When integrating with the server, you should be aware of the schema version being used to ensure compatibility with the available commands and the shape of the state dumps.

    Key types of changes include:

    • New Commands: Addition of namespaces like driver.*, controller.*, node.*, or endpoint.*.
    • State Changes: New properties added to NodeState, ControllerState, or Endpoint state dumps.
    • Event Changes: New controller or node events (e.g., statistics updated, interview started).
    • Breaking Changes: Renaming of properties (e.g., version to protocolVersion) or changes in parameter types/return shapes.

    Refer to the specific schema version documentation to map your client logic to the server's capabilities.

  7. How Z-Wave JS Server handles controller command callbacks

    master

    Because callbacks cannot be passed over a WebSocket connection, the Z-Wave JS Server automatically converts several controller methods that typically accept callback parameters into an event-driven model. Instead of providing a callback function in the command payload, the server emits specific events to the client to signal progress or required user interaction.

    Key conversions include:

    • Inclusion/Joining: For controller.begin_inclusion, controller.replace_failed_node, and controller.begin_joining_network, the server handles userCallbacks (like S2 security bootstrapping) and emits events such as grant security classes, validate dsk and enter pin, inclusion aborted, joining network show dsk, or joining network done.
    • NVM Operations: controller.backup_nvm_raw reports progress via nvm backup progress events. controller.restore_nvm and controller.restore_nvm_raw use nvm convert progress and nvm restore progress events.
    • Firmware Updates: controller.firmware_update_otw accepts a base64 encoded file and a filename.
    • NVM Buffers: Commands like controller.external_nvm_read_buffer return NVM data as a base64 encoded string in the buffer field. For writes, the buffer input must be a base64 encoded string.
  8. Understand the Z-Wave JS Server Connection Lifecycle

    master

    When a client connects to the server, the following lifecycle occurs:

    1. Version Handshake: The server immediately sends a version message containing driverVersion, serverVersion, homeId, and schema version ranges (minSchemaVersion, maxSchemaVersion).
    2. Driver Readiness: If the driver is not yet ready, the server closes the connection with error code 1013 (Try Again Later). Clients should implement a retry mechanism.
    3. Initialization: The client should send an initialize command to specify its supported schemaVersion and optional additionalUserAgentComponents.
    4. Listening: The client sends a start_listening command to receive the current state and subsequent events.

    Data Formats

    Version Message (Server -> Client):

    {
      type: "version",
      driverVersion: string,
      serverVersion: string,
      homeId: number | undefined,
      minSchemaVersion: number,
      maxSchemaVersion: number
    }

    Initialize Command (Client -> Server):

    {
      messageId: string,
      command: "initialize",
      schemaVersion: number,
      additionalUserAgentComponents?: Record<string, string>
    }

    Start Listening Command (Client -> Server):

    {
      messageId: string,
      command: "start_listening"
    }

    State Result (Server -> Client):

    {
      type: "result",
      messageId: string, // maps to the start_listening command
      success: true,
      result: {
        state: {
          driver: Partial<DriverState>;
          controller: Partial<ZWaveController>;
          nodes: Partial<ZWaveNode>[];
        }
      }
    }
  9. Access Controller level commands

    master

    The zwave-js-server supports all controller methods defined in the official Z-Wave JS documentation.

    Important Mapping Rule: To use a controller method via the server, you must:

    1. Prefix the method with controller.
    2. Convert the method name from camelCase to snake_case.

    Example: The Z-Wave JS method beginInclusion is invoked via the server using the command controller.begin_inclusion.

  10. Access Utility and Config Manager commands

    master

    The server exposes Z-Wave JS utility and configuration manager methods using a specific naming convention:

    • Snake Casing: All commands use snake_case instead of camelCase.
    • Prefixing: Controller-level commands are prefixed with their category.

    Examples:

    • parseQRCodeString becomes utils.parse_qr_code_string.
    • lookupDevice becomes config_manager.lookup_device.

    Note: String utilities like num2hex are available but should be implemented locally rather than over WebSocket for performance.

  11. Manage API Schema Versions

    master

    Z-Wave JS Server uses an API Schema Versioning system to maintain compatibility between different server and client versions.

    When a client connects, the server sends a version message containing minSchemaVersion and maxSchemaVersion. The client should then use the set_api_schema command to tell the server which schema version it intends to use.

    Key behaviors:

    • Default Behavior: If the client does not send set_api_schema, the server defaults to the minimum supported schema (currently 0).
    • Multi-client Support: The server can handle multiple clients simultaneously, even if they are using different schema versions.
    • Breaking Changes: When breaking changes are introduced to the API, the schema version is bumped. New features will also bump the schema version.
    • Out of Range: If a client requests a version outside the server's supported range, the server returns a schema_incompatible error.
    // 1. Server sends version info upon connection
    {
      "type": "version",
      "driverVersion": "6.5.0",
      "serverVersion": "1.0.0",
      "homeId": 3967882672,
      "minSchemaVersion": 0,
      "maxSchemaVersion": 1
    }
    
    // 2. Client sets the desired schema version
    {
      "command": "set_api_schema",
      "messageId": 1,
      "schemaVersion": 1
    }
  12. Start the Z-Wave JS Server

    master

    To start the server, you can use the zwave-server CLI (or tsx src/bin/server.ts during development). You must provide a path to a Z-Wave controller device (e.g., /dev/tty0).

    Configuration Options

    • --config <path>: Specify a JSON or JS file following the Z-Wave JS config format. Note: emitValueUpdateAfterSetValue defaults to true unless specified otherwise.
    • --port <number>: Set the WebSocket server port (default is 3000).
    • --host <address>: Set the interface to attach to (default is 0.0.0.0).
    • --mock-driver: Use a fake Z-Wave stick if no USB hardware is available.
    • --disable-dns-sd: Disable DNS-SD (enabled by default).
    • --reconnect: Enable automatic reconnection.

    For development purposes, use:

    tsx src/bin/server.ts /dev/tty0