node-zwave-js/docs/getting-started/migrating/v10.md

12 KiB

Migrating to v10

What started out as an attempt to improve the testing setup, resulted in a huge refactor of the entire code base.

The implementations of serial messages and Command Classes have been decoupled from the Driver, ZWaveNode and Endpoint classes and no longer store direct references to them. Instead, most of the implementations now operate on abstractions:

  • ZWaveHost - A barebones abstraction of the environment, e.g. for simple test cases
  • ZWaveApplicationHost - A feature abstraction of the host environment with access to value DBs, other nodes, configuration, etc. Driver is an implementation of this abstraction.
  • IZWaveEndpoint - A barebones abstraction of a Z-Wave endpoint
  • IZWaveNode - A barebones abstraction of a Z-Wave node. Similar to how ZWaveNode is an Endpoint, an IZWaveNode is an IZWaveEndpoint
  • IVirtualEndpoint - A barebones abstraction of an endpoint on a virtual (multicast, broadcast) node
  • IVirtualNode - A barebones abstraction of a virtual (multicast, broadcast) node. Similar to how VirtualNode is a VirtualEndpoint, an IVirtualNode is an IVirtualEndpoint

These abstractions are mainly used internally. Object instances exposed to applications through the Driver will still be ZWaveNodes and Endpoints.

For many use cases, these changes should not affect applications, unless they are using some CC methods directly. The commandClasses APIs are unchanged.

CC implementations: methods with driver access take a ZWaveApplicationHost as the first argument

Old signature:

public async interview(): Promise<void>;
public async refreshValues(): Promise<void>;
public persistValues(): boolean;
public toLogEntry(): MessageOrCCLogEntry;

public getDefinedValueIDs(): ValueID[];
public translateProperty(
	property: string | number,
	propertyKey?: string | number,
): string | undefined;
public translatePropertyKey(
	property: string | number,
	propertyKey?: string | number,
): string | undefined;

New signatures:

public async interview(applHost: ZWaveApplicationHost): Promise<void>;
public async refreshValues(applHost: ZWaveApplicationHost): Promise<void>;
public persistValues(applHost: ZWaveApplicationHost): boolean;
public toLogEntry(applHost: ZWaveApplicationHost): MessageOrCCLogEntry;

public getDefinedValueIDs(applHost: ZWaveApplicationHost): ValueID[];
public translateProperty(
	applHost: ZWaveApplicationHost,
	property: string | number,
	propertyKey?: string | number,
): string | undefined;
public translatePropertyKey(
	applHost: ZWaveApplicationHost,
	property: string | number,
	propertyKey?: string | number,
): string | undefined;

Simply pass the driver instance as the first argument whenever you call these methods.

Note: getDefinedValueIDs on the ZWaveNode class is not affected.

CC-specific methods to read certain values from cache are now static take additional arguments

Some CC implementations expose value-specific methods to read certain values from cache, for example getNumValvesCached on the Irrigation CC. Previously some of those were protected, some were public. Now all of them are public, static on the CC base class, take additional arguments and include undefined in the return type:

Old signature:

protected getNumValvesCached(): number;

New signature:

public static getNumValvesCached(
	applHost: ZWaveApplicationHost,
	endpoint: ZWaveEndpointBase,
): number | undefined;

The same is true for several other similar methods on several other CCs. To use them from application code, simply pass the Driver and Endpoint or ZWaveNode instance:

- irrgCCInstance.getNumValvesCached();
+ IrrigationCC.getNumValvesCached(driver, endpoint);

The valueFormat property in ConfigurationCCBulkSetOptions no longer defaults to the last stored format

Instead, if no valueFormat is passed, the default will be SignedInteger according to the specification. This change does not affect setBulk calls through the commandClasses API.

CommandClass.interviewComplete is no longer a property

Instead, two methods are used in its place:

Old:

if (!instance.interviewComplete) {
	instance.interviewComplete = true;
}

New signature:

if (!instance.isInterviewComplete(applHost)) {
	instance.setInterviewComplete(applHost, true);
}

NotificationCC.notificationMode is no longer a property

Instead, a static method on the Notification CC is used in its place:

// On NotificationCC
public static getNotificationMode(
	applHost: ZWaveApplicationHost,
	node: ZWaveNodeBase,
): "push" | "pull" | undefined;

The max. send attempts in SendData messages now defaults to 1 instead of the driver option

If you're constructing SendData[Bridge][Multicast]Requests manually, the maxSendAttempts property now needs to be set if more than 1 attempts are desired. The driver does this automatically when using the sendCommand method, so most use cases should not be affected.

Moved the Driver.interviewNode method to the ZWaveNode class

The method interviewNode(node: ZWaveNode) which is meant to kick off a deferred initial interview for a node was moved to the ZWaveNode class. The new signature is now node.interview().

The firmware update service now requires API keys

There will be a grace period on this, but soon after the release of v10, the service will respond with an error when no or an invalid API key is provided. Please refer to https://github.com/zwave-js/firmware-updates/ for requesting an API key and set it using the new apiKeys.firmwareUpdateService property on the driver options.

Removed the "zwave-js/CommandClass" sub-package export

The CC implementations have been moved to their own package, @zwave-js/cc. Simply replace the imports with the new package name.

Removed the sendSupervisedCommand and trySendCommandSupervised driver methods

Whether supervision is used or not can now be controlled by the options argument of the sendCommand method. By default, the driver will now determine on its own whether supervision should be used or not. As a result, a wider range of commands can now be sent with supervision automatically.

Removed several deprecated method signatures, enums and properties

  • The enum EventTypes did not give any context to which CC it belongs and has been removed. Use the EntryControlEventTypes enum instead.
  • The enum RecordStatus did not give any context to which CC it belongs and has been removed. Use the DoorLockLoggingRecordStatus enum instead.
  • The type Association was not specific enough and has been deprecated for a long time. It has now been removed. Use AssociationAddress instead.
  • The set method overload of the Configuration CC API with 4 parameters has been removed. Use the overload the single options object instead.
  • The Controller.beginInclusion method overload with the boolean parameter has been removed. Use the overload with the InclusionOptions object instead. NOTE: If you do not pass this object, the new node will be included without security.
  • The Controller.replaceFailedNode method overload accepting the node ID as the second parameter has been removed. Use the overload with the ReplaceNodeOptions object instead. NOTE: If you do not pass this object, the new node will be included without security.
  • The Controller.getAssociationGroups method overload with the nodeId: number parameter has been removed. Use the overload with the AssociationAddress object instead.
  • The Controller.getAssociations method overload with the nodeId: number parameter has been removed. Use the overload with the AssociationAddress object instead.
  • The Controller.isAssociationAllowed method overload accepting the node ID as the first parameter has been removed. Use the overload which accepts an AssociationAddress object instead.
  • The Controller.addAssociations method overload accepting the node ID as the first parameter has been removed. Use the overload which accepts an AssociationAddress object instead.
  • The Controller.removeAssociations method overload accepting the node ID as the first parameter has been removed. Use the overload which accepts an AssociationAddress object instead.
  • The networkKey driver option has been removed. Use securityKeys.S0_Legacy instead.
  • The Controller.isSecondary property was removed. Use Controller.isPrimary instead.
  • The Controller.isStaticUpdateController property was renamed to isSUC to be in line with the similar isSIS property.
  • The Controller.isSlave property was removed. Use the Controller.nodeType property to distinguish between Controller and End Node instead.
  • The GetSerialApiInitDataResponse.initVersion property was removed. Use the zwaveApiVersion property instead, which gives additional context.

Deprecated the unprovision argument to Controller.beginExclusion

The current variant of the argument was confusing, so it has been deprecated. Use the new ExclusionOptions object parameter instead. Z-Wave JS now defaults to disabling the provisioning entry.

async beginExclusion(options?: ExclusionOptions): Promise<boolean>

type ExclusionOptions = {
	strategy:
		| ExclusionStrategy.ExcludeOnly
		| ExclusionStrategy.DisableProvisioningEntry
		| ExclusionStrategy.Unprovision;
};

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,
}

Further deprecations

  • The "Routing End Node" enum member for the NodeType enum was deprecated. Use the alternative "End Node" instead.

Dropped support for Node.js 12

Node.js 12 has been EOL since May 2022 and many libraries already dropped support, which continuously makes it harder to maintain compatibility. As such, we have dropped support for Node.js 12 in the v10 release. You might find that it still works, but we can no longer guarantee this.

Changed argument type of "node found" event

This event is emitted immediately after the Z-Wave protocol is done including a node. At this point, the node is not operational yet, but the argument type ZWaveNode did not make that clear. The event callback was changed to:

(node: FoundNode) => void;

where FoundNode is defined as

interface FoundNode {
	id: number;
	deviceClass?: DeviceClass;
	supportedCCs?: CommandClasses[];
	controlledCCs?: CommandClasses[];
}

Moved user callbacks for S2 inclusion into the driver options

In order to support inclusion controllers (which is required for certification), the inclusion user callbacks had to be decoupled from application-initiated inclusion, since inclusion controllers will tell Z-Wave JS when to bootstrap S2 capable nodes.

Instead of having to pass them via the userCallbacks property of the InclusionOptions, they are now passed directly to the driver via the inclusionUserCallbacks property of the ZWaveOptions. The InclusionOptions still allow passing the user callbacks via the userCallbacks property to override the statically defined ones. This can be useful in scenarios where the driver instance is shared between multiple UIs.

Node firmwareVersion supports major.minor.patch format

Some newer devices can report their primary firmware version in the major.minor.patch format instead of just major.minor. These versions will now be exposed through the firmwareVersion property of the ZWaveNode class.

Internally, Z-Wave JS pads the old versions to major.minor.0 and compares them according to semver, so applications that operate on the versions should likely do the same.