There are three Zigbee API levels which all build on top of each other with increasing complexity to interact with Zigbee devices on Homey:
In general it is likely you will only need node-homey-zigbeedriver, and possibly node-zigbee-clusters if you want to do some more advanced things. The Zigbee-API is what node-zigbee-clusters
is built on. It is not advised to use this API directly, but it is there in case you need it.
1. node-homey-zigbeedriver
This is a library developed by Athom which makes it easier to create Drivers for Zigbee devices.
It exposes classes which can be extended in your app and other useful functionality. The most important class is ZigBeeDevice
. This class handles getting a ZigBeeNode and uses node-zigbee-clusters to extend the ZigBeeNode with Zigbee Cluster Library (ZCL) functionality. Doing this enables a developer to directly communicate with the ZigBeeNode using ZCL very easily. The basic usage is demonstrated below, for more in-depth information take a look at the node-homey-zigbeedriver documentation or the source code on GitHub.
/device.js
const { ZigBeeDevice } = require('homey-zigbeedriver');
class MyZigBeeDevice extends ZigBeeDevice {
async onNodeInit({ zclNode }) {
await zclNode.endpoints[1].clusters.onOff.toggle();
}
}
Note: for Zigbee light devices (e.g. bulbs and spots) we created ZigBeeLightDevice, this class can be extended in your driver and will by default handle all light related functionality.
For inspiration check out some of the Zigbee apps already created with node-homey-zigbeedriver:
2. node-zigbee-clusters
This is the library used by node-homey-zigbeedriver to expose the Zigbee Cluster Library (ZCL) functionality. It implements all the clusters that are accessible through zclNode
in lib/clusters
. It is very easy to add new clusters, or add attributes or commands to an existing cluster, merely by changing the definition in one of the cluster files (e.g. the onOff cluster). Take a look at the Zigbee Cluster Specification (PDF) if you are interested in how this library works. The basic usage of this library is demonstrated below, note that it is usually better to use ZigBeeDevice
exported by node-homey-zigbeedriver instead.
/device.js
const Homey = require('homey');
const { ZCLNode, CLUSTER } = require('zigbee-clusters');
class MyDevice extends Homey.Device {
async onInit() {
// Get ZigBeeNode instance from ManagerZigBee
const node = await this.homey.zigbee.getNode(this);
// Create ZCLNode instance
const zclNode = new ZCLNode(node);
// Interact with the node
await zclNode.endpoints[1].clusters.onOff.toggle();
}
}
There are a few cases where you need to interact with node-zigbee-clusters in your app.
1. Interacting with node-homey-zigbeedriver
In order to inform node-homey-zigbeedriver
about which cluster we are targeting we need to import the cluster specification from node-zigbee-clusters
as demonstrated below.
const { CLUSTER } = require('zigbee-clusters');
const { ZigBeeDevice } = require('homey-zigbeedriver');
class MyZigBeeDevice extends ZigBeeDevice {
onNodeInit() {
// Register onoff capability
this.registerCapability('onoff', CLUSTER.ON_OFF);
}
}
This ensures the cluster to be registered is actually available in node-zigbee-clusters
.
2. Implementing a new cluster, or improving an existing cluster
It is very easy to add or improve clusters in node-zigbee-clusters
by changing the cluster definition in lib/clusters
. For more information on how to do this, check out Implementing a cluster.
3. Implementing a bound cluster
As mentioned in the introduction, in order to receive commands from a node a binding must be made
to the respective cluster. This can be done by listing the cluster id in the bindings
array in
the driver's manifest (read Creating a Zigbee Driver for more information on the driver's
manifest). Please refer to Implementing a bound cluster for more information on how to create a BoundCluster
in your driver.
4. Implementing a custom cluster
Zigbee device manufacturers are allowed to implement custom clusters for their devices. In order to use such a custom cluster in your driver you need to extend an existing cluster with the custom behaviour. Check out Implementing a custom cluster on how to do this exactly.
3. Zigbee-API
The Zigbee-API can be used for directly communicating with a ZigBeeNode if needed. In general it is advised not to use this API and take a look at node-zigbee-clusters and node-homey-zigbeedriver which are libraries built on top of the Zigbee-API which do most of the heavy lifting and make it even easier to develop Zigbee apps for Homey.
In the unexpected case that you do want to access the Zigbee-API take a look below for a basic example.
First, the ZigBeeNode must be retrieved from ManagerZigBee.
/device.js
class MyDevice extends Homey.Device {
async onInit() {
const node = await this.homey.zigbee.getNode(this);
}
}
Next, we can use the Zigbee-API to directly communicate with the ZigBeeNode using ZigBeeNode#sendFrame and ZigBeeNode#handleFrame. Important: override the handleFrame
method on ZigBeeNode, this method is called when a frame is received and if it is not overridden it will throw.
/device.js
const node = await this.homey.zigbee.getNode(this);
node.handleFrame = (endpointId, clusterId, frame, meta) => {
if (endpointId === 1 && clusterId === 6) {
// The node sent a frame to Homey from endpoint 1 and cluster 'onOff'
}
};
// Send a frame to endpoint 1, cluster 6 ('onOff') which turns the node on
await node.sendFrame(
1, // endpoint id
6, // cluster id
Buffer.from([
1, // frame control
0, // transaction sequence number
1, // command id ('on')
]),
);
// Send a frame to endpoint 1, cluster 6 ('onOff') which turns the node off
await node.sendFrame(
1, // endpoint id
6, // cluster id
Buffer.from([
1, // frame control
1, // transaction sequence number
0, // command id ('off')
]),
);