The controller instance contains information about the controller and a list of its nodes.
supportsFeature(feature: ZWaveFeature): boolean | undefined
Some Z-Wave features are not available on all controllers and can potentially create unwanted situations. The supportsFeature
method must be used to check for support before using certain features. It returns a boolean indicating whether the feature is supported or undefined
if this information isn't known yet.
The available features to test for are:
enum ZWaveFeature {
SmartStart,
}
async beginInclusion(options: InclusionOptions): Promise<boolean>
Starts the inclusion process for a new node. The returned promise resolves to true
if starting the inclusion was successful, false
if it failed or if it was already active.
The options parameter is used to specify the inclusion strategy and provide callbacks to the application which are necessary to support inclusion with Security S2. The following inclusion strategies are defined:
-
InclusionStrategy.Default
: Prefer Security S2 if supported, use Security S0 if absolutely necessary (e.g. for legacy locks) or if opted in with theforceSecurity
flag, don't use encryption otherwise.
This is the recommended strategy and should be used unless there is a good reason not to. -
InclusionStrategy.Insecure
: Don't use encryption, even if supported.
Not recommended, because S2 should be used where possible. -
InclusionStrategy.Security_S0
: Use Security S0, even if a higher security mode is supported. Issues a warning if Security S0 is not supported or the secure bootstrapping fails.
Not recommended because S0 should be used sparingly and S2 preferred wherever possible. -
InclusionStrategy.Security_S2
: Use Security S2 and issue a warning if it is not supported or the secure bootstrapping fails.
Not recommended becauseDefault
is more versatile and less complicated for the user.
Note
For some devices, a special inclusion sequence needs to be performed in order to include it securely. Please refer to the device manual for further information.
[!NOTE] We've compiled some guidelines how to tackle inclusion from the UI side, especially for Security S2.
Depending on the chosen inclusion strategy, the options object requires additional properties:
type InclusionOptions =
| {
strategy: InclusionStrategy.Default;
/**
* Allows overriding the user callbacks for this inclusion.
* If not given, the inclusion user callbacks of the driver options will be used.
*/
userCallbacks?: InclusionUserCallbacks;
/**
* Force secure communication (S0) even when S2 is not supported and S0 is supported but not necessary.
* This is not recommended due to the overhead caused by S0.
*/
forceSecurity?: boolean;
}
| {
strategy: InclusionStrategy.Security_S2;
/**
* Allows pre-filling the DSK, e.g. when a DSK-only QR code has been scanned.
* If this is given, the `validateDSKAndEnterPIN` callback will not be called.
*/
dsk?: string;
/**
* Allows overriding the user callbacks for this inclusion.
* If not given, the inclusion user callbacks of the driver options will be used.
*/
userCallbacks?: InclusionUserCallbacks;
}
| {
strategy: InclusionStrategy.Security_S2;
/**
* The optional provisioning entry for the device to be included.
* If not given, the inclusion user callbacks of the driver options will be used.
*/
provisioning?: PlannedProvisioningEntry;
}
| {
strategy:
| InclusionStrategy.Insecure
| InclusionStrategy.Security_S0;
};
For inclusion with Security S2, callbacks into the application must be defined as part of the driver options (inclusionUserCallbacks
). They can optionally be overridden for individual inclusion attempts by setting the userCallbacks
property in the InclusionOptions
. The callbacks are defined as follows:
interface InclusionUserCallbacks {
/**
* Instruct the application to display the user which security classes the device has requested and whether client-side authentication (CSA) is desired.
* The returned promise MUST resolve to the user selection - which of the requested security classes have been granted and whether CSA was allowed.
* If the user did not accept the requested security classes, the promise MUST resolve to `false`.
*/
grantSecurityClasses(
requested: InclusionGrant,
): Promise<InclusionGrant | false>;
/**
* Instruct the application to display the received DSK for the user to verify if it matches the one belonging to the device and
* additionally enter the PIN that's found on the device.
* The returned promise MUST resolve to the 5-digit PIN (as a string) when the user has confirmed the DSK and entered the PIN and `false` otherwise.
*
* @param dsk The partial DSK in the form `-bbbbb-ccccc-ddddd-eeeee-fffff-11111-22222`. The first 5 characters are left out because they are the unknown PIN.
*/
validateDSKAndEnterPIN(dsk: string): Promise<string | false>;
/** Called by the driver when the user validation has timed out and needs to be aborted */
abort(): void;
}
This includes choosing the security classes to grant to the node and whether client side authentication should allowed.
interface InclusionGrant {
/**
* An array of security classes that are requested or to be granted.
* The granted security classes MUST be a subset of the requested ones.
*/
securityClasses: SecurityClass[];
/** Whether client side authentication is requested or to be granted */
clientSideAuth: boolean;
}
enum SecurityClass {
/**
* Used internally during inclusion of a node. Don't use this!
*/
Temporary = -2,
/**
* `None` is used to indicate that a node is included without security.
* It is not meant as input to methods that accept a security class.
*/
None = -1,
S2_Unauthenticated = 0,
S2_Authenticated = 1,
S2_AccessControl = 2,
S0_Legacy = 7,
}
[!NOTE] These callbacks will also be called when inclusion is initiated by an inclusion controller. As such, the corresponding UI flow must be supported outside of application-initiated inclusion.
Alternatively, the node can be pre-provisioned by providing the full DSK and the granted security classes instead of the user callbacks:
interface PlannedProvisioningEntry {
/** The device specific key (DSK) in the form aaaaa-bbbbb-ccccc-ddddd-eeeee-fffff-11111-22222 */
dsk: string;
securityClasses: SecurityClass[];
// ...other fields are irrelevant for this inclusion procedure
}
[!NOTE] The
provisioning
property acceptsQRProvisioningInformation
which is returned byparseQRCodeString
. You just need to make sure that the QR code is anS2
QR code by checking theversion
field.
[!ATTENTION] The intended use case for this is inclusion after scanning a S2 QR code. Otherwise, care must be taken to give correct information. If the included node has a different DSK than the provided one, the secure inclusion will fail. Furthermore, the node will be granted only those security classes that are requested and the provided list. If there is no overlap, the secure inclusion will fail.
async stopInclusion(): Promise<boolean>
Stops the inclusion process for a new node. The returned promise resolves to true
if stopping the inclusion was successful, false
if it failed or if it was not active.
async beginExclusion(options?: ExclusionOptions): Promise<boolean>
Starts the exclusion process to remove a node from the network. The returned promise resolves to true
if starting the exclusion was successful, false
if it failed or if it was already active.
The optional options
parameter specifies further actions like removing or disabling the node's Smart Start provisioning entries:
type ExclusionOptions = {
strategy:
| ExclusionStrategy.ExcludeOnly
| ExclusionStrategy.DisableProvisioningEntry
| ExclusionStrategy.Unprovision;
};
where the strategy is one of the following values:
enum ExclusionStrategy {
/** Exclude the node, keep the provisioning entry untouched */
ExcludeOnly,
/** Disable the node's Smart Start provisioning entry, but do not remove it */
DisableProvisioningEntry,
/** Remove the node from the Smart Start provisioning list */
Unprovision,
}
[!NOTE] The default behavior is disabling the provisioning entry.
async stopExclusion(): Promise<boolean>
Stops the exclusion process to remove a node from the network. The returned promise resolves to true
if stopping the exclusion was successful, false
if it failed or if it was not active.
provisionSmartStartNode(entry: PlannedProvisioningEntry): void
Adds the given entry (DSK and security classes) to the controller's SmartStart provisioning list or replaces an existing entry. The node will be included out of band when it powers up.
If the protocol
field is set to Protocols.ZWaveLongRange
, the node will be included using Z-Wave Long Range instead of Z-Wave Classic.
[!ATTENTION] This method will throw when SmartStart is not supported by the controller!
The parameter has the following shape:
interface PlannedProvisioningEntry {
/**
* The status of this provisioning entry, which is assumed to be active by default.
* Inactive entries do not get included automatically.
*/
status?: ProvisioningEntryStatus;
/** The device specific key (DSK) in the form aaaaa-bbbbb-ccccc-ddddd-eeeee-fffff-11111-22222 */
dsk: string;
/** Which protocol to use for inclusion. Default: Z-Wave Classic */
protocol?: Protocols;
/**
* The protocols that are **supported** by the device.
* When this is not set, applications should default to Z-Wave classic.
*/
supportedProtocols?: readonly Protocols[];
/** The security classes that have been **granted** by the user */
securityClasses: SecurityClass[];
/**
* The security classes that were **requested** by the device.
* When this is not set, applications should default to {@link securityClasses} instead.
*/
requestedSecurityClasses?: readonly SecurityClass[];
/**
* Additional properties to be stored in this provisioning entry, e.g. the device ID from a scanned QR code
*/
[prop: string]: any;
}
[!NOTE] This method accepts a
QRProvisioningInformation
which is returned byparseQRCodeString
. You just need to make sure that the QR code is aSmartStart
QR code by checking theversion
field.
unprovisionSmartStartNode(dskOrNodeId: string | number): void
Removes the given DSK or node ID from the controller's SmartStart provisioning list.
[!NOTE] If this entry corresponds to an already-included node, it will NOT be excluded.
getProvisioningEntry(dsk: string): SmartStartProvisioningEntry | undefined
Returns the entry for the given DSK from the controller's SmartStart provisioning list. The returned entry (if found) has the following shape:
interface SmartStartProvisioningEntry {
/** The device specific key (DSK) in the form aaaaa-bbbbb-ccccc-ddddd-eeeee-fffff-11111-22222 */
dsk: string;
securityClasses: SecurityClass[];
nodeId?: number;
/**
* Additional properties to be stored in this provisioning entry, e.g. the device ID from a scanned QR code
*/
[prop: string]: any;
}
The nodeId
will be set when the entry corresponds to an included node.
getProvisioningEntries(): SmartStartProvisioningEntry[]
Returns all entries from the controller's SmartStart provisioning list.
async getNodeNeighbors(nodeId: number): Promise<readonly number[]>
Returns the known list of neighbors for a node.
[!ATTENTION] Especially older Z-Wave sticks can get stuck if you call this too often while the Z-Wave radio is still on.
To get around this:
- Turn the radio off with
controller.toggleRF(false)
- Batch all
getNodeNeighbors
requests together - Turn the radio back on with
controller.toggleRF(true
)
The routing table of the controller is stored in its memory and not easily accessible during normal operation. Z-Wave JS gets around this by keeping statistics for each node that include the last used routes, the used repeaters, protocol and speed, as well as RSSI readings. This information can be read using
getKnownLifelineRoutes(): ReadonlyMap<number, LifelineRoutes>
This has some limitations:
- The information is dynamically built using TX status reports and may not be accurate at all times.
- It may not be available immediately after startup or at all if the controller doesn't support this feature.
- It only includes information about the routes between the controller and nodes, not between individual nodes.
[!NOTE] To keep information returned by this method updated, subscribe to each node's
"statistics"
event and use the included information.
The returned objects have the following shape:
interface LifelineRoutes {
/** The last working route from the controller to this node. */
lwr?: RouteStatistics;
/** The next to last working route from the controller to this node. */
nlwr?: RouteStatistics;
}
interface RouteStatistics {
/** The protocol and used data rate for this route */
protocolDataRate?: ProtocolDataRate;
/** Which nodes are repeaters for this route */
repeaters: number[];
/** The RSSI of the ACK frame received by the controller */
rssi?: RSSI;
/**
* The RSSI of the ACK frame received by each repeater.
* If this is set, it has the same length as the repeaters array.
*/
repeaterRSSI?: RSSI[];
/**
* The node IDs of the nodes between which the transmission failed most recently.
* Is only set if there recently was a transmission failure.
*/
routeFailedBetween?: [number, number];
}
enum ProtocolDataRate {
ZWave_9k6 = 0x01,
ZWave_40k = 0x02,
ZWave_100k = 0x03,
LongRange_100k = 0x04,
}
While Z-Wave meshes have the ability to heal themselves - at least for somewhat modern devices - the routing algorithm tends to stick to routes that work, even if those are not optimal. In an ideal situation, nodes get assigned multiple good routes upon inclusion, so this is usually not an issue.
However, when physically moving devices, the optimal routes are likely to change. In this case, it can make sense to assign them new routes to the controller and association targets. This can be done for individual nodes or the whole network.
[!NOTE] Contrary to popular belief, this process does not magically make the mesh better. If devices have a physically bad connection, assigning new routes will not help. In fact, it can make the situation worse by deleting routes that were found to be working and assigning other bad routes.
In this case, checking the network health and acting upon the results should be preferred.
[!ATTENTION] Rebuilding routes for a Z-Wave network causes a lot of traffic and can take very long. Degraded performance must be expected while this process is active.
async rebuildNodeRoutes(nodeId: number): Promise<boolean>
Rebuilds routes for a single alive node in the network, updating the neighbor list and assigning fresh routes to association targets. The returned promise resolves to true
if the process was completed, or false
if it was unsuccessful.
[!ATTENTION] Rebuilding routes for a single node will delete existing priority return routes to end nodes and the SUC. It is recommended to first check if priority return routes are known to exist using
getPriorityReturnRoutesCached
andgetPrioritySUCReturnRouteCached
and asking for confirmation before proceeding.
beginRebuildingRoutes(options?: RebuildRoutesOptions): boolean
Starts the process of rebuilding routes for all alive nodes in the network. Returns true
if the process was started, otherwise false
. Also returns false
if the process was already active.
The application will be notified about the progress with the following events:
"rebuild routes progress"
: The route rebuilding progress has changed. See details."rebuild routes done"
: The route rebuilding process for all nodes was completed (or failed). See details.
The options
argument can be used to skip sleeping nodes:
interface RebuildRoutesOptions {
/** Whether the routes of sleeping nodes should be rebuilt too at the end of the process. Default: true */
includeSleeping?: boolean;
/** Whether nodes with priority return routes should be included, as those will be deleted. Default: false */
deletePriorityReturnRoutes?: boolean;
}
stopRebuildingRoutes(): boolean
Stops the route rebuilding process. Returns true
if the process was stopped or no process was active, otherwise false
.
isFailedNode(nodeId: number): Promise<boolean>
Checks if a node was marked as failed in the controller. If it is, it can be removed from the network with removeFailedNode
.
removeFailedNode(nodeId: number): Promise<void>
Removes a failed node from the controller's memory. If the process fails, this will throw an exception with the details why.
replaceFailedNode(nodeId: number, options: ReplaceNodeOptions): Promise<boolean>
Removes a failed node from the controller's memory and starts an inclusion process to include a replacement node which will re-use the same node ID.
This method returns true
when the inclusion process is started, false
if another inclusion or exclusion process is already running. If the process fails, this will throw an exception with the details why.
Like beginInclusion
, this method supports different inclusion strategies for the new node. However, the user or application must decide beforehand which security CC should be used to include the new node, since it is not possible to detect automatically. For that reason, only the inclusion strategies Security_S2
, Security_S0
and Insecure
are supported:
type ReplaceNodeOptions =
// We don't know which security CCs a node supports when it is a replacement
// we we need the user to specify how the node should be included
| {
strategy: InclusionStrategy.Security_S2;
userCallbacks: InclusionUserCallbacks;
}
| {
strategy: InclusionStrategy.Security_S2;
provisioning: PlannedProvisioningEntry;
}
| {
strategy:
| InclusionStrategy.Insecure
| InclusionStrategy.Security_S0;
};
The methods shown here can be used to manage routes between nodes. For the most part, these are not particularly relevant for applications or even end users, since they are used automatically by Z-Wave JS when necessary. Routes assigned by these methods are determined by the controller, which should be preferred usually.
assignReturnRoutes(nodeId: number, destinationNodeId: number): Promise<boolean>;
deleteReturnRoutes(nodeId: number): Promise<boolean>;
assignSUCReturnRoutes(nodeId: number): Promise<boolean>;
deleteSUCReturnRoutes(nodeId: number): Promise<boolean>;
assignReturnRoutes
instructs the controller to assign nodenodeId
a set of routes to nodedestinationNodeId
.deleteReturnRoutes
instructs nodenodeId
to delete all previously assigned routes.assignSUCReturnRoutes
works likeassignReturnRoutes
, but the routes have the SUC as the destination.deleteSUCReturnRoutes
works likedeleteReturnRoutes
, but for routes that have the SUC as the destination.
[!NOTE] These routes cannot be read back, since they are managed internally by the controller and no API exists to query them.
In certain scenarios, the routing algorithm of Z-Wave can break down and produce subpar results. It is possible to manually assign priority routes which will always be attempted first before resorting to the automatically determined routes.
[!WARNING] While these methods are meant to improve the routing and latency in certain situations, they can easily make things worse by choosing the wrong or unreachable repeaters, or by selecting a route speed that is not supported by a node in the route.
Typically you'll want to use these methods to force a direct connection as the first attempt.
The following methods control which route is used for the first transmission attempt from the controller to the given node.
setPriorityRoute(
destinationNodeId: number,
repeaters: number[],
routeSpeed: ZWaveDataRate,
): Promise<boolean>
getPriorityRoute(destinationNodeId: number): Promise<
| {
routeKind:
| RouteKind.LWR
| RouteKind.NLWR
| RouteKind.Application;
repeaters: number[];
routeSpeed: ZWaveDataRate;
}
| undefined
>;
removePriorityRoute(destinationNodeId: number): Promise<boolean>;
setPriorityRoute
sets the priority route which will always be used for the first transmission attempt from the controller to the given node.getPriorityRoute
returns the priority route to the given node, which can be:undefined
if there is no route at all,- the priority route if it exists,
- otherwise the LWR/NLWR
routeKind
identifies which kind of route is returned by getPriorityRoute
(None
is only used internally):
enum RouteKind {
None = 0x00,
/** Last Working Route */
LWR = 0x01,
/** Next to Last Working Route */
NLWR = 0x02,
/** Application-defined priority route */
Application = 0x10,
}
The repeaters
array contains the node IDs of the repeaters (max. 4) that should be used for the route. An empty array means a direct connection.
routeSpeed
is the transmission speed to be used for the route. Make sure that all nodes in the route support this speed.
enum ZWaveDataRate {
"9k6" = 0x01,
"40k" = 0x02,
"100k" = 0x03,
}
To control which routes a node will use for the first attempt, use the following methods:
assignPriorityReturnRoute(
nodeId: number,
destinationNodeId: number,
repeaters: number[],
routeSpeed: ZWaveDataRate,
): Promise<boolean>;
assignPrioritySUCReturnRoute(
nodeId: number,
repeaters: number[],
routeSpeed: ZWaveDataRate,
): Promise<boolean>
assignPriorityReturnRoute
sets the priority route from nodenodeId
to the destination node.assignPrioritySUCReturnRoute
does the same, but with the SUC (controller) as the destination node.
These methods also assign up to 3 fallback routes, which are chosen automatically by the controller.
[!WARNING] It has been found that assigning return routes to nodes that already have a priority route can cause the priority route to be changed unexpectedly. To avoid this, assigning priority routes should be done last. Otherwise, call
deleteReturnRoutes
ordeleteSUCReturnRoutes
(for routes to the controller) before assigning new routes. Unfortunately,deleteReturnRoutes
deletes all return routes to all destination nodes, so they all have to be set up again afterwards.
As mentioned before, there is unfortunately no way to query return routes from a node. To remedy this, Z-Wave JS caches the routes it has assigned. To read them, use the following methods:
getPriorityReturnRouteCached(nodeId: number, destinationNodeId: number): MaybeUnknown<Route> | undefined;
getPriorityReturnRoutesCached(nodeId: number): Record<number, Route>;
getPrioritySUCReturnRouteCached(nodeId: number): MaybeUnknown<Route> | undefined;
getPriorityReturnRouteCached
returns a priority return route that was set usingassignPriorityReturnRoute
. If a non-priority return route has been set since assigning the priority route, this will returnUNKNOWN_STATE
(null
).getPriorityReturnRoutesCached
returns an object containing the IDs of all known end node destinations a node has priority return routes for and their respective routes.getPrioritySUCReturnRouteCached
does the same for a route set throughassignPrioritySUCReturnRoute
.
The return type Route
has the following shape:
interface Route {
repeaters: number[];
routeSpeed: ZWaveDataRate;
}
[!NOTE] When another controller also manages routes in a network, the cached information is not guaranteed to be up to date. In this case, use the methods above to set the routes again or clear them.
As a last resort, the routes uses by a node can entirely be assigned manually. This uses the Z-Wave Protocol
command class, which is used internally by the controller and Z-Wave protocol, so this should at least be considered an unofficial way to set return routes.
Up to 4 routes for each combination of source and destination node can be set. If less routes are given, the remaining ones will be cleared. Optionally, a priority route can be set, which will always be used for the first transmission attempt. Up to 3 of the other routes will then be used as fallbacks, but no automatically determined routes will be used.
Note that the same caveats as above in regards to deleting priority non-SUC return routes apply.
assignCustomReturnRoutes(
nodeId: number,
destinationNodeId: number,
routes: Route[],
priorityRoute?: Route
): Promise<boolean>;
assignCustomSUCReturnRoutes(
nodeId: number,
routes: Route[],
priorityRoute?: Route
): Promise<boolean>;
assignCustomReturnRoutes
assigns nodenodeId
a set of routes to nodedestinationNodeId
.assignCustomSUCReturnRoutes
does the same, but with the SUC as the destination.
Z-Wave JS caches manually assigned routes, so they can be read back:
getCustomReturnRoutesCached(nodeId: number, destinationNodeId: number): Route[] | undefined;
getCustomSUCReturnRoutesCached(nodeId: number, destinationNodeId: number): Route[] | undefined;
getCustomReturnRoutesCached
returns routes that were was set usingassignCustomReturnRoutes
.getCustomSUCReturnRoutesCached
returns routes that were was set usingassignCustomSUCReturnRoutes
.
To read priority routes assigned using the optional priorityRoute
parameter, use getPriorityReturnRouteCached
and getPrioritySUCReturnRouteCached
as described above.
[!ATTENTION] When another controller also manages routes in a network, the cached information is not guaranteed to be up to date. In this case, use the methods above to set the routes again or clear them.
The following methods can be used to manage associations between nodes and/or endpoints. This only works AFTER the interview process!
getAssociationGroups(source: AssociationAddress): ReadonlyMap<number, AssociationGroup>;
getAllAssociationGroups(nodeId: number): ReadonlyMap<number, ReadonlyMap<number, AssociationGroup>>;
getAssociations(source: AssociationAddress): ReadonlyMap<number, readonly AssociationAddress[]>;
getAllAssociations(nodeId: number): ReadonlyObjectKeyMap<
AssociationAddress,
ReadonlyMap<number, readonly AssociationAddress[]>
>;
checkAssociation(source: AssociationAddress, group: number, destination: AssociationAddress): AssociationCheckResult;
addAssociations(source: AssociationAddress, group: number, destinations: AssociationAddress[]): Promise<void>;
removeAssociations(source: AssociationAddress, group: number, destinations: AssociationAddress[]): Promise<void>;
removeNodeFromAllAssociations(nodeId: number): Promise<void>;
getAssociationGroups
returns all association groups for a given node or endpoint.getAllAssociationGroups
returns all association groups of a given node and all its endpoints. The returnedMap
uses the endpoint index as keys and its values areMap
s of group IDs to their definitiongetAssociations
returns all defined associations of a given node or endpoint. If no endpoint is given, the associations for the root endpoint (0
) are returned.getAllAssociations
returns all defined associations of a given node and all its endpoints. The returnedMap
uses the source node+endpoint as keys and its values areMap
s of association group IDs to target node+endpoint.addAssociations
can be used to add one or more associations to a node's or endpoint's group. You should check if each association is allowed usingcheckAssociation
before doing so.- To remove a previously added association, use
removeAssociations
- A node can be removed from all other nodes' associations using
removeNodeFromAllAssociations
Contains information about a single association group.
interface AssociationGroup {
/** How many nodes this association group supports */
maxNodes: number;
/** Whether this is the lifeline association (where the Controller must not be removed) */
isLifeline: boolean;
/** Whether multi channel associations are allowed */
multiChannel: boolean;
/** The name of the group */
label: string;
/** The association group profile (if known) */
profile?: AssociationGroupInfoProfile;
/** A map of Command Classes and commands issued by this group (if known) */
issuedCommands?: ReadonlyMap<CommandClasses, readonly number[]>;
}
This defines the source and target node/endpoint of an association:
interface AssociationAddress {
nodeId: number;
endpoint?: number;
}
If the target endpoint is not given, the association is a "node association". If an endpoint is given, the association is an "endpoint association".
A target endpoint of 0
(i.e. the root endpoint), the association targets the node itself and acts like a node association for the target node. However, you should note that some devices don't like having a root endpoint association as the lifeline and must be configured with a node association.
This tells you whether an association is allowed, and if not, why:
enum AssociationCheckResult {
OK = 0x01,
/** The association is forbidden, because the destination is a ZWLR node. ZWLR does not support direct communication between end devices. */
Forbidden_DestinationIsLongRange,
/** The association is forbidden, because the source is a ZWLR node. ZWLR does not support direct communication between end devices. */
Forbidden_SourceIsLongRange,
/** The association is forbidden, because a node cannot be associated with itself. */
Forbidden_SelfAssociation,
/** The association is forbidden, because the source node's CC versions require the source and destination node to have the same (highest) security class. */
Forbidden_SecurityClassMismatch,
/** The association is forbidden, because the source node's CC versions require the source node to have the key for the destination node's highest security class. */
Forbidden_DestinationSecurityClassNotGranted,
/** The association is forbidden, because none of the CCs the source node sends are supported by the destination. */
Forbidden_NoSupportedCCs,
}
When controlling multiple nodes, a "waterfall" effect can often be observed, because nodes get the commands after another. This can be avoided by using multicast or broadcast, which sends commands to multiple/all nodes at once.
Note
Multicast does NOT reduce the number of messages sent, but it can eliminate the waterfall effect when targeting many nodes. All multicasts are followed up by singlecast messages to the individual nodes. This makes sure that all nodes got the command, and is necessary to make secure (S2) multicast work at all.
There are some caveats when secure nodes are involved:
- Nodes that are included via
Security S0
can only be controlled using singlecast. - When controlling nodes with mixed security classes, each group of nodes will automatically be targeted individually. It is not possible to send a single command that both secure and insecure nodes will understand.
Note
Virtual nodes do not support all methods that physical nodes do. Check VirtualNode
for details on the available methods and properties.
getMulticastGroup(nodeIDs: number[]): VirtualNode
Creates a virtual node that can be used to send commands to multiple supporting nodes with as few multicast messages as possible. Nodes are grouped by security class automatically, and get ignored if they cannot be controlled via multicast. You can target individual endpoints as usual.
Note
This may actually send broadcast frames, since it has been found that some (all?) devices interpret S2 multicast frames as the S2 singlecast followup, causing them to respond incorrectly.
getBroadcastNode(): VirtualNode
Returns a reference to the (virtual) Z-Wave Classic broadcast node. This can be used to send a command to all Z-Wave Classic nodes in the network with a single command. You can target individual endpoints as usual.
Note
When the network contains Z-Wave Classic devices with mixed security classes, this will do the same as getMulticastGroup
instead and send multiple commands.
getBroadcastNodeLR(): VirtualNode
Returns a reference to the (virtual) Z-Wave LR broadcast node. This can be used to send a command to all Z-Wave LR nodes in the network with a single command. You can target individual endpoints as usual.
Note
When the network contains Z-Wave LR devices with mixed security classes, this will do the same as getMulticastGroup
instead and send multiple commands.
readonly rfRegion: MaybeNotKnown<RFRegion>
Which RF region the controller is currently set to, or undefined
if it could not be determined (yet). This value is cached and can be changed through the following API.
setRFRegion(region: RFRegion): Promise<boolean>
getRFRegion(): Promise<RFRegion>
Configure or read the RF region from the Z-Wave API Module. The possible regions are:
export enum RFRegion {
"Europe" = 0x00,
"USA" = 0x01,
"Australia/New Zealand" = 0x02,
"Hong Kong" = 0x03,
"India" = 0x05,
"Israel" = 0x06,
"Russia" = 0x07,
"China" = 0x08,
"USA (Long Range)" = 0x09,
"Japan" = 0x20,
"Korea" = 0x21,
"Unknown" = 0xfe,
"Default (EU)" = 0xff,
}
[!NOTE] Long Range capable regions are automatically preferred over their non-LR counterparts. This behavior can be disabled by setting the driver option
rf.preferLRRegion
tofalse
.
[!ATTENTION] Not all controllers support configuring the RF region. These methods will throw if they are not supported
To determine which regions are supported by the current controller, use the following method:
getSupportedRFRegions(filterSubsets: boolean): MaybeNotKnown<readonly RFRegion[]>
The filterSubsets
parameter (true
by default) can be used to filter out regions that are subsets of other supported regions. For example, if the controller supports both USA
and USA (Long Range)
, only USA (Long Range)
will be returned, since it includes the USA
region.
setPowerlevel(powerlevel: number, measured0dBm: number): Promise<boolean>;
getPowerlevel(): Promise<{powerlevel: number, measured0dBm: number}>;
Configure or read the TX powerlevel setting for Z-Wave Classic. powerlevel
is the normal powerlevel, measured0dBm
the measured output power at 0 dBm and serves as a calibration. Both are in dBm and must satisfy the following constraints:
powerlevel
between-10
and either+12.7
,+14
or+20
dBm (depending on the controller)measured0dBm
between-10
and+10
or between-12.8
and+12.7
dBm (depending on the controller)
Unfortunately there doesn't seem to be a way to determine which constrains apply for a given controller.
[!ATTENTION] Not all controllers support configuring the TX powerlevel. These methods will throw if they are not supported.
[!WARNING] Increasing the powerlevel (i.e. "shouting louder") does not improve reception of the controller and may even be against the law. Use at your own risk!
readonly maxLongRangePowerlevel: MaybeNotKnown<number>;
The maximum powerlevel to use for Z-Wave Long Range, or undefined
if it could not be determined (yet). This value is cached and can be changed through the following API.
setMaxLongRangePowerlevel(limit: number): Promise<boolean>;
getMaxLongRangePowerlevel(): Promise<number>;
Z-Wave Long Range dynamically adjusts its transmit power. This API is used to configure or read the maximum TX power to use for this. The value is in dBm and must be between -10.0
and +14.0
or +20.0
, depending on the controller hardware.
readonly longRangeChannel: MaybeNotKnown<LongRangeChannel>;
readonly supportsLongRangeAutoChannelSelection: MaybeNotKnown<boolean>
The channel to use for Z-Wave Long Range, whether automatic channel selection is supported by the controller, or undefined
if this information could not be determined (yet). These values are cached. The channel can changed through the following API.
setLongRangeChannel(
channel:
| LongRangeChannel.A
| LongRangeChannel.B
| LongRangeChannel.Auto,
): Promise<boolean>;
getLongRangeChannel(): Promise<{
channel: LongRangeChannel;
supportsAutoChannelSelection: boolean
}>;
Request the channel setting and capabilities for Z-Wave Long Range. The following channels exist:
enum LongRangeChannel {
/** Indicates that Long Range is not supported by the currently set RF region */
Unsupported = 0x00,
A = 0x01,
B = 0x02,
/** Z-Wave Long Range Channel automatically selected by the Z-Wave algorithm */
Auto = 0xff,
}
[!NOTE]
supportsAutoChannelSelection
indicates whether the controller supports automatic channel selection.LongRangeChannel.Auto
is only allowed if supported.
toggleRF(enabled: boolean): Promise<boolean>
When accessing the controller memory, the Z-Wave radio must be turned off with toggleRF(false)
to avoid resource conflicts and inconsistent data. Afterwards the radio can be turned back on with toggleRF(true)
.
This method returns true
when turning the radio on or off succeeded, false
otherwise.
[!WARNING] The Z-Wave radio must be turned off when accessing the NVM.
getNVMId(): Promise<NVMId>
Returns information of the controller's external NVM. The return value has the following shape:
interface NVMId {
readonly nvmManufacturerId: number;
readonly memoryType: NVMType;
readonly memorySize: NVMSize;
}
externalNVMOpen(): Promise<number>
Before reading or writing to a 700 series NVM, it must be opened using this method, which also returns the accessible NVM size in bytes.
[!NOTE] The first access determines whether the NVM can be written to or read from. To change the access method, close and re-open the NVM.
externalNVMClose(): Promise<void>
externalNVMReadByte(offset: number): Promise<number>
Reads a byte from the external NVM at the given offset.
externalNVMReadBuffer(offset: number, length: number): Promise<Buffer>
Reads a buffer from the external NVM at the given offset. The returned buffer length is limited by the Serial API capabilities and not guaranteed to equal length
.
externalNVMReadBuffer700(offset: number, length: number): Promise<{ buffer: Buffer; endOfFile: boolean }>
Reads a buffer from the external NVM at the given offset. The returned buffer
length is limited by the Serial API capabilities and not guaranteed to equal length
.
If endOfFile
is true
, the end of the NVM has been reached and the NVM should be closed with a call to externalNVMClose
.
externalNVMWriteByte(offset: number, data: number): Promise<boolean>
Writes a byte to the external NVM at the given offset
externalNVMWriteBuffer(offset: number, buffer: Buffer): Promise<boolean>
Writes a buffer to the external NVM at the given offset.
[!WARNING] These methods can write in the full NVM address space and are not offset to start at the application area. Take care not to accidentally overwrite the protocol NVM area!
externalNVMWriteBuffer700(offset: number, buffer: Buffer): Promise<boolean>
Writes a buffer to the external NVM at the given offset. If endOfFile
is true
, the end of the NVM has been reached and the NVM should be closed with a call to externalNVMClose
.
[!WARNING] This method can write in the full NVM address space and are not offset to start at the application area. Take care not to accidentally overwrite the protocol NVM area!
backupNVMRaw(onProgress?: (bytesRead: number, total: number) => void): Promise<Buffer>
Creates a backup of the NVM and returns the raw data as a Buffer. The optional argument can be used to monitor the progress of the operation, which may take several seconds up to a few minutes depending on the NVM size.
[!NOTE]
backupNVMRaw
automatically turns the Z-Wave radio on/off during the backup.
restoreNVM(
nvmData: Buffer,
convertProgress?: (bytesRead: number, total: number) => void,
restoreProgress?: (bytesWritten: number, total: number) => void,
): Promise<void>
Restores an NVM backup that was created with backupNVMRaw
.
?> If the given buffer is in a different NVM format, it is converted automatically. If the conversion is not supported, the operation fails.
The optional convertProgress
and restoreProgress
callbacks can be used to monitor the progress of the operation, which may take several seconds up to a few minutes depending on the NVM size.
[!NOTE]
restoreNVM
automatically turns the Z-Wave radio on/off during the restore.
[!WARNING] A failure during this process may brick your controller. Use at your own risk!
restoreNVMRaw(nvmData: Buffer, onProgress?: (bytesWritten: number, total: number) => void): Promise<void>
Restores an NVM backup that was created with backupNVMRaw
. The optional 2nd argument can be used to monitor the progress of the operation, which may take several seconds up to a few minutes depending on the NVM size.
[!NOTE]
restoreNVMRaw
automatically turns the Z-Wave radio on/off during the restore.
[!WARNING] The given buffer is NOT checked for compatibility with the current stick. To have Z-Wave JS do that, use the
restoreNVM
method instead.
[!WARNING] A failure during this process may brick your controller. Use at your own risk!
Note
This section describes updating the firmware of a node using the Z-Wave JS firmware update service. If you want to update the firmware of a node using a file, see ZWaveNode.updateFirmware
.
getAvailableFirmwareUpdates(nodeId: number, options?: GetFirmwareUpdatesOptions): Promise<FirmwareUpdateInfo[]>
Retrieves the available firmware updates for the given node from the Z-Wave JS firmware update service. The following options are available to control the behavior:
interface GetFirmwareUpdatesOptions {
/** Allows overriding the API key for the firmware update service */
apiKey?: string;
/** Allows adding new components to the user agent sent to the firmware update service (existing components cannot be overwritten) */
additionalUserAgentComponents?: Record<string, string>;
/** Whether the returned firmware upgrades should include prereleases from the `"beta"` channel. Default: `false`. */
includePrereleases?: boolean;
}
This method returns an array with all available firmware updates for the given node. The entries of the array have the following form:
type FirmwareUpdateInfo = {
device: FirmwareUpdateDeviceID;
version: string;
changelog: string;
channel: "stable" | "beta";
files: FirmwareUpdateFileInfo[];
downgrade: boolean;
normalizedVersion: string;
};
where the device
field stores which device the update is for,
interface FirmwareUpdateDeviceID {
manufacturerId: number;
productType: number;
productId: number;
firmwareVersion: string;
rfRegion?: RFRegion;
}
and each entry in files
looks like this:
interface FirmwareUpdateFileInfo {
target: number;
url: string;
integrity: `sha256:${string}`;
}
The version
and changelog
properties are meant to be presented to the user prior to choosing an update.
The fields downgrade
and normalizedVersion
are meant for applications to filter and sort the updates.
In addition, the channel
property indicates which release channel an upgrade is from:
"stable"
: Production-ready, well-tested firmwares."beta"
: Beta or pre-release firmwares. This channel is supposed to contain firmwares that are stable enough for a wide audience to test, but may still contain bugs.
Many Z-Wave devices only have a single upgradeable firmware target (chip), so the files
array will usually contain a single entry. If there are more, the entries must be applied in the order they are defined.
[!WARNING] This method does not rely on cached data to identify a node, so sleeping nodes need to be woken up for this to work. If a sleeping node is not woken up within a minute after calling this, the method will throw. You can schedule the check when a node wakes up using the
waitForWakeup
method.
[!NOTE] Calling this will result in an HTTP request to the firmware update service at https://firmware.zwave-js.io
This method requires an API key to be set in the driver options under apiKeys
. Refer to https://github.com/zwave-js/firmware-updates/ to request a key (free for open source projects and non-commercial use). The API key can also be passed via the options
argument:
interface GetFirmwareUpdatesOptions {
/** Allows overriding the API key for the firmware update service */
apiKey?: string;
/** Allows adding new components to the user agent sent to the firmware update service (existing components cannot be overwritten) */
additionalUserAgentComponents?: Record<string, string>;
/** Whether the returned firmware upgrades should include prereleases from the `"beta"` channel. Default: `false`. */
includePrereleases?: boolean;
}
firmwareUpdateOTA(nodeId: number, updateInfo: FirmwareUpdateInfo): Promise<FirmwareUpdateResult>
[!WARNING] We don't take any responsibility if devices upgraded using Z-Wave JS don't work afterwards. Although there are security measures in place, always double-check that the correct update is about to be installed.
Downloads the desired firmware updates from the Z-Wave JS firmware update service and performs an over-the-air (OTA) firmware update for the given node. This is very similar to ZWaveNode.updateFirmware
, except that the updates are officially provided by manufacturers and downloaded in the background.
To keep track of the update progress, use the "firmware update progress"
and "firmware update finished"
events of the corresponding node.
The return value indicates whether the update was successful and includes some additional information. This is the same information that is emitted using the "firmware update finished"
event.
[!NOTE] Calling this will result in an HTTP request to the URLs referenced in the
updateInfo
parameter.
isAnyOTAFirmwareUpdateInProgress(): boolean;
Returns whether an OTA firmware update is in progress for any node.
firmwareUpdateOTW(data: Buffer): Promise<ControllerFirmwareUpdateResult>
[!WARNING] We don't take any responsibility if devices upgraded using Z-Wave JS don't work after an update. Always double-check that the correct update is about to be installed.
Performs an over-the-wire (OTW) firmware update for the controller using the given firmware image. To do so, the controller gets put in bootloader mode where a new firmware image can be uploaded.
[!WARNING] A failure during this process may leave your controller in recovery mode, rendering it unusable until a correct firmware image is uploaded.
To keep track of the update progress, use the "firmware update progress"
and "firmware update finished"
events of the controller.
The return value indicates whether the update was successful and includes an error code that can be used to determine the reason for a failure. This is the same information that is emitted using the "firmware update finished"
event:
interface ControllerFirmwareUpdateResult {
success: boolean;
status: ControllerFirmwareUpdateStatus;
}
isFirmwareUpdateInProgress(): boolean;
Return whether a firmware update is in progress for the controller.
Aside from managing its own network, Z-Wave JS can also become a secondary controller and join an existing network. This is done with the following APIs:
beginJoiningNetwork(options?: JoinNetworkOptions): Promise<JoinNetworkResult>
Starts the process to join another network. The result indicates whether the process was started or if there was an error:
enum JoinNetworkResult {
/** The process to join the network was started successfully */
OK,
/** Another join/leave process is already in progress. */
Error_Busy,
/** Joining another network is not permitted due to the controller's network role */
Error_NotPermitted,
/** There was an unknown error while joining the network */
Error_Failed,
}
The progress will be reported through the "network found"
, "network joined"
, and/or "joining network failed"
events.
The options parameter is used to specify the joining strategy and provide callbacks to the application which may be necessary to support joining with Security S2. Currently, only one strategy is defined:
JoinStrategy.Default
: Leave the choice of encryption (Security S2, Security S0 or no encryption) up to the including controller. This is the default when no options are specified.
Depending on the chosen inclusion strategy, the options object requires additional properties:
type JoinNetworkOptions = {
strategy: JoinNetworkStrategy.Default;
/**
* Allows overriding the user callbacks for this attempt at joining a network.
* If not given, the join network user callbacks of the driver options will be used.
*/
userCallbacks?: JoinNetworkUserCallbacks;
};
For joining with Security S2, callbacks into the application should be defined as part of the driver options (joinNetworkUserCallbacks
). They can optionally be overridden for individual inclusion attempts by setting the userCallbacks
property in the JoinNetworkOptions
.
[!ATTENTION] If the callbacks are not defined, the application should have an appropriate way of displaying the controller's DSK to the user to enable joining with
S2 Authenticated
andS2 Access Control
. The DSK can be read using thedsk
property.
The callbacks are defined as follows:
interface JoinNetworkUserCallbacks {
/**
* Instruct the application to display the controller's DSK so the user can enter it in the including controller's UI.
* @param dsk The partial DSK in the form `aaaaa-bbbbb-ccccc-ddddd-eeeee-fffff-11111-22222`
*/
showDSK(dsk: string): void;
/**
* Called by the driver when the DSK has been verified, or the bootstrapping has timed out, and user interaction is no longer necessary.
* The application should hide any prompts created by joining a network.
*/
done(): void;
}
async stopJoiningNetwork(): Promise<boolean>
Stops the process to join a network. The returned promise resolves to true
if stopping was successful, false
if it failed or if it was not active.
async beginLeavingNetwork(): Promise<LeaveNetworkResult>
Starts the process to leave the current network. The result indicates whether the process was started or if there was an error:
enum LeaveNetworkResult {
/** The process to leave the network was started successfully */
OK,
/** Another join/leave process is already in progress. */
Error_Busy,
/** Leaving the network is not permitted due to the controller's network role */
Error_NotPermitted,
/** There was an unknown error while leaving the network */
Error_Failed,
}
The progress will be reported through the "network left"
or "leaving network failed"
events.
async stopLeavingNetwork(): Promise<boolean>
Stops the process to leave the current network. The returned promise resolves to true
if stopping was successful, false
if it failed or if it was not active.
readonly nodes: ReadonlyMap<number, ZWaveNode>
This property contains a map of all nodes that you can access by their node ID, e.g. nodes.get(2)
for node 2.
readonly sdkVersion: string
Returns the Z-Wave SDK version that is supported by the controller hardware.
Warning
This property is only defined after the controller interview!
readonly type: ZWaveLibraryTypes
Returns the type of the Z-Wave library that is supported by the controller hardware. The following values are defined, although only "Static Controller"
or "Bridge Controller"
will realistically be possible:
enum ZWaveLibraryTypes {
"Unknown",
"Static Controller",
"Controller",
"Enhanced Slave",
"Slave",
"Installer",
"Routing Slave",
"Bridge Controller",
"Device under Test",
"N/A",
"AV Remote",
"AV Device",
}
Warning
This property is only defined after the controller interview!
readonly homeId: number
A 32bit number identifying the current network.
Warning
This property is only defined after the controller interview!
readonly ownNodeId: number
Returns the ID of the controller in the current network.
Warning
This property is only defined after the controller interview!
dsk(): Buffer
Returns the controller's DSK in binary format.
readonly status: ControllerStatus
This property tracks the status of the controller. Valid values are:
enum ControllerStatus {
/** The controller is ready to accept commands and transmit */
Ready,
/** The controller is unresponsive */
Unresponsive,
/** The controller is unable to transmit */
Jammed,
}
The status is ControllerStatus.Ready
by default and should not change unless there is a problem with the controller. Changes to the status are exposed using the "status changed"
event.
readonly isRebuildingRoutes: boolean;
Returns whether the routes are currently being rebuilt for one or more nodes.
readonly rebuildRoutesProgress: ReadonlyMap<number, RebuildRoutesStatus> | undefined;
If routes are currently being rebuilt for the entire network, this returns the current progress as a map of each node's ID and its status.
readonly inclusionState: InclusionState
Returns the controller state regarding inclusion/exclusion.
enum InclusionState {
/** The controller isn't doing anything regarding inclusion. */
Idle,
/** The controller is waiting for a node to be included. */
Including,
/** The controller is waiting for a node to be excluded. */
Excluding,
/** The controller is busy including or excluding a node. */
Busy,
/** The controller listening for SmartStart nodes to announce themselves. */
SmartStart,
}
readonly rfRegion: RFRegion | undefined
Which RF region the controller is currently set to, or undefined
if it could not be determined (yet).
This value is cached and updated automatically when using getRFRegion
or setRFRegion
.
readonly supportsLongRange: MaybeNotKnown<boolean>;
Returns whether the controller supports the Z-Wave Long Range protocol. This depends on the configured RF region.
The Controller
class inherits from the Node.js EventEmitter and thus also supports its methods like on
, removeListener
, etc. The available events are available:
The process to include a node into the network was started successfully. The event handler has a parameter which indicates which inclusion strategy is used to include the node, and which can also be used to determine whether the inclusion is supposed to be secure.
(strategy: InclusionStrategy) => void
Note
Whether a node will actually be included securely may depend on the physical activation of the node. Some devices require a special activation sequence to be included securely. Please refer to the device manual for further information.
The process to exclude a node from the network was started successfully.
A node could not be included into or excluded from the network for some reason.
The process to include or exclude a node was stopped successfully. Note that these events are also emitted after a node was included or excluded.
The controller's inclusion state has changed. The new state is passed as an argument.
(state: InclusionState) => void
enum InclusionState {
/** The controller isn't doing anything regarding inclusion. */
Idle,
/** The controller is waiting for a node to be included. */
Including,
/** The controller is waiting for a node to be excluded. */
Excluding,
/** The controller is busy including or excluding a node. */
Busy,
/** The controller listening for SmartStart nodes to announce themselves. */
SmartStart,
}
A node has successfully been added to the network.
[!NOTE] At this point, the initial setup and the node interview is still pending, so the node is not yet operational.
(node: FoundNode) => void
interface FoundNode {
id: number;
deviceClass?: DeviceClass;
supportedCCs?: CommandClasses[];
controlledCCs?: CommandClasses[];
}
A node has successfully been added to the network and the initial setup was completed. After this event is emitted, a node is operational but not yet ready to be used until after the node interview.
(node: ZWaveNode, result: InclusionResult) => void
The second argument gives additional info about the inclusion result.
type InclusionResult =
| {
/** This flag warns that a node was included with a lower than intended security, meaning unencrypted when it should have been included with Security S0/S2 */
lowSecurity?: false;
}
| {
/** This flag warns that a node was included with a lower than intended security, meaning unencrypted when it should have been included with Security S0/S2 */
lowSecurity: true;
lowSecurityReason: SecurityBootstrapFailure;
};
If there was a failure during the inclusion, the lowSecurity
flag will be true
and the lowSecurityReason
property will contain additional information why.
enum SecurityBootstrapFailure {
/** Security bootstrapping was canceled by the user */
UserCanceled,
/** The required security keys were not configured in the driver */
NoKeysConfigured,
/** No Security S2 user callbacks (or provisioning info) were provided to grant security classes and/or validate the DSK. */
S2NoUserCallbacks,
/** An expected message was not received within the corresponding timeout */
Timeout,
/** There was no possible match in encryption parameters between the controller and the node */
ParameterMismatch,
/** Security bootstrapping was canceled by the included node */
NodeCanceled,
/** The PIN was incorrect, so the included node could not decode the key exchange commands */
S2IncorrectPIN,
/** There was a mismatch in security keys between the controller and the node */
S2WrongSecurityLevel,
/** The node has been bootstrapped using S0 in an S2-capable network */
S0Downgrade,
/** Some other unspecified error happened */
Unknown,
}
A node has successfully been replaced or removed from the network.
(node: ZWaveNode, reason: RemoveNodeReason) => void
The reason
argument indicates why the node was removed:
enum RemoveNodeReason {
/** The node was excluded by the user or an inclusion controller */
Excluded,
/** The node was excluded by an inclusion controller */
ProxyExcluded,
/** The node was removed using the "remove failed node" feature */
RemoveFailed,
/** The node was replaced using the "replace failed node" feature */
Replaced,
/** The node was replaced by an inclusion controller */
ProxyReplaced,
/** The node was reset locally and was auto-removed */
Reset,
/** SmartStart inclusion failed, and the node was auto-removed as a result. */
SmartStartFailed,
}
[!NOTE] To comply with the Z-Wave specifications, applications MUST indicate that the node was reset locally and has left the network when the
reason
isRemoveNodeReason.Reset
.
(status: ControllerStatus) => void;
This event is used to inform applications about changes in the controller status.
This event is used to inform listeners about the progress of an ongoing route rebuilding process. The progress is reported as a map of each node's ID and its status.
(progress: ReadonlyMap<number, RebuildRoutesStatus>) => void
The status is one of the following values:
"pending"
: The process for this node was not started yet"done"
: The process for this node is done"failed"
: There was an error while rebuilding routes for this node"skipped"
: The node was skipped because it is dead
The route rebuilding process for the network was completed. The event handler is called with the final status, see the "rebuild routes progress"
event for details
This event is emitted regularly during and after communication with the controller and gives some insight that would otherwise only be visible by looking at logs. The callback has the signature
(statistics: Readonly<ControllerStatistics>) => void
where the statistics are readonly and have the following shape:
interface ControllerStatistics {
/** No. of messages successfully sent to the controller */
messagesTX: number;
/** No. of messages received by the controller */
messagesRX: number;
/** No. of messages from the controller that were dropped by the host */
messagesDroppedRX: number;
/** No. of messages that the controller did not accept */
NAK: number;
/** No. of collisions while sending a message to the controller */
CAN: number;
/** No. of transmission attempts where an ACK was missing from the controller */
timeoutACK: number;
/** No. of transmission attempts where the controller response did not come in time */
timeoutResponse: number;
/** No. of transmission attempts where the controller callback did not come in time */
timeoutCallback: number;
/** No. of outgoing messages that were dropped because they could not be sent */
messagesDroppedTX: number;
/**
* Background RSSI of the network in dBm. These values are typically between -100 and -30, but can be even smaller (down to -128 dBm) in quiet environments.
*
* The `average` values are calculated using an exponential moving average.
* The `current` values are the most recent measurements, which can be compared to the average to detect interference/jamming.
* The `timestamp` is the time of the most recent update of these measurements, and can be used to draw graphs.
*/
backgroundRSSI?: {
timestamp: number;
channel0: {
average: number;
current: number;
};
channel1: {
average: number;
current: number;
};
channel2?: {
average: number;
current: number;
};
channel3?: {
average: number;
current: number;
};
};
}
(progress: ControllerFirmwareUpdateProgress) => void
Firmware update progress has been made. The callback arguments gives information about the progress of the update:
interface ControllerFirmwareUpdateProgress {
/** How many fragments of the firmware update have been transmitted. Together with `totalFragments` this can be used to display progress. */
sentFragments: number;
/** How many fragments the firmware update consists of. */
totalFragments: number;
/** The total progress of the firmware update in %, rounded to two digits. */
progress: number;
}
(result: ControllerFirmwareUpdateResult) => void;
The firmware update process is finished. The result
argument looks like this indicates whether the update was successful:
interface ControllerFirmwareUpdateResult {
success: boolean;
status: ControllerFirmwareUpdateStatus;
}
Its status
property contains more details on potential errors.
enum ControllerFirmwareUpdateStatus {
Error_Timeout = 0,
/** The maximum number of retry attempts for a firmware fragments were reached */
Error_RetryLimitReached,
/** The update was aborted by the bootloader */
Error_Aborted,
/** This controller does not support firmware updates */
Error_NotSupported,
OK = 0xff,
}
This is emitted when another node instructs Z-Wave JS to identify itself using the Indicator CC
, indicator ID 0x50
.
(node: ZWaveNode) => void
[!NOTE] Although support for this seems to be a certification requirement, it is currently unclear how this requirement must be fulfilled for controllers. The specification only refers to nodes: The node is RECOMMENDED to use a visible LED for an identify function if it has an LED. If the node is itself a light source, e.g. a light bulb, this MAY be used in place of a dedicated LED.
The event signature may be extended to accommodate this after clarification.
This is emitted while joining another network, as soon as the inclusion is successful.
(homeId: number, ownNodeId: number) => void
[!NOTE] Applications should wait before interacting with the network until the
"network joined"
event is received.
This is emitted after joining another network, once security bootstrapping is done or the network is joined without security.
This is emitted if joining another network failed. In this case, the "network found"
and "network joined"
events will not be emitted.
This is emitted after successfully leaving the current network.
This is emitted if leaving the current network failed. In this case, the "network left"
event will not be emitted.