npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

irrelonopenzwave

v1.0.0

Published

Control a Z-Wave network via the Open Z-Wave library

Downloads

10

Readme

Note this fork is a modified version of openzwave that includes changes making it easier to receive data on device changes

node-openzwave

This is a node.js add-on which wraps the Open Z-Wave library to provide access to a Z-Wave network from JavaScript.

It is currently able to scan a Z-Wave network, report on connected devices, monitor the network for changes, and has rudimentary write support.

This fork is a somewhat experimental version of the original node-openzwave which appears to be fairly unmaintained with not everything implemented yet. With this fork I'm trying to improve on the original work based on changes done by the community.

Changes include:

  • Support for Scene & Node Events
  • More recent OpenZWave (1.3.x)
  • Network healing functionality
  • Support for `setConfigParam
  • Instance control of switches

Install

The module currently builds only on OS X and Linux. On Linux you will need to ensure the libudev headers are installed first.

$ npm install openzwave

API

Start by loading the addon and creating a new instance, specifying a path to the USB device:

var OpenZWave = require('openzwave');
var zwave     = new OpenZWave('/dev/ttyUSB0');

An optional object can be passed at creation time to alter the behavior of the ZWave module. The options currently supported and their defaults are:

var OpenZWave = require('openzwave');
var zwave     = new OpenZWave('/dev/ttyUSB0', {
        logging: false,           // enable logging to OZW_Log.txt
        consoleoutput: false,     // copy logging to the console
        saveconfig: false,        // write an XML network layout
        driverattempts: 3,        // try this many times before giving up
        pollinterval: 500,        // interval between polls in milliseconds
        suppressrefresh: true,    // do not send updates if nothing changed
});

The rest of the API is split into Functions and Events. Messages from the Z-Wave network are handled by EventEmitter, and you will need to listen for specific events to correctly map the network.

Functions

Connecting to the network:

zwave.connect();     // initialise and start a new driver.
zwave.disconnect();  // disconnect from the current connection

Modifying device state:

/*
 * Set a multi-level device to the specified level (between 0-99).
 */
zwave.setLevel(nodeid, level);

/*
 * Turn a binary switch on/off.
 */
zwave.switchOn(nodeid);
zwave.switchOff(nodeid);

/*
 * Set arbitrary values.
 */
zwave.setValue(nodeid, commandclass, index, value);

Writing to device metadata (stored on the device itself):

zwave.setLocation(nodeid, location);    // arbitrary location string
zwave.setName(nodeid, name);            // arbitrary name string

Polling a device for changes (not all devices require this):

zwave.enablePoll(nodeid, commandclass);
zwave.disablePoll(nodeid, commandclass);

Reset the controller. Calling hardReset will clear any associations, so use carefully:

zwave.hardReset();      // destructive! will wipe out all known configuration
zwave.softReset();      // non-destructive, just resets the chip

Repair network. Call 'healNetwork' will do a node-by-node network heal and perform a return route initialization.

zwave.healNetwork();

Events

The supported events are:

.on('connected', function(){})

We have connected to an OpenZWave node.

.on('driver ready', function(homeid){})

The OpenZWave driver has initialised and scanning has started. Returns a unique homeid which identifies this particular network.

.on('driver failed', function(){})

The OpenZWave driver failed to initialise.

.on('node added', function(nodeid){})

A new node has been found on the network. At this point you can allocate resources to hold information about this node.

.on('value added', function(nodeid, commandclass, value){})

A new value has been discovered. Values are associated with a particular node, and are the parts of the device you can monitor or control.

Values are split into command classes. The classes currently supported and their unique identifiers are:

  • COMMAND_CLASS_SWITCH_BINARY (37)
  • COMMAND_CLASS_SWITCH_MULTILEVEL (38)
  • COMMAND_CLASS_VERSION (134)

Binary switches can be controlled with .switchOn() and .switchOff().

Multi-level devices can be set with .setLevel().

The version class is informational only and cannot be controlled.

The value object differs between command classes, and contains all the useful information about values stored for the particular class.

.on('value changed', function(nodeid, commandclass, value){})

A value has changed. Use this to keep track of value state across the network. When values are first discovered, the module enables polling on those values so that we will receive change messages.

Prior to the 'node ready' event, there may be 'value changed' events even when no values were actually changed.

.on('value removed', function(nodeid, commandclass, index){})

A value has been removed. Use the index to calculate the offset where a command class can contain multiple values.

.on('node ready', function(nodeid, nodeinfo){})

A node is now ready for operation, and information about the node is available in the nodeinfo object:

  • nodeinfo.manufacturer
  • nodeinfo.product
  • nodeinfo.type
  • nodeinfo.loc (location, renamed to avoid location keyword).

.on('scan complete', function(){})

The initial network scan has finished.

Example

The test program below connects to a Z-Wave network, scans for all nodes and values, and prints out information about the network. It will then continue to scan for changes until the user hits ^C.

/*
 * OpenZWave test program.
 */

var OpenZWave = require('openzwave');

var zwave = new OpenZWave('/dev/ttyUSB0', {
	saveconfig: true,
});
var nodes = [];

zwave.on('driver ready', function(homeid) {
	console.log('scanning homeid=0x%s...', homeid.toString(16));
});

zwave.on('driver failed', function() {
	console.log('failed to start driver');
	zwave.disconnect();
	process.exit();
});

zwave.on('node added', function(nodeid) {
	nodes[nodeid] = {
		manufacturer: '',
		manufacturerid: '',
		product: '',
		producttype: '',
		productid: '',
		type: '',
		name: '',
		loc: '',
		classes: {},
		ready: false,
	};
});

zwave.on('value added', function(nodeid, comclass, value) {
	if (!nodes[nodeid]['classes'][comclass])
		nodes[nodeid]['classes'][comclass] = {};
	nodes[nodeid]['classes'][comclass][value.index] = value;
});

zwave.on('value changed', function(nodeid, comclass, value) {
	if (nodes[nodeid]['ready']) {
		console.log('node%d: changed: %d:%s:%s->%s', nodeid, comclass,
			    value['label'],
			    nodes[nodeid]['classes'][comclass][value.index]['value'],
			    value['value']);
	}
	nodes[nodeid]['classes'][comclass][value.index] = value;
});

zwave.on('value removed', function(nodeid, comclass, index) {
	if (nodes[nodeid]['classes'][comclass] &&
	    nodes[nodeid]['classes'][comclass][index])
		delete nodes[nodeid]['classes'][comclass][index];
});

zwave.on('node ready', function(nodeid, nodeinfo) {
	nodes[nodeid]['manufacturer'] = nodeinfo.manufacturer;
	nodes[nodeid]['manufacturerid'] = nodeinfo.manufacturerid;
	nodes[nodeid]['product'] = nodeinfo.product;
	nodes[nodeid]['producttype'] = nodeinfo.producttype;
	nodes[nodeid]['productid'] = nodeinfo.productid;
	nodes[nodeid]['type'] = nodeinfo.type;
	nodes[nodeid]['name'] = nodeinfo.name;
	nodes[nodeid]['loc'] = nodeinfo.loc;
	nodes[nodeid]['ready'] = true;
	console.log('node%d: %s, %s', nodeid,
		    nodeinfo.manufacturer ? nodeinfo.manufacturer
					  : 'id=' + nodeinfo.manufacturerid,
		    nodeinfo.product ? nodeinfo.product
				     : 'product=' + nodeinfo.productid +
				       ', type=' + nodeinfo.producttype);
	console.log('node%d: name="%s", type="%s", location="%s"', nodeid,
		    nodeinfo.name,
		    nodeinfo.type,
		    nodeinfo.loc);
	for (comclass in nodes[nodeid]['classes']) {
		switch (comclass) {
		case 0x25: // COMMAND_CLASS_SWITCH_BINARY
		case 0x26: // COMMAND_CLASS_SWITCH_MULTILEVEL
			zwave.enablePoll(nodeid, comclass);
			break;
		}
		var values = nodes[nodeid]['classes'][comclass];
		console.log('node%d: class %d', nodeid, comclass);
		for (idx in values)
			console.log('node%d:   %s=%s', nodeid, values[idx]['label'], values[idx]['value']);
	}
});

zwave.on('notification', function(nodeid, notif) {
	switch (notif) {
	case 0:
		console.log('node%d: message complete', nodeid);
		break;
	case 1:
		console.log('node%d: timeout', nodeid);
		break;
	case 2:
		console.log('node%d: nop', nodeid);
		break;
	case 3:
		console.log('node%d: node awake', nodeid);
		break;
	case 4:
		console.log('node%d: node sleep', nodeid);
		break;
	case 5:
		console.log('node%d: node dead', nodeid);
		break;
	case 6:
		console.log('node%d: node alive', nodeid);
		break;
        }
});

zwave.on('scan complete', function() {
	console.log('scan complete, hit ^C to finish.');
});

zwave.on('node event', function(nodeid, eventid) {
  console.log('node%d: node event %d', nodeid, eventid);
});

zwave.on('scene event', function(nodeid, sceneid) {
  console.log('node%d: scene %d activated', nodeid, sceneid);
});

zwave.connect();

process.on('SIGINT', function() {
	console.log('disconnecting...');
	zwave.disconnect();
	process.exit();
});

Sample output from this program:

$ node test.js 2>/dev/null
scanning homeid=0x161db5f...
node1: Aeon Labs, Z-Stick S2
node1: name="", type="Static PC Controller", location=""
node1: class 32
node1:   Basic=0
node11: Everspring, AD142 Plug-in Dimmer Module
node11: name="", type="Multilevel Power Switch", location=""
node11: class 32
node11: class 38
node11:   Level=89
node11:   Bright=undefined
node11:   Dim=undefined
node11:   Ignore Start Level=true
node11:   Start Level=0
node11: class 39
node11:   Switch All=3073
node11: class 115
node11:   Powerlevel=3073
node11:   Timeout=0
node11:   Set Powerlevel=undefined
node11:   Test Node=0
node11:   Test Powerlevel=3072
node11:   Frame Count=0
node11:   Test=undefined
node11:   Report=undefined
node11:   Test Status=3072
node11:   Acked Frames=0
node11: class 117
node11:   Protection=3072
node11: class 134
node11:   Library Version=4
node11:   Protocol Version=2.64
node11:   Application Version=1.02
node12: Wenzhou TKB Control System, product=0103, type=0101
node12: name="", type="Binary Power Switch", location=""
node12: class 32
node12: class 37
node12:   Switch=true
node12: class 39
node12:   Switch All=3161
node12: class 134
node12:   Library Version=6
node12:   Protocol Version=3.40
node12:   Application Version=1.04
node13: Wenzhou TKB Control System, product=0103, type=0101
node13: name="", type="Binary Power Switch", location=""
node13: class 32
node13: class 37
node13:   Switch=true
node13: class 39
node13:   Switch All=3073
node13: class 134
node13:   Library Version=6
node13:   Protocol Version=3.40
node13:   Application Version=1.04
node10: Popp / Duwi, ZW ESJ Blind Control
node10: name="", type="Multiposition Motor", location=""
node10: class 32
node10: class 37
node10:   Switch=true
node10: class 38
node10:   Level=99
node10:   Bright=undefined
node10:   Dim=undefined
node10:   Ignore Start Level=true
node10:   Start Level=0
node10: class 39
node10:   Switch All=3073
node10: class 117
node10:   Protection=3073
node10: class 134
node10:   Library Version=6
node10:   Protocol Version=2.51
node10:   Application Version=1.00
node10: class 135
node10:   Indicator=0
scan complete, hit ^C to finish.
^Cdisconnecting...

Remove 2>/dev/null to get verbose output of all incoming notification types and additional debug information.

License

The Open Z-Wave library that this module heavily relies upon is licensed under the LGPLv3.

Everything else (all the bits that I have written) is under the vastly more sensible ISC license.