Git Product home page Git Product logo

zwave-js-server-docker's Introduction

zwave-js-server-docker

A minimal docker container for Z-Wave JS Server. This container provides a usable Z-Wave JS Server and little else.

For a more functional application that also provides the Server, use Z-Wave JS UI instead.

Docker Configuration

The Z-Wave JS driver stores information about the Z-Wave network in a set of cache files. When the server restarts, the driver loads the network information from the cache. Without this information the network will not be fully usable right away. Therefore it is very important that the cache files are persisted between container restarts.

The docker run examples below use an environment file to provide all of the Z-Wave network keys.

$ cat .env
S2_ACCESS_CONTROL_KEY=7764841BC794A54442E324682A550CEF
S2_AUTHENTICATED_KEY=66EA86F088FFD6D7497E0B32BC0C8B99
S2_UNAUTHENTICATED_KEY=2FAB1A27E19AE9C7CC6D18ACEB90C357
S0_LEGACY_KEY=17DFB0C1BED4CABFF54E4B5375E257B3
LR_S2_ACCESS_CONTROL_KEY=61BEF779F9DF0827CD9870B719D074BB
LR_S2_AUTHENTICATED_KEY=905B869063266296AE5159EEDBEE038D
RF_REGION=USA (Long Range)

Run with a volume mount

# Create a persistent volume for the driver cache
$ docker volume create zjs-storage

# starts the server and uses the volume as the persistent cache directory
$ docker run -d -p 3000:3000 --name=zjs -v zjs-storage:/cache --env-file=.env --device "/dev/serial/by-id/usb-0658_0200-if00:/dev/zwave" ghcr.io/kpine/zwave-js-server:latest

Run with a bind mount

# starts the server and uses a local folder as the persisent cache directory
$ docker run -d -p 3000:3000 --name=zjs -v "$PWD/cache:/cache" --env-file=.env --device "/dev/serial/by-id/usb-0658_0200-if00:/dev/zwave" ghcr.io/kpine/zwave-js-server:latest

Docker Compose

Docker Compose is a simple way to maintain a container configuration.

Example of a minimal docker-compose.yaml file:

services:
  zjs:
    container_name: zjs
    image: ghcr.io/kpine/zwave-js-server:latest
    restart: unless-stopped
    environment:
      - "S2_ACCESS_CONTROL_KEY=7764841BC794A54442E324682A550CEF"
      - "S2_AUTHENTICATED_KEY=66EA86F088FFD6D7497E0B32BC0C8B99"
      - "S2_UNAUTHENTICATED_KEY=2FAB1A27E19AE9C7CC6D18ACEB90C357"
      - "S0_LEGACY_KEY=17DFB0C1BED4CABFF54E4B5375E257B3"
      - "LR_S2_ACCESS_CONTROL_KEY=61BEF779F9DF0827CD9870B719D074BB"
      - "LR_S2_AUTHENTICATED_KEY=905B869063266296AE5159EEDBEE038D"
      - "RF_REGION=USA (Long Range)"
    devices:
      - "/dev/serial/by-id/usb-0658_0200-if00:/dev/zwave"
    volumes:
      - ./cache:/cache
    ports:
      - "3000:3000"

Environment variables

  • LOGTOFILE: Set this to true to configure the driver to log to a file.
  • LOGFILENAME: Set this to configure the driver log filename (only used when LOGTOFILE is true). The default is /logs/zwavejs, which results in files named zwavejs_%DATE%.log. Note that the driver will automatically rotate the log files using the date based scheme.
  • LOGMAXFILES: Set this to configure the maximum number of log files to keep. Z-Wave JS rotates log files once a day, so this corresponds to the number of days of log files to keep.
  • LOGLEVEL: Set this to configure the driver log level.
  • S2_ACCESS_CONTROL_KEY: The network key for the S2 Access Control security class.
  • S2_AUTHENTICATED_KEY: The network key for the S2 Authenticated security class.
  • S2_UNAUTHENTICATED_KEY: The network key for the S2 Unauthenticated security class.
  • S0_LEGACY_KEY: The network key for the S0 (Legacy) security class.
  • LR_S2_ACCESS_CONTROL_KEY: The network key for the Long Range S2 Access Control security class.
  • LR_S2_AUTHENTICATED_KEY: The network key for the Long Range S2 Authenticated security class.
  • RF_REGION: The RF region the radio should be tuned to. If set, the driver will ensure the region is set to the specified value. The default is unset, which means the controller will keep its current region setting.
  • USB_PATH: The device path of the Z-Wave USB controller. Defaults to /dev/zwave. Use of this variable is unnecessary if the controller device path is mapped from the host as /dev/zwave.
  • FIRMWARE_UPDATE_API_KEY: The API key used to access the Z-Wave JS Firmware Update Service. By default, no key is configured. Usually it is not necessary to configure this, unless you are a commercial user. See the Firmware Update API Key section for details.
  • ENABLE_DNS_SD: Set this to true to enable DNS Service Discovery. The default is disabled. Enabling this only works if you are using host networking.

Directories

  • /cache - The driver cache directory. A volume or bind mount should be mapped to this directory to persist the network information between container restarts.
  • /cache/config - The driver device configuration priority directory. Used to load your custom device configuration files. The directory is automatically created if /cache is a named volume, otherwise it must be created manually or mapped as a volume/bind mount.
  • /logs - When logging to file is enabled, this is the directory where the driver log file is written to. Assign a volume or bind mount to this directory to access and save the log files outside of the container.

Ports

  • 3000 - The zwave-js-server websocket port. External applications, such as Home Assistant, must be able to connect to this port to interact with the server.

Details

Network Keys

All network keys must specified as 16-byte hexadecimal strings (32 characters). A simple way to generate a random network key is with the following command:

$ < /dev/urandom tr -dc A-F0-9 | head -c32 ; echo
8387D66323E8209C58B0C317FD1F4251

All keys should be unique; sharing keys between multiple security classes is a security risk. See the Z-Wave JS Key management docs for further details.

At a minimum, the S0 (Legacy) network key is required, otherwise the zwave-js-server will fail to start. The S2 keys are optional but highly recommended. If unspecified, S2 inclusion will not be available.

USB Path

Instead of using the USB_PATH environment variable, map the USB controller device path to the container's default of /dev/zwave.

Controller Firmware Updates (OTW)

The @zwave-js/flash command line utility is included in the Docker image to support Over-The-Wire (OTW) firmware updates of controllers. Download the appropriate firmware file for your controller and issue the flash command. Be sure to stop any running Z-Wave JS server before doing so.

docker run --rm -it -v "$PWD/fw:/fw" --device "/dev/ttyUSB0:/dev/zwave" ghcr.io/kpine/zwave-js-server:latest flash /fw/fw.gbl

The command expects the device path to be /dev/zwave by default, or whatever environment variable USB_PATH is set to.

See the wiki page for more information.

User Device Configuration Files

Use the /cache/config directory to easily test new device configuration files or modifications to existing ones. The files located in this directory will supplement or override the embedded device configuration database. When the container is restarted the driver logs will indicate which file was loaded:

2021-06-19T06:19:18.506Z CNTRLR   [Node 007] Embedded device config loaded
2021-06-19T06:21:43.793Z CNTRLR   [Node 008] User-provided device config loaded

Serial Soft-Reset

Z-Wave JS performs a soft-reset (restart) of the Z-Wave controller during startup, and during certain operations such as NVM backups and restores. The soft-reset can result in a USB disconnect for some Z-Wave controllers, which may cause problems with certain container runtimes or host configurations. If you observe that Z-Wave JS has trouble finding the USB device, you may try opting out of this functionality by setting the ZWAVEJS_DISABLE_SOFT_RESET environment variable, or setting the softReset driver feature option to false. For more details, see the softReset and ZWaveOptions documentation.

If you continue to have issues even after disabling soft-reset, you may also need to disable the unresponsive controller recovery feature. You can opt out of this functionality by setting the ZWAVEJS_DISABLE_UNRESPONSIVE_CONTROLLER_RECOVERY environment variable, or setting the unresponsiveControllerRecovery driver feature option to false. For more details, see the ZWaveOptions documentation.

Cache Lock Files

Z-Wave JS uses directories as lock files to prevent the cache files from being modified by multiple concurrent processes; this helps prevent against cache corruption. These directories are located in the cache directory, next to the actual cache files. The locking technique updates the mtime (Modified time) of the lock file every ~1 second. If your storage media is sensitive to frequent writes, such as an SD card, you may want to relocate the lock files to another directory, such as a tmpfs. To relocate the cache files, set the ZWAVEJS_LOCK_DIRECTORY environment variable to an alternate path, preferably some kind of tmpfs on the host. Here is an extract of a compose file:

services:
  zjs:
    environment:
      ZWAVEJS_LOCK_DIRECTORY: "/run/lock/zwave-js"
    volumes:
      - /run/lock/zwave-js:/run/lock/zwave-js

The environment variable tells Z-Wave JS to store the lock files in the directory /run/lock/zwave-js. The volume entry maps the hosts /run/lock/zwave-js directory, which is a tmpfs, to the container directory with the same name. The end result is that the lock files created in the container are located in the tmpfs of the host. The path /run/lock is usually mounted as a tmpfs. Another candidate might be /tmp/zwave-js.

Note that locating the locks in a central place on the host ensures that multiple containers with the same configuration will be aware of the locks. However, if Z-Wave JS is run in another instance without the same lock directory configuration, it will not see the locks and this will bypass the lock protections, allowing for the chance that the cache will be corrupted. When the locks are located in the default location, all instances of Z-Wave JS using the default configuration will see the locks. So use this feature with care.

Firmware Update API Key

Z-Wave JS has an online web service that provides information about firmware updates for your devices. Use of this service requires an API key. The Z-Wave JS organization has provided this project with its own key. This key is only valid when used for non-commercial purposes, and is not permitted for commercial usage. If you are a commercial organization using this application, you must request and configure your own key.

If you are using the Z-Wave integration with Home Assistant, you do not need to enable or install an API key. The integration provides the key when accessing the firmware update APIs. This is true for any client application that makes use of the firmware update APIs with its own keys.

If you use a client that does not support its own API key, and you are a non-commercial user, you can enable the built-in key by setting the FIRMWARE_UPDATE_API_KEY to -. By doing so you agree that you are not a commercial user.

If you have your own key, i.e. you are a commercial user, you can set FIRMWARE_UPDATE_API_KEY to that key.

If the FIRMWARE_UPDATE_API_KEY environment variable is empty (the default), no API key will be configured. In that case a client application would be responsible for setting it, otherwise the firmware update service may not be functional or incur more restrictive rate-limiting.

zwave-js-server-docker's People

Contributors

kpine avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zwave-js-server-docker's Issues

Question for @kpine re Locks not reporting status after autolocking ????

I am going crazy as a noob on Z-Wave trying to get my locks to talk to HA.
Do i need to post a question in GitHub i have tried online here
The post shows images and the main issue
I have spoken to Daniel Lando who pointed me in the direction of @kpine.
Daniel
"I can see in your z-ui screenshot it means there is some issue on hass integration side or a device configuration issue. Try asking to @kpine he usually know how to fix such things on HA side :) Hope this helps"

Sorry to bother you but my logs look fine just need to know how to get the entities updated correctly.
I have no doubt i am doing something wrong just looking to get some help please

Some strange issue with starting Docker

I try from inside of docker and with docker run but always same effect:

zwave-server --config options.js  /dev/zwave


#
# Fatal error in , line 0
# unreachable code
#
#
#
#FailureMessage Object: 0x7eedd15c
Illegal instruction (core dumped)

options.js

module.exports = {
  logConfig: {
    filename: process.env.LOGFILENAME,
  },

  storage: {
    cacheDir: "/cache",
  },

  networkKey: process.env.NETWORK_KEY,
};

env variablees

echo $NETWORK_KEY
94949494949494949494949494949494
echo $LOGFILENAME
/logs/zwave.log

directories exist

 ls -la /cache/
total 8
drwxr-xr-x    2 root     root          4096 Mar  3  2021 .
drwxr-xr-x    1 root     root          4096 Mar 27  2021 ..
/app # ls -la /logs/
total 8
drwxr-xr-x    2 root     root          4096 Mar  3  2021 .
drwxr-xr-x    1 root     root          4096 Mar 27  2021 ..

Also /dev/zwave llinked

ls -la /dev/zwave
crw-rw----    1 root     dialout   166,   0 Mar 27  2021 /dev/zwave

Anything that can help me debug this ??

WARNING (MainThread) [homeassistant.config_entries] Config entry 'Z-Wave JS' for zwave_js integration not ready yet: Failed to connect: Cannot connect to host localhost:3055 ssl:default [Connect call failed ('127.0.0.1', 3055)]; Retrying in background

The latest (aa585edc0749) gives me connection failed from Home Assistant. Tried to go back to kpine/zwave-js-server:1.30.0-11.9.0 and that works just fine.

Here's my docker-compose-file:

version: '3'
services:
  zwave-js-server:
    container_name: zwave-js-server
    image: kpine/zwave-js-server:1.30.0-11.9.0
    # NOT WORKING:
    # image: kpine/zwave-js-server:latest
    restart: unless-stopped
    environment:
      - S2_ACCESS_CONTROL_KEY=blabla
      - S2_AUTHENTICATED_KEY=blabla
      - S2_UNAUTHENTICATED_KEY=blabla
      - S0_LEGACY_KEY=blabla
    devices:
      - /dev/serial/by-id/usb-*-if00:/dev/zwave
    volumes:
      - /docker/zwave_js_server_home/cache:/cache
    ports:
      - '8091:8091'
      - '3055:3000'

    labels:
      - "com.centurylinklabs.watchtower.enable=true"

700 Series update

I performed an update on my Zooz ZST10 700 using a Raspberry Pi 2 Model B running Raspberry Pi OS 32-bit.
Thanks

Unable to flash firmware to Zooz S2 Stick 700

Hello, i have a problem flashing firmware using the latest release.
Error message: Failed to update firmware: The controller is not in bootloader mode! (ZW0103)

Hardware: Raspberry Pi 3,

# cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.5 LTS"

Command line:

 docker run --rm -it   --device /dev/ttyUSB0:/dev/zwave   --volume /root:/fw   ghcr.io/kpine/zwave-js-server:1.26.0-10.12.0-7ec17fa3  flash /fw/Zooz_ZST10-700_SDK_7.18.3_US.gbl --verbose

Log:

Starting driver...
23:42:23.892 DRIVER   ███████╗ ██╗    ██╗  █████╗  ██╗   ██╗ ███████╗             ██╗ ███████╗
                      ╚══███╔╝ ██║    ██║ ██╔══██╗ ██║   ██║ ██╔════╝             ██║ ██╔════╝
                        ███╔╝  ██║ █╗ ██║ ███████║ ██║   ██║ █████╗   █████╗      ██║ ███████╗
                       ███╔╝   ██║███╗██║ ██╔══██║ ╚██╗ ██╔╝ ██╔══╝   ╚════╝ ██   ██║ ╚════██║
                      ███████╗ ╚███╔███╔╝ ██║  ██║  ╚████╔╝  ███████╗        ╚█████╔╝ ███████║
                      ╚══════╝  ╚══╝╚══╝  ╚═╝  ╚═╝   ╚═══╝   ╚══════╝         ╚════╝  ╚══════╝
23:42:23.908 DRIVER   version 10.12.0
23:42:23.911 DRIVER
23:42:23.914 DRIVER   starting driver...
23:42:23.999 DRIVER   opening serial port /dev/zwave
23:42:24.042 DRIVER   serial port opened
23:42:24.047 SERIAL » 0x15                                                                 (1 bytes)
23:42:25.074 DRIVER   beginning interview...
23:42:25.084 DRIVER   added request handler for AddNodeToNetwork (0x4a)...
                      1 registered
23:42:25.087 DRIVER   added request handler for RemoveNodeFromNetwork (0x4b)...
                      1 registered
23:42:25.090 DRIVER   added request handler for ReplaceFailedNode (0x63)...
                      1 registered
23:42:25.095 CNTRLR   querying controller IDs...
23:42:26.064 SERIAL » 0x01030020dc                                                         (5 bytes)
23:42:26.072 DRIVER » [REQ] [GetControllerId]
23:42:26.092 SERIAL « [ACK]                                                                   (0x06)
23:42:26.112 SERIAL « 0x01080120e9c5644301dc                                              (10 bytes)
23:42:26.119 SERIAL » [ACK]                                                                   (0x06)
23:42:26.128 DRIVER « [RES] [GetControllerId]
                        home ID:     0xe9c56443
                        own node ID: 1
23:42:26.170 CNTRLR   received controller IDs:
                        home ID:     0xe9c56443
                        own node ID: 1
23:42:26.172 CNTRLR   querying API capabilities...
23:42:26.207 SERIAL » 0x01030007fb                                                         (5 bytes)
23:42:26.209 DRIVER » [REQ] [GetSerialApiCapabilities]
23:42:26.219 SERIAL « [ACK]                                                                   (0x06)
23:42:26.227 SERIAL « 0x012b0107070d000000040004f6873e88cf2bc04ffbd7fde00700008000808680b (45 bytes)
                      a05007000002e0000000000a5
23:42:26.233 SERIAL » [ACK]                                                                   (0x06)
23:42:26.238 DRIVER « [RES] [GetSerialApiCapabilities]
                        payload: 0x070d000000040004f6873e88cf2bc04ffbd7fde00700008000808680ba0500700
                      0002e0000000000
23:42:26.260 CNTRLR   received API capabilities:
                        firmware version:    7.13
                        manufacturer ID:     0x00
                        product type:        0x04
                        product ID:          0x04
                        supported functions:
                        · GetSerialApiInitData (0x02)
                        · SetApplicationNodeInformation (0x03)
                        · GetControllerCapabilities (0x05)
                        · SetSerialApiTimeouts (0x06)
                        · GetSerialApiCapabilities (0x07)
                        · SoftReset (0x08)
                        · GetProtocolVersion (0x09)
                        · SerialAPIStarted (0x0a)
                        · SerialAPISetup (0x0b)
                        · SetRFReceiveMode (0x10)
                        · FUNC_ID_ZW_SEND_NODE_INFORMATION (0x12)
                        · SendData (0x13)
                        · SendDataMulticast (0x14)
                        · GetControllerVersion (0x15)
                        · SendDataAbort (0x16)
                        · FUNC_ID_ZW_GET_RANDOM (0x1c)
                        · GetControllerId (0x20)
                        · UNKNOWN_FUNC_MEMORY_GET_BYTE (0x21)
                        · UNKNOWN_FUNC_MEMORY_PUT_BYTE (0x22)
                        · UNKNOWN_FUNC_MEMORY_GET_BUFFER (0x23)
                        · UNKNOWN_FUNC_MEMORY_PUT_BUFFER (0x24)
                        · EnterBootloader (0x27)
                        · UNKNOWN_FUNC_UNKNOWN_0x28 (0x28)
                        · GetNVMId (0x29)
                        · ExtNVMReadLongBuffer (0x2a)
                        · ExtNVMReadLongByte (0x2c)
                        · NVMOperations (0x2e)
                        · undefined (0x37)
                        · undefined (0x38)
                        · UNKNOWN_FUNC_ClearNetworkStats (0x39)
                        · UNKNOWN_FUNC_GetNetworkStats (0x3a)
                        · GetBackgroundRSSI (0x3b)
                        · undefined (0x3c)
                        · UNKNOWN_FUNC_RemoveNodeIdFromNetwork (0x3f)
                        · GetNodeProtocolInfo (0x41)
                        · HardReset (0x42)
                        · FUNC_ID_ZW_REPLICATION_COMMAND_COMPLETE (0x44)
                        · FUNC_ID_ZW_REPLICATION_SEND_DATA (0x45)
                        · AssignReturnRoute (0x46)
                        · DeleteReturnRoute (0x47)
                        · RequestNodeNeighborUpdate (0x48)
                        · ApplicationUpdateRequest (0x49)
                        · AddNodeToNetwork (0x4a)
                        · RemoveNodeFromNetwork (0x4b)
                        · FUNC_ID_ZW_CONTROLLER_CHANGE (0x4d)
                        · AssignPriorityReturnRoute (0x4f)
                        · FUNC_ID_ZW_SET_LEARN_MODE (0x50)
                        · AssignSUCReturnRoute (0x51)
                        · FUNC_ID_ZW_REQUEST_NETWORK_UPDATE (0x53)
                        · SetSUCNodeId (0x54)
                        · DeleteSUCReturnRoute (0x55)
                        · GetSUCNodeId (0x56)
                        · UNKNOWN_FUNC_SEND_SUC_ID (0x57)
                        · AssignPrioritySUCReturnRoute (0x58)
                        · FUNC_ID_ZW_EXPLORE_REQUEST_INCLUSION (0x5e)
                        · undefined (0x5f)
                        · RequestNodeInfo (0x60)
                        · RemoveFailedNode (0x61)
                        · IsFailedNode (0x62)
                        · ReplaceFailedNode (0x63)
                        · GetRoutingInfo (0x80)
                        · UNKNOWN_FUNC_LOCK_ROUTE_RESPONSE (0x90)
                        · GetPriorityRoute (0x92)
                        · SetPriorityRoute (0x93)
                        · UNKNOWN_FUNC_UNKNOWN_0x98 (0x98)
                        · FUNC_ID_SERIAL_API_SLAVE_NODE_INFO (0xa0)
                        · FUNC_ID_ZW_SEND_SLAVE_NODE_INFO (0xa2)
                        · FUNC_ID_ZW_SET_SLAVE_LEARN_MODE (0xa4)
                        · FUNC_ID_ZW_GET_VIRTUAL_NODES (0xa5)
                        · FUNC_ID_ZW_IS_VIRTUAL_NODE (0xa6)
                        · BridgeApplicationCommand (0xa8)
                        · SendDataBridge (0xa9)
                        · SendDataMulticastBridge (0xab)
                        · UNKNOWN_FUNC_GET_LIBRARY_TYPE (0xbd)
                        · UNKNOWN_FUNC_SEND_TEST_FRAME (0xbe)
                        · UNKNOWN_FUNC_GET_PROTOCOL_STATUS (0xbf)
                        · UNKNOWN_FUNC_UNKNOWN_0xD2 (0xd2)
                        · UNKNOWN_FUNC_UNKNOWN_0xD3 (0xd3)
                        · UNKNOWN_FUNC_UNKNOWN_0xD4 (0xd4)
                        · undefined (0xd6)
23:42:26.311 CNTRLR   Performing soft reset...
23:42:26.345 SERIAL » 0x01030008f4                                                         (5 bytes)
23:42:26.347 DRIVER » [REQ] [SoftReset]
23:42:26.355 SERIAL « [ACK]                                                                   (0x06)
23:42:26.374 CNTRLR   Waiting for the controller to reconnect...
23:42:27.456 SERIAL « 0x011a000a0300030201115e7a70858659728a556c2256735a74989f1c          (28 bytes)
23:42:27.465 SERIAL » [ACK]                                                                   (0x06)
23:42:27.471 DRIVER « [REQ] [SerialAPIStarted]
                        wake up reason:        WatchdogReset
                        watchdog enabled:      false
                        generic device class:  0x02
                        specific device class: 0x01
                        always listening:      false
                        supports Long Range:   false
23:42:27.482 CNTRLR   reconnected and restarted
23:42:27.526 CNTRLR   querying version info...
23:42:27.551 SERIAL » 0x01030015e9                                                         (5 bytes)
23:42:27.553 DRIVER » [REQ] [GetControllerVersion]
23:42:27.560 SERIAL « [ACK]                                                                   (0x06)
23:42:27.566 SERIAL « 0x011001155a2d5761766520372e3133000795                              (18 bytes)
23:42:27.569 SERIAL » [ACK]                                                                   (0x06)
23:42:27.574 DRIVER « [RES] [GetControllerVersion]
                        payload: 0x5a2d5761766520372e31330007
23:42:27.590 CNTRLR   received version info:
                        controller type: Bridge Controller
                        library version: Z-Wave 7.13
23:42:27.592 CNTRLR   querying protocol version info...
23:42:27.616 SERIAL » 0x01030009f5                                                         (5 bytes)
23:42:27.626 DRIVER » [REQ] [GetProtocolVersion]
23:42:27.631 SERIAL « [ACK]                                                                   (0x06)
23:42:27.638 SERIAL « 0x0119010900070d06014730313233343536373839414243444546a2            (27 bytes)
23:42:27.644 SERIAL » [ACK]                                                                   (0x06)
23:42:27.648 DRIVER « [RES] [GetProtocolVersion]
                        payload: 0x00070d06014730313233343536373839414243444546
23:42:27.669 CNTRLR   received protocol version info:
                        protocol type:             Z-Wave
                        protocol version:          7.13.6
                        appl. framework build no.: 327
                        git commit hash:           30313233343536373839414243444546
23:42:27.684 CNTRLR   supported Z-Wave features:
                        · SmartStart
23:42:27.685 CNTRLR   querying controller capabilities...
23:42:27.714 SERIAL » 0x01030005f9                                                         (5 bytes)
23:42:27.716 DRIVER » [REQ] [GetControllerCapabilities]
23:42:27.724 SERIAL « [ACK]                                                                   (0x06)
23:42:27.729 SERIAL « 0x010401053cc3                                                       (6 bytes)
23:42:27.733 SERIAL » [ACK]                                                                   (0x06)
23:42:27.736 DRIVER « [RES] [GetControllerCapabilities]
                        payload: 0x3c
23:42:27.754 CNTRLR   received controller capabilities:
                        controller role:      primary
                        is the SUC:           true
                        started this network: true
                        SIS is present:       true
                        was real primary:     true
23:42:27.755 CNTRLR   querying serial API setup capabilities...
23:42:27.782 SERIAL » 0x0104000b01f1                                                       (6 bytes)
23:42:27.786 DRIVER » [REQ] [SerialAPISetup]
                        command: GetSupportedCommands
                        payload: 0x01
23:42:27.799 SERIAL « [ACK]                                                                   (0x06)
23:42:27.805 SERIAL « 0x0105010b017e8f                                                     (7 bytes)
23:42:27.810 SERIAL » [ACK]                                                                   (0x06)
23:42:27.814 DRIVER « [RES] [SerialAPISetup]
                        command: GetSupportedCommands
                        payload: 0x7e
23:42:27.831 CNTRLR   supported serial API setup commands:
                      · GetSupportedCommands
                      · SetTxStatusReport
                      · SetPowerlevel
                      · GetPowerlevel
                      · GetMaximumPayloadSize
                      · GetRFRegion
                      · SetRFRegion
23:42:27.834 CNTRLR   Enabling TX status report...
23:42:27.854 SERIAL » 0x0105000b02ff0c                                                     (7 bytes)
23:42:27.858 DRIVER » [REQ] [SerialAPISetup]
                        command: SetTxStatusReport
                        enabled: true
23:42:27.864 SERIAL « [ACK]                                                                   (0x06)
23:42:27.869 SERIAL « 0x0105010b0201f3                                                     (7 bytes)
23:42:27.872 SERIAL » [ACK]                                                                   (0x06)
23:42:27.877 DRIVER « [RES] [SerialAPISetup]
                        command: SetTxStatusReport
                        success: true
23:42:27.891 CNTRLR   Enabling TX status report successful...
23:42:27.892 CNTRLR   Querying configured RF region...
23:42:27.916 SERIAL » 0x0104000b20d0                                                       (6 bytes)
23:42:27.919 DRIVER » [REQ] [SerialAPISetup]
                        command: GetRFRegion
                        payload: 0x20
23:42:27.924 SERIAL « [ACK]                                                                   (0x06)
23:42:27.929 SERIAL « 0x0105010b2001d1                                                     (7 bytes)
23:42:27.933 SERIAL » [ACK]                                                                   (0x06)
23:42:27.938 DRIVER « [RES] [SerialAPISetup]
                        command: GetRFRegion
                        region:  USA
23:42:27.952 CNTRLR   The controller is using RF region USA
23:42:27.953 CNTRLR   finding SUC...
23:42:27.980 SERIAL » 0x01030056aa                                                         (5 bytes)
23:42:27.982 DRIVER » [REQ] [GetSUCNodeId]
23:42:27.988 SERIAL « [ACK]                                                                   (0x06)
23:42:27.992 SERIAL « 0x0104015601ad                                                       (6 bytes)
23:42:27.995 SERIAL » [ACK]                                                                   (0x06)
23:42:27.999 DRIVER « [RES] [GetSUCNodeId]
                        payload: 0x01
23:42:28.012 CNTRLR   This is the SUC
23:42:28.014 CNTRLR   querying additional controller information...
23:42:28.035 SERIAL » 0x01030002fe                                                         (5 bytes)
23:42:28.038 DRIVER » [REQ] [GetSerialApiInitData]
23:42:28.046 SERIAL « [ACK]                                                                   (0x06)
23:42:28.051 SERIAL « 0x0125010208081d010000000000000000000000000000000000000000000000000 (39 bytes)
                      00000000700c2
23:42:28.057 SERIAL » [ACK]                                                                   (0x06)
23:42:28.060 DRIVER « [RES] [GetSerialApiInitData]
                        payload: 0x08081d01000000000000000000000000000000000000000000000000000000000
                      700
23:42:28.076 CNTRLR   received additional controller information:
                        Z-Wave API version:         8 (legacy)
                        Z-Wave chip type:           EFR32ZG14 / ZGM130S
                        node type                   Controller
                        controller role:            primary
                        controller is the SIS:      true
                        controller supports timers: false
                        nodes in the network:       1
23:42:28.121 CNTRLR   [Node 001] [translateValueEvent: metadata updated]
                        commandClass: Manufacturer Specific
                        endpoint:     undefined
                        property:     manufacturerId
                        propertyKey:  undefined
                        internal:     false
                        secret:       false
                        event source: undefined
23:42:28.125 CNTRLR   [Node 001] [Manufacturer Specific] manufacturerId: metadata updated
23:42:28.130 CNTRLR   [Node 001] [translateValueEvent: metadata updated]
                        is root endpoint:        true
                        is application CC:       false
                        should hide root values: false
23:42:28.133 CNTRLR   [Node 001] [translateValueEvent: metadata updated]
                        commandClass: Manufacturer Specific
                        endpoint:     undefined
                        property:     productType
                        propertyKey:  undefined
                        internal:     false
                        secret:       false
                        event source: undefined
23:42:28.134 CNTRLR   [Node 001] [Manufacturer Specific] productType: metadata updated
23:42:28.138 CNTRLR   [Node 001] [translateValueEvent: metadata updated]
                        is root endpoint:        true
                        is application CC:       false
                        should hide root values: false
23:42:28.141 CNTRLR   [Node 001] [translateValueEvent: metadata updated]
                        commandClass: Manufacturer Specific
                        endpoint:     undefined
                        property:     productId
                        propertyKey:  undefined
                        internal:     false
                        secret:       false
                        event source: undefined
23:42:28.143 CNTRLR   [Node 001] [Manufacturer Specific] productId: metadata updated
23:42:28.146 CNTRLR   [Node 001] [translateValueEvent: metadata updated]
                        is root endpoint:        true
                        is application CC:       false
                        should hide root values: false
23:42:28.151 CNTRLR   [Node 001] [translateValueEvent: value added]
                        commandClass: Manufacturer Specific
                        endpoint:     undefined
                        property:     manufacturerId
                        propertyKey:  undefined
                        internal:     false
                        secret:       false
                        event source: undefined
23:42:28.155 CNTRLR   [Node 001] [+] [Manufacturer Specific] manufacturerId: 0
23:42:28.157 CNTRLR   [Node 001] [translateValueEvent: value added]
                        is root endpoint:        true
                        is application CC:       false
                        should hide root values: false
23:42:28.160 CNTRLR   [Node 001] [translateValueEvent: value added]
                        commandClass: Manufacturer Specific
                        endpoint:     undefined
                        property:     productType
                        propertyKey:  undefined
                        internal:     false
                        secret:       false
                        event source: undefined
23:42:28.162 CNTRLR   [Node 001] [+] [Manufacturer Specific] productType: 4
23:42:28.164 CNTRLR   [Node 001] [translateValueEvent: value added]
                        is root endpoint:        true
                        is application CC:       false
                        should hide root values: false
23:42:28.167 CNTRLR   [Node 001] [translateValueEvent: value added]
                        commandClass: Manufacturer Specific
                        endpoint:     undefined
                        property:     productId
                        propertyKey:  undefined
                        internal:     false
                        secret:       false
                        event source: undefined
23:42:28.169 CNTRLR   [Node 001] [+] [Manufacturer Specific] productId: 4
23:42:28.171 CNTRLR   [Node 001] [translateValueEvent: value added]
                        is root endpoint:        true
                        is application CC:       false
                        should hide root values: false
23:42:28.177 CNTRLR   [Node 001] [translateValueEvent: metadata updated]
                        commandClass: Version
                        endpoint:     undefined
                        property:     firmwareVersions
                        propertyKey:  undefined
                        internal:     false
                        secret:       false
                        event source: undefined
23:42:28.179 CNTRLR   [Node 001] [Version] firmwareVersions: metadata updated
23:42:28.181 CNTRLR   [Node 001] [translateValueEvent: metadata updated]
                        is root endpoint:        true
                        is application CC:       false
                        should hide root values: false
23:42:28.186 CNTRLR   [Node 001] [translateValueEvent: value added]
                        commandClass: Version
                        endpoint:     undefined
                        property:     firmwareVersions
                        propertyKey:  undefined
                        internal:     false
                        secret:       false
                        event source: undefined
23:42:28.188 CNTRLR   [Node 001] [+] [Version] firmwareVersions: 7.13
23:42:28.190 CNTRLR   [Node 001] [translateValueEvent: value added]
                        is root endpoint:        true
                        is application CC:       false
                        should hide root values: false
23:42:28.193 CNTRLR   [Node 001] [translateValueEvent: metadata updated]
                        commandClass: Version
                        endpoint:     undefined
                        property:     zWaveProtocolVersion
                        propertyKey:  undefined
                        internal:     false
                        secret:       false
                        event source: undefined
23:42:28.195 CNTRLR   [Node 001] [Version] zWaveProtocolVersion: metadata updated
23:42:28.197 CNTRLR   [Node 001] [translateValueEvent: metadata updated]
                        is root endpoint:        true
                        is application CC:       false
                        should hide root values: false
23:42:28.200 CNTRLR   [Node 001] [translateValueEvent: value added]
                        commandClass: Version
                        endpoint:     undefined
                        property:     zWaveProtocolVersion
                        propertyKey:  undefined
                        internal:     false
                        secret:       false
                        event source: undefined
23:42:28.202 CNTRLR   [Node 001] [+] [Version] zWaveProtocolVersion: "7.13.6"
23:42:28.204 CNTRLR   [Node 001] [translateValueEvent: value added]
                        is root endpoint:        true
                        is application CC:       false
                        should hide root values: false
23:42:28.208 CNTRLR   [Node 001] [translateValueEvent: metadata updated]
                        commandClass: Version
                        endpoint:     undefined
                        property:     sdkVersion
                        propertyKey:  undefined
                        internal:     false
                        secret:       false
                        event source: undefined
23:42:28.209 CNTRLR   [Node 001] [Version] sdkVersion: metadata updated
23:42:28.218 CNTRLR   [Node 001] [translateValueEvent: metadata updated]
                        is root endpoint:        true
                        is application CC:       false
                        should hide root values: false
23:42:28.221 CNTRLR   [Node 001] [translateValueEvent: value added]
                        commandClass: Version
                        endpoint:     undefined
                        property:     sdkVersion
                        propertyKey:  undefined
                        internal:     false
                        secret:       false
                        event source: undefined
23:42:28.223 CNTRLR   [Node 001] [+] [Version] sdkVersion: "7.13.6"
23:42:28.225 CNTRLR   [Node 001] [translateValueEvent: value added]
                        is root endpoint:        true
                        is application CC:       false
                        should hide root values: false
23:42:28.226 CNTRLR   Interview completed
23:42:28.231 DRIVER   No network key for S0 configured, communication with secure (S0) devices won't
                       work!
23:42:28.232 DRIVER   No network key for S2 configured, communication with secure (S2) devices won't
                       work!
23:42:28.234 DRIVER   driver ready
Flashing firmware...
23:42:28.244 CNTRLR   Entering bootloader...
23:42:28.252 CNTRLR   Performing soft reset...
23:42:28.287 SERIAL » 0x01030008f4                                                         (5 bytes)
23:42:28.291 DRIVER » [REQ] [SoftReset]
23:42:28.299 SERIAL « [ACK]                                                                   (0x06)
23:42:28.313 CNTRLR   Waiting for the controller to reconnect...
23:42:29.398 SERIAL « 0x011a000a0300030201115e7a70858659728a556c2256735a74989f1c          (28 bytes)
23:42:29.402 SERIAL » [ACK]                                                                   (0x06)
23:42:29.406 DRIVER « [REQ] [SerialAPIStarted]
                        wake up reason:        WatchdogReset
                        watchdog enabled:      false
                        generic device class:  0x02
                        specific device class: 0x01
                        always listening:      false
                        supports Long Range:   false
23:42:29.413 CNTRLR   reconnected and restarted
23:42:29.418 SERIAL » 0x01030027db                                                         (5 bytes)
23:42:29.510 SERIAL « �
23:42:29.515 CNTRLR   [BOOTLOADER] �
23:42:29.517 SERIAL «
23:42:29.519 CNTRLR   [BOOTLOADER]
23:42:30.021 CNTRLR   [BOOTLOADER] ^zp��Yr�Ul"VsZt��
23:42:31.038 SERIAL «
23:42:31.040 CNTRLR   [BOOTLOADER]
23:42:31.042 SERIAL «
23:42:31.043 CNTRLR   [BOOTLOADER]
23:42:31.545 CNTRLR   [BOOTLOADER] ^zp��Yr�Ul"VsZt��
23:42:32.566 SERIAL «
23:42:32.568 CNTRLR   [BOOTLOADER]
23:42:32.570 SERIAL «
23:42:32.572 CNTRLR   [BOOTLOADER]
23:42:33.075 CNTRLR   [BOOTLOADER] ^zp��Yr�Ul"VsZt��
23:42:34.095 SERIAL «
23:42:34.097 CNTRLR   [BOOTLOADER]
23:42:34.099 SERIAL «
23:42:34.101 CNTRLR   [BOOTLOADER]
23:42:34.425 CNTRLR   Leaving bootloader...
Failed to update firmware: The controller is not in bootloader mode! (ZW0103)

Wiki update/suggestion

Heyo, fantastic work! I just wanted to try to contribute to the wiki page here: https://github.com/kpine/zwave-js-server-docker/wiki/700-series-Controller-Firmware-Updates-(Linux)#host-update-method

Between steps 2 & 3, these steps should be added or added as one big step:

  1. Add the "testing" branch to your apk repo list: vi /etc/apk/repositories
  2. Press the insert key to enable edit mode in vi
  3. Add a new line after the last line: https://dl-cdn.alpinelinux.org/alpine/edge/testing
  4. Now save and exit vi by pressing the Escape key, and type : followed by wq
  5. Install minicom by issuing: apk add minicom && apk add lrzsz
  6. (former step 3)

Fatal error when running latest version in unprivileged mode on RaspberryPi

Example:

$ docker run -it --rm -p 3000:3000 --name=zjs -v "$PWD/cache:/cache" -e NETWORK_KEY="17DFB0C1BED4CABFF54E4B5375E257B3" --device "/dev/ttyUSB1:/dev/zwave" kpine/zwave-js-server:latest

Starting zwave-server: zwave-server --config options.js /dev/zwave


#
# Fatal error in , line 0
# unreachable code
#
#
#
#FailureMessage Object: 0xbee37

However, if I run in the privileged mode it works:

$ docker run -it --rm -p 3000:3000 --name=zjs -v "$PWD/cache:/cache" -e NETWORK_KEY="17DFB0C1BED4CABFF54E4B5375E257B3" --privileged -e USB_PATH=/dev/ttyUSB1  kpine/zwave-js-server:latest

Starting zwave-server: zwave-server --config options.js /dev/ttyUSB1
18:34:00.356 DRIVER   version 8.0.6
18:34:00.357 DRIVER
18:34:00.358 DRIVER   starting driver...
18:34:00.396 DRIVER   opening serial port /dev/ttyUSB1
18:34:00.425 DRIVER   serial port opened
........

I did some digging and it looks like the problem comes from recent docker alpine image 3.13 and above. I don't know if there is a direct connection, but the given image has some basic functionality broken as well:

$ docker run -it --rm alpine:3.13 ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
ping: clock_gettime(MONOTONIC) failed

$ docker run -it --rm alpine:3.13 date
Sun Jan  0 00:100:4174038  1900

$ docker run -it --rm alpine:3.14 ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
ping: clock_gettime(MONOTONIC) failed

$ docker run -it --rm alpine:3.14 date
Mon Jun  8 19:59:44 UTC 2071

$ docker run -it --rm alpine:latest ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
ping: clock_gettime(MONOTONIC) failed

$ docker run -it --rm alpine:latest date
Thu Jun 11 10:34:24 UTC 2071

However, this works in 3.12:

$ docker run -it --rm alpine:3.12 ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=57 time=5.019 ms
...

$ docker run -it --rm alpine:3.12 date
Sat Jul 31 22:13:43 UTC 2021

I found a relevant issue here which is referring specifically to version 3.13.

Aeotec Z-stick 700: Strange characters displayed in controllers bootloader when upgrading

I got an Aeotec Z-stick 700 (with firmware v7.17.2) and tried updating to v7.18.1 (by using Aeotec download link from README). I followed both firmware update instructions, by using Docker container and running bash script from host, but after 10 seconds, when the controllers bootloader is displayed, I get strange characters continously in the command line. It's impossible to quit the process and I never see any menu with options.

Im running Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-56-generic x86_64) on Intel Nuc, and Im ssh into the machine when executing the commands.

With bash script (but similar with docker container)

> sudo bash zfw-update.sh

Welcome to minicom 2.8

OPTIONS: I18n
Port /dev/ttyUSB0

Press CTRL-A Z for help on special keys

Activating the controller's bootloader. It will appear in about 10 seconds...
9...
8...
2!$�.�21"ֵ�21"ֵ�21"ֵ�21"ֵ�s`
1"��s                                                    `
1"��s       `
1"��s       `
1"��s       `
1"���s      `
2�"u`   R��u`
1"گ7�u          `
1"گ7�u      `
1"گ7�u      `
2!$�1�``R�r``
1"���      `
1"���     `
1"���     `
1"���71   `
              ���71
                       ���71
                                ���71
                                         ���s
1"��s                                           `
CTRL-A Z for help | 115200 8N1 | NOR | Minicom 2.8   VT102 | Offline | ttyUSB0

Using docker image for update doesn't show bootloader

I am trying to update the firmware on my aeotec stick 7, but I never get the boot loader program option. When running with the firmware upgrade he is looking for a file /app/options.js. Am I missing something ?

suggestion -- provide minicom script for 700 series Controller Firmware Updates doc

Rather than separate stty and printf commands, I think it's less error-prone to just do it all with minicom. Include the following script (note hex had to be converted to octal):

print "Soft-reset the controller"
send "\1\3\0\10\364"

print "Waiting for the controller to recover. You may see some junk"
print "characters printed to the screen. This is normal."
sleep 10

print "Dropping controller to bootloader."
send "\1\3\0\47\333"

print "This should be followed by 'Gecko Bootloader ...' and a menu."
print "Pick #3, then use xmodem to upload your firmware gbl when it "
print "starts printing CCCC.... (press Ctrl-a then s, then pick with "
print "<spacebar> and press <enter> to upload)."
print ""
print "When complete, pick #2 (run). You'll see the sequence of junk "
print "characters again -- that means it's working! Ctrl-A q to exit."
sleep 1

Save that as 700firmware.runscript and then start minicom with

minicom -o -S 700firmware.runscript zwave

Actually, I think -o can actually be omitted as your zwave config doesn't send an init string. So just:

minicom -S 700firmware.runscript zwave

This could be enhanced to use the expect runscript command to find the menu, and even call sx to upload the firmware automatically, but that's probably overkill (and at that point maybe minicom isn't the right tool anyway).

Also of note — if you're in the dialout group in most distros, no need to be root, and you can put the minicom zwave config at ~/.minirc.zwave instead of in /etc.

TypeError: Cannot set property 'S0_Legacy' of undefined

I am on the latest branch kpine/zwave-js-server:latest and am now receiving the following error,

Starting zwave-server: zwave-server --config options.js /dev/zwave
Error: failed loading config file /app/options.js
TypeError: Cannot set property 'S0_Legacy' of undefined
    at /app/node_modules/@zwave-js/server/dist/bin/server.js:66:48
    at Object.<anonymous> (/app/node_modules/@zwave-js/server/dist/bin/server.js:116:3)
    at Module._compile (internal/modules/cjs/loader.js:1072:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)
    at Module.load (internal/modules/cjs/loader.js:937:32)
    at Function.Module._load (internal/modules/cjs/loader.js:778:12)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
    at internal/main/run_main_module.js:17:47

Validated that rolling back to version 1.10.0-8.2.0 I was able to get around the above issue.

Looking at the latest pull requests, I am seeing Add S2 key support #7 which is where I think the above bug was introduced in version 1.10.1-8.2.1.

Retry 0: No ACK on EOT

I tried updating using the docker and the host methods but both resolves in the same error when trying to upload gbl, any idea on why this is happening would be appreciated!

image

This only happens for 7.18.2 firmware for Z-Stick 7, I tried using 7.18.1 and that works without error

0x50 error when updating Zooz 7.15 --> 7.17

I don't know if you would be able to assist, but trying to update my Zooz controller to the latest firmware.

I initially went the simplicity studio route to update, where I got 0x50 errors. Communications with zooz thus far have not been helpful. I came along your wiki and tried to update utilizing your method, and after I select the firmware in minicom, the transfer never completes:
image

I saw note #2 on https://community.silabs.com/s/article/z-wave-700-otw-of-controller?language=en_US, but not sure how to do that, and if that is even the problem. Any help is appreciated.

Error: Invalid key format for securityKeys.S2_AccessControl option

zwavejs                     | Starting zwave-server: zwave-server --config options.js /dev/zwave
zwavejs                     | Error: failed loading config file /app/options.js
zwavejs                     | Error: Invalid key format for securityKeys.S2_AccessControl option
zwavejs                     |     at normalizeKey (/app/node_modules/@zwave-js/server/dist/bin/server.js:18:11)
zwavejs                     |     at /app/node_modules/@zwave-js/server/dist/bin/server.js:66:53
zwavejs                     |     at Object.<anonymous> (/app/node_modules/@zwave-js/server/dist/bin/server.js:145:3)
zwavejs                     |     at Module._compile (node:internal/modules/cjs/loader:1105:14)
zwavejs                     |     at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
zwavejs                     |     at Module.load (node:internal/modules/cjs/loader:981:32)
zwavejs                     |     at Function.Module._load (node:internal/modules/cjs/loader:822:12)
zwavejs                     |     at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
zwavejs                     |     at node:internal/main/run_main_module:17:47

I've just updated to the latest docker image and when I try and start it I get the error above ...

Can confirm it's possible to update 700 Series firmware from a docker container.

I used a Debian 10.9 image, but it probably works with many other Linux images, of course. Ran with this command (from a Synology NAS):

docker run --name="debian" -it --net=host -v /volume1/docker/debian:/tmp --device /dev/ttyUSB0 debian:10.9

Had to do an apt update before the packages could be installed, but otherwise the instructions were the same. Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.