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

159 lines
10 KiB
Markdown

# Migrating to v11 <!-- {docsify-ignore-all} -->
I've put this off for a while now. `v10` has been pretty stable - we've never had anything close to `.23` minor version before.
But Z-Wave JS is on the road to certification, and some of those requirements are forcing my hand.
## Window Covering CC vs. Multilevel Switch CC
The `Window Covering CC` allows for more granular control of covers to the point of making `Multilevel Switch CC` redundant.
As a result, the Z-Wave specification forbids interacting with the `Multilevel Switch CC` on devices that support the `Window Covering CC`.
To avoid removing functionality for users, applications that plan on upgrading to `v11` must make sure to have support for the `Window Covering CC`.
## Changed return types of `Controller.firmwareUpdateOTA` and `Controller.firmwareUpdateOTW` methods
These methods previously only returned a `boolean` indicating success or failure. To get more information about the update result, applications had to listen to the `firmware update finished` event in addition to awaiting the returned promise.
To make this easier:
- `firmwareUpdateOTA` now returns a `Promise<FirmwareUpdateResult>`
- `firmwareUpdateOTW` now returns a `Promise<ControllerFirmwareUpdateResult>`
both of which contain the same information as the corresponding `firmware update finished` events.
## Renamed methods on the `ZWaveHost` interface
The `getSafeCCVersionForEndpoint` method has been renamed to `getSafeCCVersion`.\
The `getSupportedCCVersionForNode` method has been renamed to `getSupportedCCVersion`.
These methods were inconsistently named and none of the other methods that accept a node ID and endpoint index specify that in their name.
## `paramInformation` in custom device configuration files can no longer be an object
In version `8.6.0`, we switched from defining config parameters as an array of objects with instead of an object. Parsing objects was still supported for user-defined config files, but this is no longer the case.
All config files must now use the new format. See [this pull request](https://github.com/zwave-js/node-zwave-js/pull/3100) for details on the change.
## Added support for configuration parameters on endpoints
Configuration parameters on endpoints are now supported. For devices with config parameters on endpoints, the parameter numbers are likely **not** unique.
Applications that expect configuration parameters to only exist on the root device will have to be updated to support this change.
## Removed `preserveUnknownValues` driver option, distinguish between (known to be) unknown and not (yet) known states/values
Several CCs use the value 254 to indicate that a state is unknown. However this value often lies outside of the normal range of values, e.g. 0-99 for multilevel switches. Other CCs translate the raw numeric values to another type, e.g. `boolean` for the `Binary Switch CC`. So simply preserving the 254 isn't an option, because it would throw off applications which expect a value in the defined range or of the correct type.
Previously, Z-Wave JS used `"unknown"` or `undefined` (based on the driver option `preserveUnknownValues`), which both have downsides aswell:
- The string `"unknown"` is obviously not a number or boolean, which could cause errors
- `undefined` gets "filtered" out by the value DB, because it also means **no value**. As a result changes **to** `unknown` would cause no events
- `undefined` could also mean the data hasn't been queried yet, but it is impossible to distinguish from the `unknown` case
To solve this dilemma, Z-Wave JS now uses two distinct values (and types using the same name):
- `NOT_KNOWN` is an alias for `undefined` and indicates that a value is **not known (yet)**, either for a value that has not been queried yet, or where no response was received
- `UNKNOWN_STATE` is an alias for `null` and indicates that some information has been queried, but the corresponding state is **(known to be) unknown**. For example a multilevel device without intermediate position support - it knows that it is neither fully open, nor fully closed, but not the exact position.
Two related utility types have been introduced to preserve this distinction through the type system and replace the former `Maybe<T>` type:
- `MaybeNotKnown<T>` is `T | NOT_KNOWN` and indicates that something is either of the type `T`, or `NOT_KNOWN = undefined`
- `MaybeUnknown<T>` is `T | UNKNOWN_STATE` and indicates that something is either of the type `T`, or `UNKNOWN_STATE = null`
Many method signatures and properties which previously used `undefined` to indicate an uncertainty have been updated to use either of the previous types to make it clear what an absence of a value means. Likewise, several CC values can now be `null / UNKNOWN_STATE`. The `preserveUnknownValues` driver option has been removed.
Application developers should double-check their code for a common class of errors/bugs that could be introduced by this change, e.g.:
- The comparisons `== null`, `== undefined`, `!= null` and `!= undefined` fail to distinguish between `NOT_KNOWN` and `UNKNOWN_STATE`. While it is generally recommended to use triple-equals comparison in JavaScript, in these cases, double-equals is a convenient way to compare against both `null` and `undefined` at the same time.
- Likewise for nullish coalescing and optional chaining operators (`?.`, `??`, `??=`)
- Expecting a `number` or `boolean` when a CC value is not `undefined` is no longer safe, because it could be `null`.
## Reworked `BitField` config parameters to behave like partial parameters
Previously, `BitField` config parameters were using JavaScript `Set`s as values. This seemed like a good idea 4 years ago when the code was written, but until recently almost no devices used this type of config parameter. As it turns out, `Set`s don't serialize well - meaning some of the queried information got lost on the way to the cache - and they are awkward to use for applications.
For config parameters that are defined in configuration files, we have had a better solution for quite some time now: **partial parameters**. Starting with `v11`, `BitField` config parameters will automatically be split into multiple single-bit partial parameters. This means applications which use value metadata to expose config parameters should be able to support them without any changes.
However, the type `ConfigValue` has been changed to just `number`, so we treat this as a breaking change.
## Changed `Node.setValue` and `VirtualNode.setValue` to return a `SetValueResult`
Historically, these methods returned a `boolean` indicating whether the value was successfully set or not. While convenient, simply returning `true` or `false` isn't very helpful, especially since Z-Wave JS started using Supervision wherever possible in v10.
For example, it is not possible to know from a simple `true` whether the command was actually executed by the device or whether it just acknowledged an unsupervised command but didn't actually do anything.
Likewise, returning `false` seems too generic when there are a multitude of possible reasons for this:
- A value was set on a non-existing endpoint
- The endpoint does not support the CC
- The CC is not implemented in Z-Wave JS
- There is no `setValue` implementation for the CC in Z-Wave JS
- The command could not be sent
- The command was sent and received, but the device could not execute it
- An invalid value was provided
- ...
To solve this and help applications give better feedback to the user, `Node.setValue` and `VirtualNode.setValue` now return a `SetValueResult` object with the following properties:
```ts
type SetValueResult = {
status: SetValueStatus;
remainingDuration?: Duration;
message?: string;
};
```
See the [updated documentation](api/node.md#setValue) for a more detailed explanation on working with `SetValueResult`s.
Since the result now contains error information, calling `setValue` will no longer emit an `"error"` event in case of a usage error (unimplemented CC, invalid value).
It will however still throw an error if the communication fails.
## The `"node removed"` event callback now indicates why a node was removed
The signature of the callback has been changed from
```ts
(node: ZWaveNode, replaced: boolean) => void
```
to
```ts
(node: ZWaveNode, reason: RemoveNodeReason) => void
```
where the second argument has one of the following values:
<!-- #import RemoveNodeReason from "zwave-js" -->
```ts
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` is `RemoveNodeReason.Reset`.
## Removed several deprecated method signatures, enums and properties
- The enum member `NodeType["Routing End Node"]` has been removed. This has been called `"End Node"` since `v9.3.0`
- `ConfigurationMetadata.name` was removed in favor of `label`
- `ConfigurationMetadata.info` was removed in favor of `description`
- `Controller.getBroadcastNodeInsecure` and `Controller.getBroadcastNodes` were removed in favor of `Controller.getBroadcastNode`
- `Controller.getMulticastGroupInsecure`, `Controller.getMulticastGroupS2` and `Controller.getMulticastGroups` were removed in favor of `Controller.getMulticastGroup`
- `Controller.beginOTAFirmwareUpdate` was removed in favor of `Controller.firmwareUpdateOTA`
- The `Controller.beginExclusion` overloads accepting a `boolean` or the string `"inactive"` have been removed. Use the overload with `ExclusionOptions` instead.
- `ZWaveNode.beginFirmwareUpdate` was removed in favor of `ZWaveNode.updateFirmware`
- The deprecated arguments of the `"firmware update progress"` and `"firmware update finished"` event callbacks of the `ZWaveNode` class were removed. The `progress` and `result` arguments are now in the 2nd place instead of in the 4th one.