From 4a84ff5f88595b5c43ba3b115ebfc043a3fa22d3 Mon Sep 17 00:00:00 2001 From: AlCalzone Date: Mon, 20 Nov 2023 16:29:54 +0100 Subject: [PATCH 01/20] fix: put failed transaction in correct queue after recovering unresponsive controller (#6507) --- packages/zwave-js/src/lib/driver/Driver.ts | 38 +++-- .../7e570001.jsonl | 53 +++++++ .../sendDataMissingCallbackAbort.test.ts | 148 +++++++++++++++++- 3 files changed, 228 insertions(+), 11 deletions(-) create mode 100644 packages/zwave-js/src/lib/test/driver/fixtures/sendDataMissingCallbackImmediateToSleepingNode/7e570001.jsonl diff --git a/packages/zwave-js/src/lib/driver/Driver.ts b/packages/zwave-js/src/lib/driver/Driver.ts index 4b86274a557f..14d7e6405530 100644 --- a/packages/zwave-js/src/lib/driver/Driver.ts +++ b/packages/zwave-js/src/lib/driver/Driver.ts @@ -1827,6 +1827,7 @@ export class Driver extends TypedEventEmitter if ( oldStatus === NodeStatus.Dead && node.interviewStage !== InterviewStage.Complete + && !this._options.testingHooks?.skipNodeInterview ) { void this.interviewNodeInternal(node); } @@ -3613,7 +3614,9 @@ export class Driver extends TypedEventEmitter // Re-queue the transaction, so it can get handled next. // Its message generator may have finished, so reset that too. transaction.reset(); - this.queue.add(transaction.clone()); + this.getQueueForTransaction(transaction).add( + transaction.clone(), + ); this._controller?.setStatus(ControllerStatus.Ready); this._recoveryPhase = ControllerRecoveryPhase.None; @@ -3729,7 +3732,9 @@ export class Driver extends TypedEventEmitter // Re-queue the transaction, so it can get handled next. // Its message generator may have finished, so reset that too. transaction.reset(); - this.queue.add(transaction.clone()); + this.getQueueForTransaction(transaction).add( + transaction.clone(), + ); this._controller?.setStatus(ControllerStatus.Ready); this._recoveryPhase = @@ -4968,9 +4973,18 @@ ${handlers.length} left`, msg, transactionSource, ); + this.driverLog.print("SerialAPI command succeeded"); result.resolve(ret); } catch (e) { + this.driverLog.print( + "SerialAPI command failed: " + getErrorMessage(e), + ); result.reject(e); + + // // We may want to handle the error before continuing with the next command + // // Ideally, we'd pause the queue here and resume it when the error was handled, + // // but this system isn't in place yet. + // await wait(250); } } } @@ -5148,6 +5162,17 @@ ${handlers.length} left`, return result; } + private getQueueForTransaction(t: Transaction): TransactionQueue { + if ( + t.priority === MessagePriority.Immediate + || t.priority === MessagePriority.ControllerImmediate + ) { + return this.immediateQueue; + } else { + return this.queue; + } + } + /** * Sends a message to the Z-Wave stick. * @param msg The message to send @@ -5257,14 +5282,7 @@ ${handlers.length} left`, transaction.tag = options.tag; // And queue it - if ( - transaction.priority === MessagePriority.Immediate - || transaction.priority === MessagePriority.ControllerImmediate - ) { - this.immediateQueue.add(transaction); - } else { - this.queue.add(transaction); - } + this.getQueueForTransaction(transaction).add(transaction); transaction.setProgress({ state: TransactionState.Queued }); // If the transaction should expire, start the timeout diff --git a/packages/zwave-js/src/lib/test/driver/fixtures/sendDataMissingCallbackImmediateToSleepingNode/7e570001.jsonl b/packages/zwave-js/src/lib/test/driver/fixtures/sendDataMissingCallbackImmediateToSleepingNode/7e570001.jsonl new file mode 100644 index 000000000000..f2db1dae76b8 --- /dev/null +++ b/packages/zwave-js/src/lib/test/driver/fixtures/sendDataMissingCallbackImmediateToSleepingNode/7e570001.jsonl @@ -0,0 +1,53 @@ +{"k":"cacheFormat","v":1} +{"k":"node.1.isListening","v":true} +{"k":"node.1.isFrequentListening","v":false} +{"k":"node.1.isRouting","v":true} +{"k":"node.1.supportedDataRates","v":[40000,9600,100000]} +{"k":"node.1.protocolVersion","v":3} +{"k":"node.1.nodeType","v":"Controller"} +{"k":"node.1.supportsSecurity","v":false} +{"k":"node.1.supportsBeaming","v":true} +{"k":"node.1.deviceClass","v":{"basic":2,"generic":2,"specific":7}} +{"k":"node.1.endpoint.0.commandClass.0x72","v":{"isSupported":true,"isControlled":false,"secure":false,"version":0}} +{"k":"node.1.endpoint.0.commandClass.0x86","v":{"isSupported":true,"isControlled":false,"secure":false,"version":0}} +{"k":"node.1.endpoint.0.commandClass.0x20","v":{"isSupported":false,"isControlled":true,"secure":false,"version":0}} +{"k":"node.1.endpoint.0.commandClass.0x60","v":{"isSupported":false,"isControlled":true,"secure":false,"version":0}} +{"k":"node.1.interviewStage","v":"Complete"} + +// Node 2 can sleep +{"k":"node.2.isListening","v":false} +{"k":"node.2.isFrequentListening","v":false} +{"k":"node.2.isRouting","v":true} +{"k":"node.2.supportedDataRates","v":[40000,9600,100000]} +{"k":"node.2.protocolVersion","v":3} +{"k":"node.2.nodeType","v":"End Node"} +{"k":"node.2.supportsSecurity","v":false} +{"k":"node.2.supportsBeaming","v":true} +{"k":"node.2.deviceClass","v":{"basic":4,"generic":6,"specific":1}} +{"k":"node.2.endpoint.0.commandClass.0x20","v":{"isSupported":true,"isControlled":false,"secure":false,"version":2}} +// Wakeup: +{"k":"node.2.endpoint.0.commandClass.0x84","v":{"isSupported":true,"isControlled":false,"secure":false,"version":1}} +{"k":"node.2.securityClasses.S2_AccessControl","v":false} +{"k":"node.2.securityClasses.S2_Authenticated","v":false} +{"k":"node.2.securityClasses.S2_Unauthenticated","v":false} +{"k":"node.2.securityClasses.S0_Legacy","v":false} +{"k":"node.2.interviewStage","v":"Complete"} +{"k":"node.2.hasSUCReturnRoute","v":true} + +// Node 3 can't +{"k":"node.3.isListening","v":true} +{"k":"node.3.isFrequentListening","v":false} +{"k":"node.3.isRouting","v":true} +{"k":"node.3.supportedDataRates","v":[40000,9600,100000]} +{"k":"node.3.protocolVersion","v":3} +{"k":"node.3.nodeType","v":"End Node"} +{"k":"node.3.supportsSecurity","v":false} +{"k":"node.3.supportsBeaming","v":true} +{"k":"node.3.deviceClass","v":{"basic":4,"generic":6,"specific":1}} +{"k":"node.3.endpoint.0.commandClass.0x20","v":{"isSupported":true,"isControlled":false,"secure":false,"version":2}} +{"k":"node.3.securityClasses.S2_AccessControl","v":false} +{"k":"node.3.securityClasses.S2_Authenticated","v":false} +{"k":"node.3.securityClasses.S2_Unauthenticated","v":false} +{"k":"node.3.securityClasses.S0_Legacy","v":false} +{"k":"node.3.interviewStage","v":"Complete"} +{"k":"node.3.hasSUCReturnRoute","v":true} diff --git a/packages/zwave-js/src/lib/test/driver/sendDataMissingCallbackAbort.test.ts b/packages/zwave-js/src/lib/test/driver/sendDataMissingCallbackAbort.test.ts index 96447e954aa0..02f82ab4304e 100644 --- a/packages/zwave-js/src/lib/test/driver/sendDataMissingCallbackAbort.test.ts +++ b/packages/zwave-js/src/lib/test/driver/sendDataMissingCallbackAbort.test.ts @@ -6,7 +6,14 @@ import { MockControllerStateKeys, } from "../../controller/MockControllerState"; -import { NodeStatus, ZWaveErrorCodes, assertZWaveError } from "@zwave-js/core"; +import { + CommandClasses, + MessagePriority, + NodeStatus, + ZWaveErrorCodes, + assertZWaveError, +} from "@zwave-js/core"; +import path from "node:path"; import Sinon from "sinon"; import { SoftResetRequest } from "../../serialapi/misc/SoftResetRequest"; import { @@ -19,6 +26,7 @@ import { SendDataResponse, } from "../../serialapi/transport/SendDataMessages"; import { integrationTest } from "../integrationTestSuite"; +import { integrationTest as integrationTestMulti } from "../integrationTestSuiteMulti"; let shouldTimeOut: boolean; @@ -683,3 +691,141 @@ integrationTest( }, }, ); + +integrationTestMulti.only( + "When a command from the immediate queue to a sleeping node triggers the unresponsive controller recovery, the normal send queue does not get blocked", + { + debug: true, + + provisioningDirectory: path.join( + __dirname, + "fixtures/sendDataMissingCallbackImmediateToSleepingNode", + ), + + nodeCapabilities: [ + { + id: 2, + capabilities: { + // isFrequentListening: false, + isListening: false, + commandClasses: [ + CommandClasses["Wake Up"], + CommandClasses.Basic, + ], + }, + }, + { + id: 3, + capabilities: { + commandClasses: [ + CommandClasses.Basic, + ], + }, + }, + ], + + // additionalDriverOptions: { + // testingHooks: { + // skipNodeInterview: true, + // }, + // }, + + customSetup: async (driver, mockController, mockNodes) => { + // This is almost a 1:1 copy of the default behavior, except that the callback never gets sent + const handleBrokenSendData: MockControllerBehavior = { + async onHostMessage(host, controller, msg) { + // If the controller is operating normally, defer to the default behavior + if (!shouldTimeOut) return false; + + if (msg instanceof SendDataRequest) { + // Check if this command is legal right now + const state = controller.state.get( + MockControllerStateKeys.CommunicationState, + ) as MockControllerCommunicationState | undefined; + if ( + state != undefined + && state !== MockControllerCommunicationState.Idle + ) { + throw new Error( + "Received SendDataRequest while not idle", + ); + } + + // Put the controller into sending state + controller.state.set( + MockControllerStateKeys.CommunicationState, + MockControllerCommunicationState.Sending, + ); + + // Notify the host that the message was sent + const res = new SendDataResponse(host, { + wasSent: true, + }); + await controller.sendToHost(res.serialize()); + + return true; + } else if (msg instanceof SendDataAbort) { + // Put the controller into idle state + controller.state.set( + MockControllerStateKeys.CommunicationState, + MockControllerCommunicationState.Idle, + ); + + shouldTimeOut = false; + + return true; + } + }, + }; + mockController.defineBehavior(handleBrokenSendData); + }, + testBody: async (t, driver, nodes, mockController, mockNodes) => { + driver.driverLog.print("TEST START"); + driver.driverLog.print("TEST START"); + driver.driverLog.print("TEST START"); + driver.driverLog.print("TEST START"); + driver.driverLog.print("TEST START"); + // Circumvent the options validation so the test doesn't take forever + driver.options.timeouts.sendDataAbort = 1000; + driver.options.timeouts.sendDataCallback = 1500; + + shouldTimeOut = true; + const [node2, node3] = nodes; + + node2.markAsAsleep(); + node3.markAsAlive(); + + const immediateCommand = node2.commandClasses.Basic.withOptions({ + priority: MessagePriority.Immediate, + }).set(0).catch((e) => e.code); + + await wait(2500); + + // Transmission should have been aborted + mockController.assertReceivedHostMessage( + (msg) => msg.functionType === FunctionType.SendDataAbort, + ); + // And the stick should have been soft-reset + mockController.assertReceivedHostMessage( + (msg) => msg.functionType === FunctionType.SoftReset, + ); + mockController.clearReceivedHostMessages(); + + const followupCommand = node3.commandClasses.Basic.set(0).catch(( + e, + ) => e.code); + + // Both commands should succeed now. + + driver.driverLog.print("normal queue"); + driver.driverLog.sendQueue(driver["queue"]); + driver.driverLog.print("immediate queue:"); + driver.driverLog.sendQueue(driver["immediateQueue"]); + + await immediateCommand; + await followupCommand; + + t.pass(); + }, + }, +); From ba3da163efc51cf96bd4a67f527a5071b6ff6609 Mon Sep 17 00:00:00 2001 From: Dominic Griesel Date: Mon, 20 Nov 2023 16:33:16 +0100 Subject: [PATCH 02/20] chore: cleanup PR #6507 --- packages/zwave-js/src/lib/driver/Driver.ts | 9 --------- .../lib/test/driver/sendDataMissingCallbackAbort.test.ts | 8 ++------ 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/packages/zwave-js/src/lib/driver/Driver.ts b/packages/zwave-js/src/lib/driver/Driver.ts index 14d7e6405530..8ab149181974 100644 --- a/packages/zwave-js/src/lib/driver/Driver.ts +++ b/packages/zwave-js/src/lib/driver/Driver.ts @@ -4973,18 +4973,9 @@ ${handlers.length} left`, msg, transactionSource, ); - this.driverLog.print("SerialAPI command succeeded"); result.resolve(ret); } catch (e) { - this.driverLog.print( - "SerialAPI command failed: " + getErrorMessage(e), - ); result.reject(e); - - // // We may want to handle the error before continuing with the next command - // // Ideally, we'd pause the queue here and resume it when the error was handled, - // // but this system isn't in place yet. - // await wait(250); } } } diff --git a/packages/zwave-js/src/lib/test/driver/sendDataMissingCallbackAbort.test.ts b/packages/zwave-js/src/lib/test/driver/sendDataMissingCallbackAbort.test.ts index 02f82ab4304e..a4b42cab2cae 100644 --- a/packages/zwave-js/src/lib/test/driver/sendDataMissingCallbackAbort.test.ts +++ b/packages/zwave-js/src/lib/test/driver/sendDataMissingCallbackAbort.test.ts @@ -692,10 +692,10 @@ integrationTest( }, ); -integrationTestMulti.only( +integrationTestMulti( "When a command from the immediate queue to a sleeping node triggers the unresponsive controller recovery, the normal send queue does not get blocked", { - debug: true, + // debug: true, provisioningDirectory: path.join( __dirname, @@ -780,10 +780,6 @@ integrationTestMulti.only( mockController.defineBehavior(handleBrokenSendData); }, testBody: async (t, driver, nodes, mockController, mockNodes) => { - driver.driverLog.print("TEST START"); - driver.driverLog.print("TEST START"); - driver.driverLog.print("TEST START"); - driver.driverLog.print("TEST START"); driver.driverLog.print("TEST START"); // Circumvent the options validation so the test doesn't take forever driver.options.timeouts.sendDataAbort = 1000; From 61bc23af573ce4b4ae0697ee2af7ccd4b212d268 Mon Sep 17 00:00:00 2001 From: Dominic Griesel Date: Mon, 20 Nov 2023 16:35:19 +0100 Subject: [PATCH 03/20] chore: update changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f70f193fda31..0e5bcf53de07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ +## __WORK IN PROGRESS__ +### Bugfixes +* Fixed an issue where the unresponsive controller recovery could put "immediate" commands to a sleeping node on the wrong queue, blocking all outgoing communication (#6507) + +### Config file changes +* Add missing units and firmware condition for Heatit Z-Temp2 (#6500) +* Correct device label for Airzone Aidoo Control HVAC unit (#6493) + ## 12.3.0 (2023-10-31) ### Features * Allow disabling the unresponsive controller recovery feature (#6480) From a489007a4a2a5ccdb5bbf8444d4ba5f1148a8b97 Mon Sep 17 00:00:00 2001 From: Dominic Griesel Date: Mon, 20 Nov 2023 16:35:38 +0100 Subject: [PATCH 04/20] chore: release v12.3.1 ### Bugfixes * Fixed an issue where the unresponsive controller recovery could put "immediate" commands to a sleeping node on the wrong queue, blocking all outgoing communication (#6507) ### Config file changes * Add missing units and firmware condition for Heatit Z-Temp2 (#6500) * Correct device label for Airzone Aidoo Control HVAC unit (#6493) --- CHANGELOG.md | 2 +- package.json | 2 +- packages/cc/package.json | 2 +- packages/config/package.json | 2 +- packages/flash/package.json | 2 +- packages/host/package.json | 2 +- packages/serial/package.json | 2 +- packages/testing/package.json | 2 +- packages/zwave-js/package.json | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e5bcf53de07..56c4cdfbed7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ -## __WORK IN PROGRESS__ +## 12.3.1 (2023-11-20) ### Bugfixes * Fixed an issue where the unresponsive controller recovery could put "immediate" commands to a sleeping node on the wrong queue, blocking all outgoing communication (#6507) diff --git a/package.json b/package.json index ae1f5dc267c9..cd878d10e725 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/repo", - "version": "12.3.0", + "version": "12.3.1", "private": true, "description": "Z-Wave driver written entirely in JavaScript/TypeScript", "keywords": [], diff --git a/packages/cc/package.json b/packages/cc/package.json index 6a12066e4b94..16ffd621333c 100644 --- a/packages/cc/package.json +++ b/packages/cc/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/cc", - "version": "12.3.0", + "version": "12.3.1", "description": "zwave-js: Command Classes", "keywords": [], "publishConfig": { diff --git a/packages/config/package.json b/packages/config/package.json index a4fb0ba41019..e82143820225 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/config", - "version": "12.3.0", + "version": "12.3.1", "description": "zwave-js: configuration files", "publishConfig": { "access": "public" diff --git a/packages/flash/package.json b/packages/flash/package.json index d050ae0490c7..c730e796eaa1 100644 --- a/packages/flash/package.json +++ b/packages/flash/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/flash", - "version": "12.3.0", + "version": "12.3.1", "description": "zwave-js: firmware flash utility", "keywords": [], "publishConfig": { diff --git a/packages/host/package.json b/packages/host/package.json index 869b739004dc..923777379aaa 100644 --- a/packages/host/package.json +++ b/packages/host/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/host", - "version": "12.3.0", + "version": "12.3.1", "description": "zwave-js: Host abstractions", "keywords": [], "publishConfig": { diff --git a/packages/serial/package.json b/packages/serial/package.json index f8aafa6632f2..39f7ef65feef 100644 --- a/packages/serial/package.json +++ b/packages/serial/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/serial", - "version": "12.3.0", + "version": "12.3.1", "description": "zwave-js: Serialport driver", "publishConfig": { "access": "public" diff --git a/packages/testing/package.json b/packages/testing/package.json index 9923212909d3..609a06c58aa6 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/testing", - "version": "12.3.0", + "version": "12.3.1", "description": "zwave-js: testing utilities", "keywords": [], "publishConfig": { diff --git a/packages/zwave-js/package.json b/packages/zwave-js/package.json index f13f4c894d90..2b007ce14266 100644 --- a/packages/zwave-js/package.json +++ b/packages/zwave-js/package.json @@ -1,6 +1,6 @@ { "name": "zwave-js", - "version": "12.3.0", + "version": "12.3.1", "description": "Z-Wave driver written entirely in JavaScript/TypeScript", "keywords": [], "main": "build/index.js", From 89031d4af8ecf2dc6ef972f2d5d3596a01cd5750 Mon Sep 17 00:00:00 2001 From: Dominic Griesel Date: Thu, 23 Nov 2023 15:44:01 +0100 Subject: [PATCH 05/20] feat: add mocks for Multilevel Sensor CC --- packages/cc/src/cc/MultilevelSensorCC.ts | 75 +++++++--- .../testing/src/CCSpecificCapabilities.ts | 11 ++ .../src/lib/node/MockNodeBehaviors.ts | 2 + .../node/mockCCBehaviors/MultilevelSensor.ts | 128 ++++++++++++++++++ 4 files changed, 197 insertions(+), 19 deletions(-) create mode 100644 packages/zwave-js/src/lib/node/mockCCBehaviors/MultilevelSensor.ts diff --git a/packages/cc/src/cc/MultilevelSensorCC.ts b/packages/cc/src/cc/MultilevelSensorCC.ts index 9b26fc5028b2..aafef9b33e54 100644 --- a/packages/cc/src/cc/MultilevelSensorCC.ts +++ b/packages/cc/src/cc/MultilevelSensorCC.ts @@ -1,5 +1,5 @@ import { Scale, getDefaultScale } from "@zwave-js/config"; -import { timespan } from "@zwave-js/core"; +import { encodeBitMask, timespan } from "@zwave-js/core"; import type { IZWaveEndpoint, MessageOrCCLogEntry, @@ -13,8 +13,6 @@ import { type MaybeNotKnown, MessagePriority, ValueMetadata, - ZWaveError, - ZWaveErrorCodes, encodeFloatWithScale, parseBitMask, parseFloatWithScale, @@ -829,22 +827,41 @@ export class MultilevelSensorCCGet extends MultilevelSensorCC { } } +// @publicAPI +export interface MultilevelSensorCCSupportedSensorReportOptions + extends CCCommandOptions +{ + supportedSensorTypes: readonly number[]; +} + @CCCommand(MultilevelSensorCommand.SupportedSensorReport) export class MultilevelSensorCCSupportedSensorReport extends MultilevelSensorCC { public constructor( host: ZWaveHost, - options: CommandClassDeserializationOptions, + options: + | CommandClassDeserializationOptions + | MultilevelSensorCCSupportedSensorReportOptions, ) { super(host, options); - validatePayload(this.payload.length >= 1); - this.supportedSensorTypes = parseBitMask(this.payload); + + if (gotDeserializationOptions(options)) { + validatePayload(this.payload.length >= 1); + this.supportedSensorTypes = parseBitMask(this.payload); + } else { + this.supportedSensorTypes = options.supportedSensorTypes; + } } // TODO: Use this during interview to precreate values @ccValue(MultilevelSensorCCValues.supportedSensorTypes) - public readonly supportedSensorTypes: readonly number[]; + public supportedSensorTypes: readonly number[]; + + public serialize(): Buffer { + this.payload = encodeBitMask(this.supportedSensorTypes); + return super.serialize(); + } public toLogEntry(applHost: ZWaveApplicationHost): MessageOrCCLogEntry { return { @@ -869,20 +886,35 @@ export class MultilevelSensorCCSupportedSensorReport @expectedCCResponse(MultilevelSensorCCSupportedSensorReport) export class MultilevelSensorCCGetSupportedSensor extends MultilevelSensorCC {} +// @publicAPI +export interface MultilevelSensorCCSupportedScaleReportOptions + extends CCCommandOptions +{ + sensorType: number; + supportedScales: readonly number[]; +} + @CCCommand(MultilevelSensorCommand.SupportedScaleReport) export class MultilevelSensorCCSupportedScaleReport extends MultilevelSensorCC { public constructor( host: ZWaveHost, - options: CommandClassDeserializationOptions, + options: + | CommandClassDeserializationOptions + | MultilevelSensorCCSupportedScaleReportOptions, ) { super(host, options); - validatePayload(this.payload.length >= 2); - this.sensorType = this.payload[0]; - this.supportedScales = parseBitMask( - Buffer.from([this.payload[1] & 0b1111]), - 0, - ); + if (gotDeserializationOptions(options)) { + validatePayload(this.payload.length >= 2); + this.sensorType = this.payload[0]; + this.supportedScales = parseBitMask( + Buffer.from([this.payload[1] & 0b1111]), + 0, + ); + } else { + this.sensorType = options.sensorType; + this.supportedScales = options.supportedScales; + } } public readonly sensorType: number; @@ -894,6 +926,14 @@ export class MultilevelSensorCCSupportedScaleReport extends MultilevelSensorCC { ) public readonly supportedScales: readonly number[]; + public serialize(): Buffer { + this.payload = Buffer.concat([ + Buffer.from([this.sensorType]), + encodeBitMask(this.supportedScales, 4, 0), + ]); + return super.serialize(); + } + public toLogEntry(applHost: ZWaveApplicationHost): MessageOrCCLogEntry { return { ...super.toLogEntry(applHost), @@ -935,11 +975,8 @@ export class MultilevelSensorCCGetSupportedScale extends MultilevelSensorCC { ) { super(host, options); if (gotDeserializationOptions(options)) { - // TODO: Deserialize payload - throw new ZWaveError( - `${this.constructor.name}: deserialization not implemented`, - ZWaveErrorCodes.Deserialization_NotImplemented, - ); + validatePayload(this.payload.length >= 1); + this.sensorType = this.payload[0]; } else { this.sensorType = options.sensorType; } diff --git a/packages/testing/src/CCSpecificCapabilities.ts b/packages/testing/src/CCSpecificCapabilities.ts index ea9d5ed988a5..789891a26925 100644 --- a/packages/testing/src/CCSpecificCapabilities.ts +++ b/packages/testing/src/CCSpecificCapabilities.ts @@ -28,6 +28,16 @@ export interface NotificationCCCapabilities { notificationTypesAndEvents: Record; } +export interface MultilevelSensorCCCapabilities { + sensors: Record; + getValue?: ( + sensorType: number | undefined, + scale: number | undefined, + ) => number | undefined; +} + export interface SoundSwitchCCCapabilities { defaultToneId: number; defaultVolume: number; @@ -105,6 +115,7 @@ export interface ScheduleEntryLockCCCapabilities { export type CCSpecificCapabilities = { [CommandClasses.Configuration]: ConfigurationCCCapabilities; [CommandClasses.Notification]: NotificationCCCapabilities; + [49 /* Multilevel Sensor */]: MultilevelSensorCCCapabilities; [121 /* Sound Switch */]: SoundSwitchCCCapabilities; [106 /* Window Covering */]: WindowCoveringCCCapabilities; [144 /* Energy Production */]: EnergyProductionCCCapabilities; diff --git a/packages/zwave-js/src/lib/node/MockNodeBehaviors.ts b/packages/zwave-js/src/lib/node/MockNodeBehaviors.ts index 714ae9ce1383..4efa04e44e99 100644 --- a/packages/zwave-js/src/lib/node/MockNodeBehaviors.ts +++ b/packages/zwave-js/src/lib/node/MockNodeBehaviors.ts @@ -31,6 +31,7 @@ import { BasicCCBehaviors } from "./mockCCBehaviors/Basic"; import { ConfigurationCCBehaviors } from "./mockCCBehaviors/Configuration"; import { EnergyProductionCCBehaviors } from "./mockCCBehaviors/EnergyProduction"; import { ManufacturerSpecificCCBehaviors } from "./mockCCBehaviors/ManufacturerSpecific"; +import { MultilevelSensorCCBehaviors } from "./mockCCBehaviors/MultilevelSensor"; import { NotificationCCBehaviors } from "./mockCCBehaviors/Notification"; import { ScheduleEntryLockCCBehaviors } from "./mockCCBehaviors/ScheduleEntryLock"; import { SoundSwitchCCBehaviors } from "./mockCCBehaviors/SoundSwitch"; @@ -293,6 +294,7 @@ export function createDefaultBehaviors(): MockNodeBehavior[] { ...ConfigurationCCBehaviors, ...EnergyProductionCCBehaviors, ...ManufacturerSpecificCCBehaviors, + ...MultilevelSensorCCBehaviors, ...NotificationCCBehaviors, ...ScheduleEntryLockCCBehaviors, ...SoundSwitchCCBehaviors, diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/MultilevelSensor.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/MultilevelSensor.ts new file mode 100644 index 000000000000..8409069e26de --- /dev/null +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/MultilevelSensor.ts @@ -0,0 +1,128 @@ +import { + MultilevelSensorCCGet, + MultilevelSensorCCGetSupportedScale, + MultilevelSensorCCGetSupportedSensor, + MultilevelSensorCCReport, + MultilevelSensorCCSupportedScaleReport, + MultilevelSensorCCSupportedSensorReport, +} from "@zwave-js/cc"; +import { CommandClasses } from "@zwave-js/core"; +import type { MultilevelSensorCCCapabilities } from "@zwave-js/testing"; +import { + type MockNodeBehavior, + MockZWaveFrameType, + createMockZWaveRequestFrame, +} from "@zwave-js/testing"; + +const defaultCapabilities: MultilevelSensorCCCapabilities = { + sensors: {}, // none +}; + +const respondToMultilevelSensorGetSupportedSensor: MockNodeBehavior = { + async onControllerFrame(controller, self, frame) { + if ( + frame.type === MockZWaveFrameType.Request + && frame.payload instanceof MultilevelSensorCCGetSupportedSensor + ) { + const capabilities = { + ...defaultCapabilities, + ...self.getCCCapabilities( + CommandClasses["Multilevel Sensor"], + frame.payload.endpointIndex, + ), + }; + const cc = new MultilevelSensorCCSupportedSensorReport(self.host, { + nodeId: controller.host.ownNodeId, + supportedSensorTypes: Object.keys( + capabilities.sensors, + ).map((t) => parseInt(t)), + }); + await self.sendToController( + createMockZWaveRequestFrame(cc, { + ackRequested: false, + }), + ); + return true; + } + return false; + }, +}; + +const respondToMultilevelSensorGetSupportedScale: MockNodeBehavior = { + async onControllerFrame(controller, self, frame) { + if ( + frame.type === MockZWaveFrameType.Request + && frame.payload instanceof MultilevelSensorCCGetSupportedScale + ) { + const capabilities = { + ...defaultCapabilities, + ...self.getCCCapabilities( + CommandClasses["Multilevel Sensor"], + frame.payload.endpointIndex, + ), + }; + const sensorType = frame.payload.sensorType; + const supportedScales = + capabilities.sensors[sensorType]?.supportedScales ?? []; + const cc = new MultilevelSensorCCSupportedScaleReport(self.host, { + nodeId: controller.host.ownNodeId, + sensorType, + supportedScales, + }); + await self.sendToController( + createMockZWaveRequestFrame(cc, { + ackRequested: false, + }), + ); + return true; + } + return false; + }, +}; + +const respondToMultilevelSensorGet: MockNodeBehavior = { + async onControllerFrame(controller, self, frame) { + if ( + frame.type === MockZWaveFrameType.Request + && frame.payload instanceof MultilevelSensorCCGet + ) { + const capabilities = { + ...defaultCapabilities, + ...self.getCCCapabilities( + CommandClasses["Multilevel Sensor"], + frame.payload.endpointIndex, + ), + }; + const firstSupportedSensorType = + Object.keys(capabilities.sensors).length > 0 + ? parseInt(Object.keys(capabilities.sensors)[0]) + : undefined; + const sensorType = frame.payload.sensorType + ?? firstSupportedSensorType + ?? 1; + const scale = frame.payload.scale + ?? capabilities.sensors[sensorType].supportedScales[0] + ?? 0; + const value = capabilities.getValue?.(sensorType, scale) ?? 0; + const cc = new MultilevelSensorCCReport(self.host, { + nodeId: controller.host.ownNodeId, + type: sensorType, + scale, + value, + }); + await self.sendToController( + createMockZWaveRequestFrame(cc, { + ackRequested: false, + }), + ); + return true; + } + return false; + }, +}; + +export const MultilevelSensorCCBehaviors = [ + respondToMultilevelSensorGetSupportedSensor, + respondToMultilevelSensorGetSupportedScale, + respondToMultilevelSensorGet, +]; From d3500953b8517883b99abe95a78c3ce1d7c740cc Mon Sep 17 00:00:00 2001 From: Danny Schuh Date: Wed, 29 Nov 2023 03:35:36 -0800 Subject: [PATCH 06/20] fix(config): correct firmware version condition for Zooz ZSE40 v3.0 (#6519) --- packages/config/config/devices/0x027a/zse40.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/config/config/devices/0x027a/zse40.json b/packages/config/config/devices/0x027a/zse40.json index f8273bddc610..34ca991dda2a 100644 --- a/packages/config/config/devices/0x027a/zse40.json +++ b/packages/config/config/devices/0x027a/zse40.json @@ -13,7 +13,7 @@ "manufacturerId": "0x027a", "label": [ { - "$if": "firmwareVersion === 32.32 || firmwareVersion >= 1.10 && firmwareVersion < 16.9", + "$if": "firmwareVersion >= 32.32 || firmwareVersion >= 1.10 && firmwareVersion < 16.9", "value": "ZSE40 700" }, // Fallback for non-700 series From a7e4e6a3de44f1b55d2f520a9f7a948337a60a5f Mon Sep 17 00:00:00 2001 From: AlCalzone Date: Wed, 29 Nov 2023 14:43:46 +0100 Subject: [PATCH 07/20] fix: transitively upgrade `axios` to a non-vulnerable version (#6520) --- package.json | 4 +- packages/zwave-js/package.json | 2 +- yarn.lock | 171 ++++++++++++++------------------- 3 files changed, 77 insertions(+), 100 deletions(-) diff --git a/package.json b/package.json index cd878d10e725..eb0e033579c8 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,8 @@ "@actions/exec": "^1.1.1", "@actions/github": "^5.0.3", "@alcalzone/jsonl-db": "^3.1.0", - "@alcalzone/monopack": "^1.2.1", - "@alcalzone/release-script": "~3.6.0", + "@alcalzone/monopack": "^1.2.2", + "@alcalzone/release-script": "~3.7.0", "@commitlint/cli": "^17.7.1", "@commitlint/config-conventional": "^17.7.0", "@dprint/formatter": "^0.2.0", diff --git a/packages/zwave-js/package.json b/packages/zwave-js/package.json index 2b007ce14266..06d506f97d48 100644 --- a/packages/zwave-js/package.json +++ b/packages/zwave-js/package.json @@ -82,7 +82,7 @@ }, "dependencies": { "@alcalzone/jsonl-db": "^3.1.0", - "@alcalzone/pak": "^0.9.0", + "@alcalzone/pak": "^0.10.1", "@zwave-js/cc": "workspace:*", "@zwave-js/config": "workspace:*", "@zwave-js/core": "workspace:*", diff --git a/yarn.lock b/yarn.lock index a246bfa74ecf..59805e658c8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -70,40 +70,29 @@ __metadata: languageName: node linkType: hard -"@alcalzone/monopack@npm:^1.2.1": - version: 1.2.1 - resolution: "@alcalzone/monopack@npm:1.2.1" +"@alcalzone/monopack@npm:^1.2.2": + version: 1.2.2 + resolution: "@alcalzone/monopack@npm:1.2.2" dependencies: - "@alcalzone/pak": ^0.9.0 + "@alcalzone/pak": ^0.10.1 fs-extra: ^10.1.0 tar: ^6.1.13 bin: monopack: bin/cli.js - checksum: 5cf676941c8ce205cf60c380523a7bf92c8957b3827f12e395d86ef093b41db2cf274b5cdc7a46d55387c382592090a0bf5ba63c132e6ee1326dcded6526018a - languageName: node - linkType: hard - -"@alcalzone/pak@npm:^0.8.1": - version: 0.8.1 - resolution: "@alcalzone/pak@npm:0.8.1" - dependencies: - axios: ^0.26.0 - execa: ^5.0.0 - fs-extra: ^10.0.1 - checksum: cea838b7cb6a92135a751719cbfeff0608692804127914c9161f525af6e9ab477828f11a2ed0d5fe98c33add229e0c4f3aceb42b1fc03d3ffc6cd3f557cedaa5 + checksum: add8acb37ceb7e2b5a133000749839fb5f62b08ce1cec10e157c99cc3def016f46cf424ae7152d701a1ee6139ecce2e4f04b0ac5e7a6b7dd8ea8f708a8d136b0 languageName: node linkType: hard -"@alcalzone/pak@npm:^0.9.0": - version: 0.9.0 - resolution: "@alcalzone/pak@npm:0.9.0" +"@alcalzone/pak@npm:^0.10.1": + version: 0.10.1 + resolution: "@alcalzone/pak@npm:0.10.1" dependencies: - axios: ^0.27.2 - execa: ~5.0.0 + axios: ^1.6.2 + execa: ~5.0.1 fs-extra: ^10.1.0 semver: ^7.3.7 tiny-glob: ^0.2.9 - checksum: f2043462c0608fad9d929dd76765d58c06c94a0bf4602d5b183e141cbc3dc83d0387f3806b4f994cc3d4bd160d54f18913d6f2ca334c90c88b4dfba9cc4c7cfb + checksum: e1f254f3df5d7e9be8f8a03a1e35d483a9203f29a7203d88cb9e238d0d8003b4c4d4377d65e333ce4aec26c864f09da89c840c0e20794b3a05a78bab5241f870 languageName: node linkType: hard @@ -118,84 +107,84 @@ __metadata: languageName: node linkType: hard -"@alcalzone/release-script-core@npm:3.5.9": - version: 3.5.9 - resolution: "@alcalzone/release-script-core@npm:3.5.9" +"@alcalzone/release-script-core@npm:3.7.0": + version: 3.7.0 + resolution: "@alcalzone/release-script-core@npm:3.7.0" dependencies: execa: ^5.1.1 - checksum: df20c8fa6ae3aba48ca092e005963a382c2a5a527d156d932e1036bb9b10a35770172fef166e467cd8f1172df1d0789d70f83d3cb1fd1958ffb74c15fef91a55 + checksum: 482c0c6ab59d7535941b0f6522c027fb9df57f91f76023c879b74efadb0a524dfcb8baee82c842c80bd323ecb2520b887b56f6597ca234773bb74c6a9e181fa6 languageName: node linkType: hard -"@alcalzone/release-script-plugin-changelog@npm:3.5.9": - version: 3.5.9 - resolution: "@alcalzone/release-script-plugin-changelog@npm:3.5.9" +"@alcalzone/release-script-plugin-changelog@npm:3.7.0": + version: 3.7.0 + resolution: "@alcalzone/release-script-plugin-changelog@npm:3.7.0" dependencies: - "@alcalzone/release-script-core": 3.5.9 + "@alcalzone/release-script-core": 3.7.0 alcalzone-shared: ^4.0.1 fs-extra: ^10.1.0 - checksum: cf00f84f4ab283ab79e923e4d73c469f79c55614944f980e51e44114ac0a9a1e274d12fb4bdc3f28d72433ee5d74a3d1682b176fcc3814ec1dfd39b9376dde28 + checksum: 1b87cdba0574aba7031940c73e44604ead29d21a28853d7f79ddef9b8dd3ea4355e5ad9f8be447878e96f927a0016a92404d6599f08aa7b810e8dedb179a1cd7 languageName: node linkType: hard -"@alcalzone/release-script-plugin-exec@npm:3.5.9": - version: 3.5.9 - resolution: "@alcalzone/release-script-plugin-exec@npm:3.5.9" +"@alcalzone/release-script-plugin-exec@npm:3.7.0": + version: 3.7.0 + resolution: "@alcalzone/release-script-plugin-exec@npm:3.7.0" dependencies: - "@alcalzone/release-script-core": 3.5.9 + "@alcalzone/release-script-core": 3.7.0 alcalzone-shared: ^4.0.1 - checksum: 509315a08258819324717730d0c95ee6de815e73f9a5a1bf36508b80b95a48b80f171ad0574effd8d2b835a2d703ebf3c849354b67b8aed5e0d13f39493566f8 + checksum: dbcfaec24a5d546e996dea2b201cc32b2279f4dd579f9a362bb56e4e0e5cb6481ab8db6d15be22b8f3e7fce2b8642384fcbc2e8fac5074bc61ab0a4f688aa4cd languageName: node linkType: hard -"@alcalzone/release-script-plugin-git@npm:3.6.0": - version: 3.6.0 - resolution: "@alcalzone/release-script-plugin-git@npm:3.6.0" +"@alcalzone/release-script-plugin-git@npm:3.7.0": + version: 3.7.0 + resolution: "@alcalzone/release-script-plugin-git@npm:3.7.0" dependencies: - "@alcalzone/release-script-core": 3.5.9 + "@alcalzone/release-script-core": 3.7.0 fs-extra: ^10.1.0 - checksum: 715151e46816ba18102bcd62775e9cdd238a48dfbf274f8616a21d394ff656f4cdc215309c89422e2ee944a77ee1887f4c39848c761d388b5a9adf486e2b189e + checksum: b7c9a26cc63d852e76930d392b12b854c063474cb08895ba691454f7900f151bdb6ec1a3017328b126e34940b38d8b83d5133ba6052bf5b374ea62d074beea54 languageName: node linkType: hard -"@alcalzone/release-script-plugin-package@npm:3.6.0": - version: 3.6.0 - resolution: "@alcalzone/release-script-plugin-package@npm:3.6.0" +"@alcalzone/release-script-plugin-package@npm:3.7.0": + version: 3.7.0 + resolution: "@alcalzone/release-script-plugin-package@npm:3.7.0" dependencies: - "@alcalzone/pak": ^0.8.1 - "@alcalzone/release-script-core": 3.5.9 + "@alcalzone/pak": ^0.10.1 + "@alcalzone/release-script-core": 3.7.0 alcalzone-shared: ^4.0.1 fs-extra: ^10.1.0 semver: ^7.5.2 - checksum: 384040b7c685af4581d91a33c3cf3782ad88026f390213b3ab65ed71de3efa8cd88bbf46dab6940666b1ce2fc614498cf01a5ced8a4eefe64b3107172fc01df2 + checksum: 5b616e5009de1fdecf3bcb74e3a5a84d0a6b6621176c32836c57f778c0cc8711ded1a20068d085a577644d17123e6496e18ed6b6c0d6a034a031616692b6c103 languageName: node linkType: hard -"@alcalzone/release-script-plugin-version@npm:3.6.0": - version: 3.6.0 - resolution: "@alcalzone/release-script-plugin-version@npm:3.6.0" +"@alcalzone/release-script-plugin-version@npm:3.7.0": + version: 3.7.0 + resolution: "@alcalzone/release-script-plugin-version@npm:3.7.0" dependencies: - "@alcalzone/release-script-core": 3.5.9 + "@alcalzone/release-script-core": 3.7.0 alcalzone-shared: ^4.0.1 fs-extra: ^10.1.0 semver: ^7.5.2 tiny-glob: ^0.2.9 - checksum: 53a80a304880936d3e8b9d9e01acd7f911f2723157a28d069f7174b8fb150f097bc728eaecaf1cd917b3de3b94352e0b5e742057e8323b64bea09106d08808c3 + checksum: 793ee254115aa212f281f1e6c4c32e74cd94723abb77f81f79add9563525624dc3aecfe8047ebc632ccc7d390c3b32779413047180aca9e6ff9c846b230cee9b languageName: node linkType: hard -"@alcalzone/release-script@npm:~3.6.0": - version: 3.6.0 - resolution: "@alcalzone/release-script@npm:3.6.0" - dependencies: - "@alcalzone/release-script-core": 3.5.9 - "@alcalzone/release-script-plugin-changelog": 3.5.9 - "@alcalzone/release-script-plugin-exec": 3.5.9 - "@alcalzone/release-script-plugin-git": 3.6.0 - "@alcalzone/release-script-plugin-package": 3.6.0 - "@alcalzone/release-script-plugin-version": 3.6.0 +"@alcalzone/release-script@npm:~3.7.0": + version: 3.7.0 + resolution: "@alcalzone/release-script@npm:3.7.0" + dependencies: + "@alcalzone/release-script-core": 3.7.0 + "@alcalzone/release-script-plugin-changelog": 3.7.0 + "@alcalzone/release-script-plugin-exec": 3.7.0 + "@alcalzone/release-script-plugin-git": 3.7.0 + "@alcalzone/release-script-plugin-package": 3.7.0 + "@alcalzone/release-script-plugin-version": 3.7.0 alcalzone-shared: ^4.0.1 - axios: ^0.27.1 + axios: ^1.6.2 enquirer: ^2.3.6 fs-extra: ^10.1.0 picocolors: 1.0.0 @@ -204,7 +193,7 @@ __metadata: yargs: ^17.4.1 bin: release-script: bin/release.js - checksum: 99fc888fea726f032130a274691f464252c5ac8266a22184c929237cb3421c04a517a75446d95aa448c2f804c198886a174fb3308847d64946530fdb8e5003d3 + checksum: 93bc69b19828b2da1843e3ec5a6060db282e0c6cbff44d757b4b9a21f44fab3a643fe977be74d6d93830828f63a215ac4a9644e3938359af8279a5fc0fec6a64 languageName: node linkType: hard @@ -2134,8 +2123,8 @@ __metadata: "@actions/exec": ^1.1.1 "@actions/github": ^5.0.3 "@alcalzone/jsonl-db": ^3.1.0 - "@alcalzone/monopack": ^1.2.1 - "@alcalzone/release-script": ~3.6.0 + "@alcalzone/monopack": ^1.2.2 + "@alcalzone/release-script": ~3.7.0 "@commitlint/cli": ^17.7.1 "@commitlint/config-conventional": ^17.7.0 "@dprint/formatter": ^0.2.0 @@ -2709,22 +2698,14 @@ __metadata: languageName: node linkType: hard -"axios@npm:^0.26.0": - version: 0.26.0 - resolution: "axios@npm:0.26.0" +"axios@npm:^1.6.2": + version: 1.6.2 + resolution: "axios@npm:1.6.2" dependencies: - follow-redirects: ^1.14.8 - checksum: d7a8b898f4157bedeb2e06c03b16133b91b354c041205bea732ce58b7a21f373d22057b0eea0d482838145ce6ff482b359750d9bcb8dd19d45e3928e3c65c280 - languageName: node - linkType: hard - -"axios@npm:^0.27.1, axios@npm:^0.27.2": - version: 0.27.2 - resolution: "axios@npm:0.27.2" - dependencies: - follow-redirects: ^1.14.9 + follow-redirects: ^1.15.0 form-data: ^4.0.0 - checksum: 38cb7540465fe8c4102850c4368053c21683af85c5fdf0ea619f9628abbcb59415d1e22ebc8a6390d2bbc9b58a9806c874f139767389c862ec9b772235f06854 + proxy-from-env: ^1.1.0 + checksum: 4a7429e2b784be0f2902ca2680964391eae7236faa3967715f30ea45464b98ae3f1c6f631303b13dfe721b17126b01f486c7644b9ef276bfc63112db9fd379f8 languageName: node linkType: hard @@ -4365,7 +4346,7 @@ __metadata: languageName: node linkType: hard -"execa@npm:~5.0.0": +"execa@npm:~5.0.1": version: 5.0.1 resolution: "execa@npm:5.0.1" dependencies: @@ -4633,13 +4614,13 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.14.8, follow-redirects@npm:^1.14.9": - version: 1.14.9 - resolution: "follow-redirects@npm:1.14.9" +"follow-redirects@npm:^1.15.0": + version: 1.15.3 + resolution: "follow-redirects@npm:1.15.3" peerDependenciesMeta: debug: optional: true - checksum: f5982e0eb481818642492d3ca35a86989c98af1128b8e1a62911a3410621bc15d2b079e8170b35b19d3bdee770b73ed431a257ed86195af773771145baa57845 + checksum: 584da22ec5420c837bd096559ebfb8fe69d82512d5585004e36a3b4a6ef6d5905780e0c74508c7b72f907d1fa2b7bd339e613859e9c304d0dc96af2027fd0231 languageName: node linkType: hard @@ -4684,17 +4665,6 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^10.0.1": - version: 10.0.1 - resolution: "fs-extra@npm:10.0.1" - dependencies: - graceful-fs: ^4.2.0 - jsonfile: ^6.0.1 - universalify: ^2.0.0 - checksum: c1faaa5eb9e1c5c7c7ff09f966e93922ecb068ae1b04801cfc983ef05fcc1f66bfbb8d8d0b745c910014c7a2e7317fb6cf3bfe7390450c1157e3cc1a218f221d - languageName: node - linkType: hard - "fs-extra@npm:^10.1.0": version: 10.1.0 resolution: "fs-extra@npm:10.1.0" @@ -7315,6 +7285,13 @@ __metadata: languageName: node linkType: hard +"proxy-from-env@npm:^1.1.0": + version: 1.1.0 + resolution: "proxy-from-env@npm:1.1.0" + checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 + languageName: node + linkType: hard + "proxyquire@npm:^2.1.3": version: 2.1.3 resolution: "proxyquire@npm:2.1.3" @@ -9259,7 +9236,7 @@ __metadata: resolution: "zwave-js@workspace:packages/zwave-js" dependencies: "@alcalzone/jsonl-db": ^3.1.0 - "@alcalzone/pak": ^0.9.0 + "@alcalzone/pak": ^0.10.1 "@microsoft/api-extractor": ^7.37.3 "@types/fs-extra": ^11.0.1 "@types/node": ^18.17.14 From 47e10596d4d195e8f8584e7858c29b252f2e3b15 Mon Sep 17 00:00:00 2001 From: Dominic Griesel Date: Wed, 29 Nov 2023 14:45:30 +0100 Subject: [PATCH 08/20] chore: release v12.3.2 ### Config file changes * Correct firmware version condition for Zooz ZSE40 v3.0 (#6519) ### Changes under the hood * Add mocks for `Multilevel Sensor CC` * Upgrade transitive dependency `axios` to a non-vulnerable version (#6520) --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- packages/cc/package.json | 2 +- packages/config/package.json | 2 +- packages/flash/package.json | 2 +- packages/host/package.json | 2 +- packages/serial/package.json | 2 +- packages/testing/package.json | 2 +- packages/zwave-js/package.json | 2 +- 9 files changed, 16 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56c4cdfbed7f..745c3f85f27f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ +## 12.3.2 (2023-11-29) +### Config file changes +* Correct firmware version condition for Zooz ZSE40 v3.0 (#6519) + +### Changes under the hood +* Add mocks for `Multilevel Sensor CC` +* Upgrade transitive dependency `axios` to a non-vulnerable version (#6520) + ## 12.3.1 (2023-11-20) ### Bugfixes * Fixed an issue where the unresponsive controller recovery could put "immediate" commands to a sleeping node on the wrong queue, blocking all outgoing communication (#6507) diff --git a/package.json b/package.json index eb0e033579c8..2f20dd6e9cd3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/repo", - "version": "12.3.1", + "version": "12.3.2", "private": true, "description": "Z-Wave driver written entirely in JavaScript/TypeScript", "keywords": [], diff --git a/packages/cc/package.json b/packages/cc/package.json index 16ffd621333c..2190d69d0fef 100644 --- a/packages/cc/package.json +++ b/packages/cc/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/cc", - "version": "12.3.1", + "version": "12.3.2", "description": "zwave-js: Command Classes", "keywords": [], "publishConfig": { diff --git a/packages/config/package.json b/packages/config/package.json index e82143820225..4c89cfe690d6 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/config", - "version": "12.3.1", + "version": "12.3.2", "description": "zwave-js: configuration files", "publishConfig": { "access": "public" diff --git a/packages/flash/package.json b/packages/flash/package.json index c730e796eaa1..9a8645c21b93 100644 --- a/packages/flash/package.json +++ b/packages/flash/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/flash", - "version": "12.3.1", + "version": "12.3.2", "description": "zwave-js: firmware flash utility", "keywords": [], "publishConfig": { diff --git a/packages/host/package.json b/packages/host/package.json index 923777379aaa..d3174ed9ee93 100644 --- a/packages/host/package.json +++ b/packages/host/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/host", - "version": "12.3.1", + "version": "12.3.2", "description": "zwave-js: Host abstractions", "keywords": [], "publishConfig": { diff --git a/packages/serial/package.json b/packages/serial/package.json index 39f7ef65feef..685923660f21 100644 --- a/packages/serial/package.json +++ b/packages/serial/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/serial", - "version": "12.3.1", + "version": "12.3.2", "description": "zwave-js: Serialport driver", "publishConfig": { "access": "public" diff --git a/packages/testing/package.json b/packages/testing/package.json index 609a06c58aa6..7ebd9047c236 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/testing", - "version": "12.3.1", + "version": "12.3.2", "description": "zwave-js: testing utilities", "keywords": [], "publishConfig": { diff --git a/packages/zwave-js/package.json b/packages/zwave-js/package.json index 06d506f97d48..eb97a4ba5646 100644 --- a/packages/zwave-js/package.json +++ b/packages/zwave-js/package.json @@ -1,6 +1,6 @@ { "name": "zwave-js", - "version": "12.3.1", + "version": "12.3.2", "description": "Z-Wave driver written entirely in JavaScript/TypeScript", "keywords": [], "main": "build/index.js", From a58ec5d54f1d13f16f820151a2a7d421aea6ab00 Mon Sep 17 00:00:00 2001 From: AlCalzone Date: Thu, 30 Nov 2023 12:32:39 +0100 Subject: [PATCH 09/20] feat: expose rebuild routes progress as a controller property (#6525) --- docs/api/controller.md | 8 ++++++++ .../zwave-js/src/lib/controller/Controller.ts | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/docs/api/controller.md b/docs/api/controller.md index b8782393cd2e..185c6f24ff29 100644 --- a/docs/api/controller.md +++ b/docs/api/controller.md @@ -1233,6 +1233,14 @@ readonly isRebuildingRoutes: boolean; Returns whether the routes are currently being rebuilt for one or more nodes. +### `rebuildRoutesProgress` + +```ts +readonly rebuildRoutesProgress: ReadonlyMap | 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. + ### `inclusionState` ```ts diff --git a/packages/zwave-js/src/lib/controller/Controller.ts b/packages/zwave-js/src/lib/controller/Controller.ts index 2b9f78fe5f60..5b2fbac08a32 100644 --- a/packages/zwave-js/src/lib/controller/Controller.ts +++ b/packages/zwave-js/src/lib/controller/Controller.ts @@ -3890,6 +3890,20 @@ supported CCs: ${ } private _rebuildRoutesProgress = new Map(); + /** + * If routes are currently being rebuilt for the entire network, this returns the current progress. + * The information is the same as in the `"rebuild routes progress"` event. + */ + public get rebuildRoutesProgress(): + | ReadonlyMap< + number, + RebuildRoutesStatus + > + | undefined + { + if (!this._isRebuildingRoutes) return undefined; + return new Map(this._rebuildRoutesProgress); + } /** * Starts the process of rebuilding routes for all alive nodes in the network, @@ -4053,6 +4067,7 @@ supported CCs: ${ } // We're done! this._isRebuildingRoutes = false; + this._rebuildRoutesProgress.clear(); } /** @@ -4073,6 +4088,8 @@ supported CCs: ${ || t.message instanceof AssignReturnRouteRequest, ); + this._rebuildRoutesProgress.clear(); + return true; } From 2c5e226d06b4a61dbe4e7ff0f0778978c4a0b9f8 Mon Sep 17 00:00:00 2001 From: Z-Wave JS Bot <76957017+zwave-js-bot@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:01:09 +0100 Subject: [PATCH 10/20] =?UTF-8?q?docs:=20update=20typed=20documentation=20?= =?UTF-8?q?and=20API=20report=20=F0=9F=A4=96=20(#6486)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Al Calzone --- packages/cc/api.md | 32 ++++++++++++++++++++++++++++---- packages/cc/src/cc/index.ts | 2 ++ packages/core/api.md | 24 +++++++++++------------- packages/testing/api.md | 15 +++++++++++++++ packages/zwave-js/api.md | 1 + 5 files changed, 57 insertions(+), 17 deletions(-) diff --git a/packages/cc/api.md b/packages/cc/api.md index df29f37daf91..4c775cc6c929 100644 --- a/packages/cc/api.md +++ b/packages/cc/api.md @@ -1723,6 +1723,8 @@ export class BasicCC extends CommandClass { // (undocumented) ccCommand: BasicCommand; // (undocumented) + getDefinedValueIDs(applHost: ZWaveApplicationHost_2): ValueID_2[]; + // (undocumented) interview(applHost: ZWaveApplicationHost_2): Promise; // (undocumented) refreshValues(applHost: ZWaveApplicationHost_2): Promise; @@ -1811,7 +1813,7 @@ export const BasicCCValues: Readonly<{ readonly minVersion: 1; readonly supportsEndpoints: true; readonly stateful: false; - readonly autoCreate: (applHost: ZWaveApplicationHost_2, endpoint: IZWaveEndpoint_2) => boolean; + readonly autoCreate: false; }; }; restorePrevious: { @@ -12133,26 +12135,48 @@ export interface MultilevelSensorCCReportOptions extends CCCommandOptions { // // @public (undocumented) export class MultilevelSensorCCSupportedScaleReport extends MultilevelSensorCC { - constructor(host: ZWaveHost_2, options: CommandClassDeserializationOptions); + constructor(host: ZWaveHost_2, options: CommandClassDeserializationOptions | MultilevelSensorCCSupportedScaleReportOptions); // (undocumented) readonly sensorType: number; // (undocumented) + serialize(): Buffer; + // (undocumented) readonly supportedScales: readonly number[]; // (undocumented) toLogEntry(applHost: ZWaveApplicationHost_2): MessageOrCCLogEntry_2; } +// Warning: (ae-missing-release-tag) "MultilevelSensorCCSupportedScaleReportOptions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface MultilevelSensorCCSupportedScaleReportOptions extends CCCommandOptions { + // (undocumented) + sensorType: number; + // (undocumented) + supportedScales: readonly number[]; +} + // Warning: (ae-missing-release-tag) "MultilevelSensorCCSupportedSensorReport" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) export class MultilevelSensorCCSupportedSensorReport extends MultilevelSensorCC { - constructor(host: ZWaveHost_2, options: CommandClassDeserializationOptions); + constructor(host: ZWaveHost_2, options: CommandClassDeserializationOptions | MultilevelSensorCCSupportedSensorReportOptions); + // (undocumented) + serialize(): Buffer; // (undocumented) - readonly supportedSensorTypes: readonly number[]; + supportedSensorTypes: readonly number[]; // (undocumented) toLogEntry(applHost: ZWaveApplicationHost_2): MessageOrCCLogEntry_2; } +// Warning: (ae-missing-release-tag) "MultilevelSensorCCSupportedSensorReportOptions" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface MultilevelSensorCCSupportedSensorReportOptions extends CCCommandOptions { + // (undocumented) + supportedSensorTypes: readonly number[]; +} + // Warning: (ae-missing-release-tag) "MultilevelSensorCCValues" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/packages/cc/src/cc/index.ts b/packages/cc/src/cc/index.ts index 709b3f9fce7c..05d329ac5f5f 100644 --- a/packages/cc/src/cc/index.ts +++ b/packages/cc/src/cc/index.ts @@ -444,6 +444,8 @@ export type { MultilevelSensorCCGetOptions, MultilevelSensorCCGetSupportedScaleOptions, MultilevelSensorCCReportOptions, + MultilevelSensorCCSupportedScaleReportOptions, + MultilevelSensorCCSupportedSensorReportOptions, } from "./MultilevelSensorCC"; export { MultilevelSensorCC, diff --git a/packages/core/api.md b/packages/core/api.md index e5ce67b4341e..7a53ef036b8d 100644 --- a/packages/core/api.md +++ b/packages/core/api.md @@ -3267,26 +3267,24 @@ export enum ZWaveErrorCodes { ConfigurationCC_NoResetToDefaultOnLegacyDevices = 1002, // (undocumented) Controller_CallbackNOK = 204, + Controller_CommandError = 215, + Controller_EndpointNotFound = 211, // (undocumented) - Controller_CommandAborted = 206, - Controller_CommandError = 216, - Controller_EndpointNotFound = 212, + Controller_ExclusionFailed = 207, // (undocumented) - Controller_ExclusionFailed = 208, - // (undocumented) - Controller_InclusionFailed = 207, - Controller_InterviewRestarted = 210, + Controller_InclusionFailed = 206, + Controller_InterviewRestarted = 209, // (undocumented) Controller_Jammed = 205, // (undocumented) Controller_MessageDropped = 202, - Controller_MessageExpired = 215, - Controller_MessageTooLarge = 217, - Controller_NodeInsecureCommunication = 214, - Controller_NodeNotFound = 211, - Controller_NodeRemoved = 213, + Controller_MessageExpired = 214, + Controller_MessageTooLarge = 216, + Controller_NodeInsecureCommunication = 213, + Controller_NodeNotFound = 210, + Controller_NodeRemoved = 212, Controller_NodeTimeout = 201, - Controller_NotSupported = 209, + Controller_NotSupported = 208, // (undocumented) Controller_ResponseNOK = 203, Controller_Timeout = 200, diff --git a/packages/testing/api.md b/packages/testing/api.md index 37a70e4023d8..15e65bce0a06 100644 --- a/packages/testing/api.md +++ b/packages/testing/api.md @@ -35,6 +35,7 @@ export type CCIdToCapabilities = T ex export type CCSpecificCapabilities = { [CommandClasses.Configuration]: ConfigurationCCCapabilities; [CommandClasses.Notification]: NotificationCCCapabilities; + [49]: MultilevelSensorCCCapabilities; [121]: SoundSwitchCCCapabilities; [106]: WindowCoveringCCCapabilities; [144]: EnergyProductionCCCapabilities; @@ -170,6 +171,8 @@ export class MockController { get nodes(): ReadonlyMap; onNodeFrame(node: MockNode, frame: MockZWaveFrame): Promise; // (undocumented) + get receivedHostMessages(): readonly Readonly[]; + // (undocumented) removeNode(node: MockNode): void; sendToHost(data: Buffer): Promise; sendToNode(node: MockNode, frame: LazyMockZWaveFrame): Promise; @@ -340,6 +343,18 @@ export interface MockZWaveRequestFrame { type: MockZWaveFrameType.Request; } +// Warning: (ae-missing-release-tag) "MultilevelSensorCCCapabilities" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface MultilevelSensorCCCapabilities { + // (undocumented) + getValue?: (sensorType: number | undefined, scale: number | undefined) => number | undefined; + // (undocumented) + sensors: Record; +} + // Warning: (ae-missing-release-tag) "NotificationCCCapabilities" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/packages/zwave-js/api.md b/packages/zwave-js/api.md index d95df676473d..653f0320ca84 100644 --- a/packages/zwave-js/api.md +++ b/packages/zwave-js/api.md @@ -1257,6 +1257,7 @@ export class ZWaveController extends TypedEventEmitter get protocolVersion(): MaybeNotKnown; provisionSmartStartNode(entry: PlannedProvisioningEntry): void; rebuildNodeRoutes(nodeId: number): Promise; + get rebuildRoutesProgress(): ReadonlyMap | undefined; removeAssociations(source: AssociationAddress, group: number, destinations: AssociationAddress[]): Promise; // Warning: (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen removeFailedNode(nodeId: number): Promise; From b4fb2b5c96cef1b5a11b3dce3e5befc3e4249028 Mon Sep 17 00:00:00 2001 From: AlCalzone Date: Thu, 30 Nov 2023 14:02:22 +0100 Subject: [PATCH 11/20] fix: only expose currentValue on devices that use Basic CC for reporting (#6526) --- maintenance/schemas/deviceClasses.json | 6 +++ packages/cc/src/cc/BasicCC.ts | 5 +- packages/config/config/deviceClasses.json | 18 ++++++-- packages/config/src/DeviceClasses.ts | 32 +++++++++++++ packages/zwave-js/src/lib/node/Endpoint.ts | 25 +++++++++- packages/zwave-js/src/lib/node/Node.ts | 7 +++ .../basicCCSupportWhenForbidden.test.ts | 46 +++++++++++++++++++ 7 files changed, 132 insertions(+), 7 deletions(-) create mode 100644 packages/zwave-js/src/lib/test/compat/basicCCSupportWhenForbidden.test.ts diff --git a/maintenance/schemas/deviceClasses.json b/maintenance/schemas/deviceClasses.json index 23c1a8dd3b1e..0f7d1820d169 100644 --- a/maintenance/schemas/deviceClasses.json +++ b/maintenance/schemas/deviceClasses.json @@ -28,6 +28,9 @@ "controlledCCs": { "$ref": "#/definitions/CCs" }, + "maySupportBasicCC": { + "const": false + }, "specific": { "type": "object", "patternProperties": { @@ -45,6 +48,9 @@ }, "controlledCCs": { "$ref": "#/definitions/CCs" + }, + "maySupportBasicCC": { + "const": false } }, "required": ["label"], diff --git a/packages/cc/src/cc/BasicCC.ts b/packages/cc/src/cc/BasicCC.ts index f3b01217c89c..484c815aea9d 100644 --- a/packages/cc/src/cc/BasicCC.ts +++ b/packages/cc/src/cc/BasicCC.ts @@ -327,12 +327,15 @@ remaining duration: ${basicResponse.duration?.toString() ?? "undefined"}`; ret.push(...super.getDefinedValueIDs(applHost)); } - // Add the compat event value if it should be exposed if ( !!applHost.getDeviceConfig?.(endpoint.nodeId)?.compat ?.treatBasicSetAsEvent ) { + // Add the compat event value if it should be exposed ret.push(BasicCCValues.compatEvent.endpoint(endpoint.index)); + } else if (endpoint.controlsCC(CommandClasses.Basic)) { + // Otherwise, only expose currentValue on devices that only control Basic CC + ret.push(BasicCCValues.currentValue.endpoint(endpoint.index)); } return ret; diff --git a/packages/config/config/deviceClasses.json b/packages/config/config/deviceClasses.json index e0aaae39e5d4..85f812a8307b 100644 --- a/packages/config/config/deviceClasses.json +++ b/packages/config/config/deviceClasses.json @@ -12,6 +12,7 @@ "0x01": { "label": "Remote Controller", "controlledCCs": ["Basic"], + "maySupportBasicCC": false, "specific": { "0x01": { "label": "Portable Remote Controller", @@ -164,6 +165,7 @@ "0x07": { "label": "Gateway", "zwavePlusDeviceType": "Gateway", + "maySupportBasicCC": false, "supportedCCs": [ "Manufacturer Specific", // "Security", (some devices only support S2) @@ -252,7 +254,8 @@ "specific": { "0x01": { "label": "Notification Sensor", - "zwavePlusDeviceType": "Sensor - Notification" + "zwavePlusDeviceType": "Sensor - Notification", + "maySupportBasicCC": false } } }, @@ -327,11 +330,13 @@ "specific": { "0x01": { "label": "Repeater Slave", - "zwavePlusDeviceType": "Repeater" + "zwavePlusDeviceType": "Repeater", + "maySupportBasicCC": false }, "0x03": { "label": "IR Repeater", "zwavePlusDeviceType": "IR Repeater", + "maySupportBasicCC": false, "supportedCCs": [ "Association", // V2+ "Association Group Information", @@ -624,7 +629,8 @@ "specific": { "0x01": { "label": "Basic Wall Controller", - "zwavePlusDeviceType": "Wall Controller" + "zwavePlusDeviceType": "Wall Controller", + "maySupportBasicCC": false } } }, @@ -643,7 +649,8 @@ "specific": { "0x01": { "label": "Routing Multilevel Sensor", - "zwavePlusDeviceType": "Sensor - Multilevel" + "zwavePlusDeviceType": "Sensor - Multilevel", + "maySupportBasicCC": false } } }, @@ -653,7 +660,7 @@ }, "0x31": { "label": "Meter", - "supportedCCs": ["Basic"], + "maySupportBasicCC": false, "specific": { "0x01": { "label": "Simple Meter", @@ -843,6 +850,7 @@ "label": "Secure Keypad", "zwavePlusDeviceType": "Entry Control Keypad", "requiresSecurity": true, + "maySupportBasicCC": false, "supportedCCs": [ // "Device Reset Locally", (we can't know if the device can be reset) "Entry Control", diff --git a/packages/config/src/DeviceClasses.ts b/packages/config/src/DeviceClasses.ts index afd851d7af90..004324a93970 100644 --- a/packages/config/src/DeviceClasses.ts +++ b/packages/config/src/DeviceClasses.ts @@ -152,6 +152,21 @@ export class GenericDeviceClass { this.controlledCCs = []; } + if (definition.maySupportBasicCC != undefined) { + if (definition.maySupportBasicCC !== false) { + throwInvalidConfig( + "device classes", + `maySupportBasicCC in device class ${this.label} (${ + num2hex(this.key) + }) must be false or omitted (= true)!`, + ); + } else { + this.maySupportBasicCC = false; + } + } else { + this.maySupportBasicCC = true; + } + const specific = new Map(); if (isObject(definition.specific)) { for ( @@ -190,6 +205,7 @@ export class GenericDeviceClass { public readonly requiresSecurity?: boolean; public readonly supportedCCs: readonly CommandClasses[]; public readonly controlledCCs: readonly CommandClasses[]; + public readonly maySupportBasicCC: boolean; public readonly specific: ReadonlyMap; } @@ -312,6 +328,21 @@ export class SpecificDeviceClass { ...generic.controlledCCs, ...this.controlledCCs, ]); + + if (definition.maySupportBasicCC != undefined) { + if (definition.maySupportBasicCC !== false) { + throwInvalidConfig( + "device classes", + `maySupportBasicCC in device class ${generic.label} -> ${this.label} (${ + num2hex(this.key) + }) must be false or omitted (= true)!`, + ); + } else { + this.maySupportBasicCC = false; + } + } else { + this.maySupportBasicCC = true; + } } public readonly key: number; @@ -320,4 +351,5 @@ export class SpecificDeviceClass { public readonly requiresSecurity?: boolean; public readonly supportedCCs: readonly CommandClasses[]; public readonly controlledCCs: readonly CommandClasses[]; + public readonly maySupportBasicCC: boolean; } diff --git a/packages/zwave-js/src/lib/node/Endpoint.ts b/packages/zwave-js/src/lib/node/Endpoint.ts index 6aaa6f75f7c3..ddacfecdc171 100644 --- a/packages/zwave-js/src/lib/node/Endpoint.ts +++ b/packages/zwave-js/src/lib/node/Endpoint.ts @@ -226,16 +226,39 @@ export class Endpoint implements IZWaveEndpoint { return !!this._implementedCommandClasses.get(cc)?.isControlled; } + /** Checks if this device type is allowed to support Basic CC per the specification */ + public maySupportBasicCC(): boolean { + return this.deviceClass?.specific.maySupportBasicCC + ?? this.deviceClass?.generic.maySupportBasicCC + ?? true; + } + /** Adds Basic CC to the supported CCs if no other actuator CCs are supported */ public maybeAddBasicCCAsFallback(): void { if ( !this.supportsCC(CommandClasses.Basic) + && this.maySupportBasicCC() && !actuatorCCs.some((cc) => this.supportsCC(cc)) ) { this.addCC(CommandClasses.Basic, { isSupported: true }); } } + /** Removes the BasicCC from the supported CCs if the device type forbids it */ + public removeBasicCCSupportIfForbidden(): void { + if ( + this.supportsCC(CommandClasses.Basic) + && !this.maySupportBasicCC() + ) { + // We assume that the device reports support for this CC in error, and that it actually controls it. + // TODO: Consider if we should check additional sources, like the issued commands in AGI CC + this.addCC(CommandClasses.Basic, { + isSupported: false, + isControlled: true, + }); + } + } + /** Removes the BasicCC from the supported CCs if any other actuator CCs are supported */ public hideBasicCCInFavorOfActuatorCCs(): void { // This behavior is defined in SDS14223 @@ -246,7 +269,7 @@ export class Endpoint implements IZWaveEndpoint { // Mark the CC as not supported, but remember if it is controlled this.addCC(CommandClasses.Basic, { isSupported: false }); - // If the record is now only a dummy, remove the CC + // If the record is now only a dummy, remove the CC entirely if ( !this.supportsCC(CommandClasses.Basic) && !this.controlsCC(CommandClasses.Basic) diff --git a/packages/zwave-js/src/lib/node/Node.ts b/packages/zwave-js/src/lib/node/Node.ts index d9a12cf74ba8..c292764561d0 100644 --- a/packages/zwave-js/src/lib/node/Node.ts +++ b/packages/zwave-js/src/lib/node/Node.ts @@ -1816,6 +1816,13 @@ export class ZWaveNode extends Endpoint if (this.interviewStage === InterviewStage.NodeInfo) { // Only advance the interview if it was completed, otherwise abort if (await this.interviewCCs()) { + // After interviewing the CCs, we may need to clean up the Basic CC values. + // Some device types are not allowed to support it, but there are devices that do. + // If a device type is forbidden to support Basic CC, remove the "support" portion of it + for (const endpoint of this.getAllEndpoints()) { + endpoint.removeBasicCCSupportIfForbidden(); + } + this.setInterviewStage(InterviewStage.CommandClasses); } else { return false; diff --git a/packages/zwave-js/src/lib/test/compat/basicCCSupportWhenForbidden.test.ts b/packages/zwave-js/src/lib/test/compat/basicCCSupportWhenForbidden.test.ts new file mode 100644 index 000000000000..55fe9ef4043b --- /dev/null +++ b/packages/zwave-js/src/lib/test/compat/basicCCSupportWhenForbidden.test.ts @@ -0,0 +1,46 @@ +import { BasicCCValues } from "@zwave-js/cc"; +import { CommandClasses } from "@zwave-js/core"; +import { integrationTest } from "../integrationTestSuite"; + +integrationTest( + "On devices that MUST not support Basic CC, but use Basic Set to report status, ONLY currentValue should be exposed", + { + // debug: true, + + nodeCapabilities: { + // Routing Multilevel Sensor, MUST not support Basic CC + genericDeviceClass: 0x21, + specificDeviceClass: 0x01, + commandClasses: [ + CommandClasses.Version, + // But it reports support if asked + CommandClasses.Basic, + ], + }, + + async testBody(t, driver, node, mockController, mockNode) { + const valueIDs = node.getDefinedValueIDs(); + t.true( + valueIDs.some((v) => BasicCCValues.currentValue.is(v)), + "Did not find Basic CC currentValue although it should be exposed", + ); + t.false( + valueIDs.some((v) => BasicCCValues.targetValue.is(v)), + "Found Basic CC targetValue although it shouldn't be exposed", + ); + t.false( + valueIDs.some((v) => BasicCCValues.duration.is(v)), + "Found Basic CC duration although it shouldn't be exposed", + ); + t.false( + valueIDs.some((v) => BasicCCValues.restorePrevious.is(v)), + "Found Basic CC restorePrevious although it shouldn't be exposed", + ); + + t.false( + valueIDs.some((v) => BasicCCValues.compatEvent.is(v)), + "Found Basic CC compatEvent although it shouldn't be exposed", + ); + }, + }, +); From e922683399a508e29a2df93eec986a5e053a8df6 Mon Sep 17 00:00:00 2001 From: Z-Wave JS Bot <76957017+zwave-js-bot@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:11:55 +0100 Subject: [PATCH 12/20] =?UTF-8?q?docs:=20update=20typed=20documentation=20?= =?UTF-8?q?and=20API=20report=20=F0=9F=A4=96=20(#6529)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Al Calzone --- docs/api/config-manager.md | 2 ++ docs/api/node.md | 2 ++ packages/config/api.md | 4 ++++ packages/zwave-js/api.md | 2 ++ 4 files changed, 10 insertions(+) diff --git a/docs/api/config-manager.md b/docs/api/config-manager.md index 525e367be8d2..41526d6b0f97 100644 --- a/docs/api/config-manager.md +++ b/docs/api/config-manager.md @@ -415,6 +415,7 @@ interface GenericDeviceClass { readonly requiresSecurity?: boolean; readonly supportedCCs: readonly CommandClasses[]; readonly controlledCCs: readonly CommandClasses[]; + readonly maySupportBasicCC: boolean; readonly specific: ReadonlyMap; } ``` @@ -429,6 +430,7 @@ interface SpecificDeviceClass { readonly requiresSecurity?: boolean; readonly supportedCCs: readonly CommandClasses[]; readonly controlledCCs: readonly CommandClasses[]; + readonly maySupportBasicCC: boolean; } ``` diff --git a/docs/api/node.md b/docs/api/node.md index fafa4af86c46..812162116d52 100644 --- a/docs/api/node.md +++ b/docs/api/node.md @@ -907,6 +907,7 @@ interface GenericDeviceClass { readonly requiresSecurity?: boolean; readonly supportedCCs: readonly CommandClasses[]; readonly controlledCCs: readonly CommandClasses[]; + readonly maySupportBasicCC: boolean; readonly specific: ReadonlyMap; } ``` @@ -921,6 +922,7 @@ interface SpecificDeviceClass { readonly requiresSecurity?: boolean; readonly supportedCCs: readonly CommandClasses[]; readonly controlledCCs: readonly CommandClasses[]; + readonly maySupportBasicCC: boolean; } ``` diff --git a/packages/config/api.md b/packages/config/api.md index 705021e81e9b..19da0602a40e 100644 --- a/packages/config/api.md +++ b/packages/config/api.md @@ -669,6 +669,8 @@ export class GenericDeviceClass { // (undocumented) readonly label: string; // (undocumented) + readonly maySupportBasicCC: boolean; + // (undocumented) readonly requiresSecurity?: boolean; // (undocumented) readonly specific: ReadonlyMap; @@ -975,6 +977,8 @@ export class SpecificDeviceClass { // (undocumented) readonly label: string; // (undocumented) + readonly maySupportBasicCC: boolean; + // (undocumented) readonly requiresSecurity?: boolean; // (undocumented) readonly supportedCCs: readonly CommandClasses[]; diff --git a/packages/zwave-js/api.md b/packages/zwave-js/api.md index 653f0320ca84..524b37d9512d 100644 --- a/packages/zwave-js/api.md +++ b/packages/zwave-js/api.md @@ -536,7 +536,9 @@ export class Endpoint implements IZWaveEndpoint { invokeCCAPI any> = CommandClasses_2 extends CC ? any : Omit extends CC ? any : APIMethodsOf>(cc: CC, method: TMethod, ...args: Parameters): ReturnType; isCCSecure(cc: CommandClasses_2): boolean; maybeAddBasicCCAsFallback(): void; + maySupportBasicCC(): boolean; readonly nodeId: number; + removeBasicCCSupportIfForbidden(): void; removeCC(cc: CommandClasses_2): void; protected reset(): void; supportsCC(cc: CommandClasses_2): boolean; From 222c2424c72be72e8f52e924510927b0aa278d7e Mon Sep 17 00:00:00 2001 From: Dominic Griesel Date: Thu, 30 Nov 2023 12:38:26 +0100 Subject: [PATCH 13/20] chore: update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 745c3f85f27f..86c5270f7a75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ +## __WORK IN PROGRESS__ +### Features +* Expose rebuild routes progress as a controller property (#6525) + +### Bugfixes +* On devices that should/must not support `Basic CC`, but use it for reporting, only the `currentValue` is now exposed. This allows applications to consider it a sensor, not an actor (#6526) + ## 12.3.2 (2023-11-29) ### Config file changes * Correct firmware version condition for Zooz ZSE40 v3.0 (#6519) From 66ad62cef791a2a78b7538da81d251e25bf4edae Mon Sep 17 00:00:00 2001 From: Dominic Griesel Date: Thu, 30 Nov 2023 14:13:56 +0100 Subject: [PATCH 14/20] chore: release v12.4.0 ### Features * Expose rebuild routes progress as a controller property (#6525) ### Bugfixes * On devices that should/must not support `Basic CC`, but use it for reporting, only the `currentValue` is now exposed. This allows applications to consider it a sensor, not an actor (#6526) --- CHANGELOG.md | 2 +- package.json | 2 +- packages/cc/package.json | 2 +- packages/config/package.json | 2 +- packages/core/package.json | 2 +- packages/eslint-plugin/package.json | 2 +- packages/flash/package.json | 2 +- packages/host/package.json | 2 +- packages/maintenance/package.json | 2 +- packages/nvmedit/package.json | 2 +- packages/serial/package.json | 2 +- packages/testing/package.json | 2 +- packages/zwave-js/package.json | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86c5270f7a75..1a28a39b0276 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ -## __WORK IN PROGRESS__ +## 12.4.0 (2023-11-30) ### Features * Expose rebuild routes progress as a controller property (#6525) diff --git a/package.json b/package.json index 2f20dd6e9cd3..27e7e8c67ea3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/repo", - "version": "12.3.2", + "version": "12.4.0", "private": true, "description": "Z-Wave driver written entirely in JavaScript/TypeScript", "keywords": [], diff --git a/packages/cc/package.json b/packages/cc/package.json index 2190d69d0fef..64791d3e69fa 100644 --- a/packages/cc/package.json +++ b/packages/cc/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/cc", - "version": "12.3.2", + "version": "12.4.0", "description": "zwave-js: Command Classes", "keywords": [], "publishConfig": { diff --git a/packages/config/package.json b/packages/config/package.json index 4c89cfe690d6..e3381b67378a 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/config", - "version": "12.3.2", + "version": "12.4.0", "description": "zwave-js: configuration files", "publishConfig": { "access": "public" diff --git a/packages/core/package.json b/packages/core/package.json index a11146c7aa6e..2bcd61e7c361 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/core", - "version": "12.3.0", + "version": "12.4.0", "description": "zwave-js: core components", "keywords": [], "publishConfig": { diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 0aa3f6f62af8..5b0253c08fc6 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/eslint-plugin", - "version": "12.3.0", + "version": "12.4.0", "description": "zwave-js: custom ESLint rules", "private": true, "keywords": [], diff --git a/packages/flash/package.json b/packages/flash/package.json index 9a8645c21b93..0f36a1681b24 100644 --- a/packages/flash/package.json +++ b/packages/flash/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/flash", - "version": "12.3.2", + "version": "12.4.0", "description": "zwave-js: firmware flash utility", "keywords": [], "publishConfig": { diff --git a/packages/host/package.json b/packages/host/package.json index d3174ed9ee93..2599b8bb2acf 100644 --- a/packages/host/package.json +++ b/packages/host/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/host", - "version": "12.3.2", + "version": "12.4.0", "description": "zwave-js: Host abstractions", "keywords": [], "publishConfig": { diff --git a/packages/maintenance/package.json b/packages/maintenance/package.json index e1523b56738f..54dcf5692314 100644 --- a/packages/maintenance/package.json +++ b/packages/maintenance/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/maintenance", - "version": "12.3.0", + "version": "12.4.0", "description": "zwave-js: maintenance scripts", "private": true, "keywords": [], diff --git a/packages/nvmedit/package.json b/packages/nvmedit/package.json index 5728f9c44fd0..47dbae2afd8d 100644 --- a/packages/nvmedit/package.json +++ b/packages/nvmedit/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/nvmedit", - "version": "12.3.0", + "version": "12.4.0", "description": "zwave-js: library to edit NVM backups", "keywords": [], "publishConfig": { diff --git a/packages/serial/package.json b/packages/serial/package.json index 685923660f21..345173c93b2c 100644 --- a/packages/serial/package.json +++ b/packages/serial/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/serial", - "version": "12.3.2", + "version": "12.4.0", "description": "zwave-js: Serialport driver", "publishConfig": { "access": "public" diff --git a/packages/testing/package.json b/packages/testing/package.json index 7ebd9047c236..f840d897783e 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/testing", - "version": "12.3.2", + "version": "12.4.0", "description": "zwave-js: testing utilities", "keywords": [], "publishConfig": { diff --git a/packages/zwave-js/package.json b/packages/zwave-js/package.json index eb97a4ba5646..22d34fe9530b 100644 --- a/packages/zwave-js/package.json +++ b/packages/zwave-js/package.json @@ -1,6 +1,6 @@ { "name": "zwave-js", - "version": "12.3.2", + "version": "12.4.0", "description": "Z-Wave driver written entirely in JavaScript/TypeScript", "keywords": [], "main": "build/index.js", From 00b09b1fb4c173b47203a0e62c81672ec3a27c6b Mon Sep 17 00:00:00 2001 From: The00Dustin <91274634+The00Dustin@users.noreply.github.com> Date: Fri, 8 Dec 2023 16:08:25 -0500 Subject: [PATCH 15/20] fix(config): correct parameter 5 size for Zooz ZEN34 (#6546) --- packages/config/config/devices/0x027a/zen34.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/config/config/devices/0x027a/zen34.json b/packages/config/config/devices/0x027a/zen34.json index 8d5a2e0a703a..2208d270e45f 100644 --- a/packages/config/config/devices/0x027a/zen34.json +++ b/packages/config/config/devices/0x027a/zen34.json @@ -156,7 +156,7 @@ "#": "5", "$if": "firmwareVersion >= 1.40", "label": "Dimmer Control Group: Dimming Duration", - "valueSize": 2, + "valueSize": 1, "unit": "seconds", "minValue": 1, "maxValue": 99, From c3f1e1aa1e7e82b38de8340438d898cd69470ed5 Mon Sep 17 00:00:00 2001 From: The00Dustin <91274634+The00Dustin@users.noreply.github.com> Date: Sat, 9 Dec 2023 07:38:04 -0500 Subject: [PATCH 16/20] fix(config): add wakeup instructions for Nexia ZSENS930 (#6545) --- packages/config/config/devices/0x0178/ZSENS930.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/config/config/devices/0x0178/ZSENS930.json b/packages/config/config/devices/0x0178/ZSENS930.json index dc1552f51193..746a41522073 100644 --- a/packages/config/config/devices/0x0178/ZSENS930.json +++ b/packages/config/config/devices/0x0178/ZSENS930.json @@ -328,6 +328,7 @@ "metadata": { "inclusion": "Set your primary controller into inclusion mode. Press and release the \"Install\" button on the sensor. The \"Status\" LED will blink rapidly for 3 seconds indicating successful inclusion into the network", "exclusion": "Set your primary controller into exclusion mode. Press and release the \"Install\" button on the sensor. The \"Status\" LED will blink rapidly for 3 seconds indicating successful exclusion from the network", - "reset": "Press and hold Install button for 10 seconds. Factory Reset should only be used if the primary controller is missing or inoperable." + "reset": "Press and hold the \"Install\" button for 10 seconds. Factory Reset should only be used if the primary controller is missing or inoperable.", + "wakeup": "Press the \"Install\" button three times rapidly to send a \"BATTERY_REPORT\" and \"WAKE_UP_NOTIFICATION\" (if installed on a network). The sensor will stay awake for 30 seconds." } } From d045267ecb6f0cfd13005f955bca1da33e98e8b9 Mon Sep 17 00:00:00 2001 From: AlCalzone Date: Sat, 9 Dec 2023 13:41:30 +0100 Subject: [PATCH 17/20] fix: handle more cases of unexpected Serial API restart (#6551) --- .../zwave-js/src/lib/controller/Controller.ts | 37 ++++++++++++------- .../application/SerialAPIStartedRequest.ts | 2 +- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/packages/zwave-js/src/lib/controller/Controller.ts b/packages/zwave-js/src/lib/controller/Controller.ts index 5b2fbac08a32..4428f4170567 100644 --- a/packages/zwave-js/src/lib/controller/Controller.ts +++ b/packages/zwave-js/src/lib/controller/Controller.ts @@ -3867,23 +3867,32 @@ supported CCs: ${ private async handleSerialAPIStartedUnexpectedly( msg: SerialAPIStartedRequest, ): Promise { - // Normally, the soft reset command includes waiting for this message. If we end up here, it is unexpected. + // Normally, the soft reset command includes waiting for this message. + // If we end up here, it is unexpected. + + switch (msg.wakeUpReason) { + // All wakeup reasons that indicate a reset of the Serial API + // need to be handled here, so we interpret node IDs correctly. + case SerialAPIWakeUpReason.Reset: + case SerialAPIWakeUpReason.WatchdogReset: + case SerialAPIWakeUpReason.SoftwareReset: + case SerialAPIWakeUpReason.EmergencyWatchdogReset: + case SerialAPIWakeUpReason.BrownoutCircuit: { + // The Serial API restarted unexpectedly + if (this._nodeIdType === NodeIDType.Long) { + this.driver.controllerLog.print( + `Serial API restarted unexpectedly.`, + "warn", + ); - if (msg.wakeUpReason === SerialAPIWakeUpReason.SoftwareReset) { - // The Serial API restarted - if (this._nodeIdType === NodeIDType.Long) { - this.driver.controllerLog.print( - `Serial API restarted unexpectedly.`, - "warn", - ); + // We previously used 16 bit node IDs, but the controller was reset. + // Remember this and try to go back to 16 bit. + this._nodeIdType = NodeIDType.Short; + await this.trySetNodeIDType(NodeIDType.Long); + } - // We previously used 16 bit node IDs, but the controller was reset. - // Remember this and try to go back to 16 bit. - this._nodeIdType = NodeIDType.Short; - await this.trySetNodeIDType(NodeIDType.Long); + return true; // Don't invoke any more handlers } - - return true; // Don't invoke any more handlers } return false; // Not handled diff --git a/packages/zwave-js/src/lib/serialapi/application/SerialAPIStartedRequest.ts b/packages/zwave-js/src/lib/serialapi/application/SerialAPIStartedRequest.ts index 93a1229ef7b6..3fffcdbd9b5b 100644 --- a/packages/zwave-js/src/lib/serialapi/application/SerialAPIStartedRequest.ts +++ b/packages/zwave-js/src/lib/serialapi/application/SerialAPIStartedRequest.ts @@ -29,7 +29,7 @@ export enum SerialAPIWakeUpReason { WatchdogReset = 0x03, /** The Z-Wave API Module has been woken up by an external interrupt. */ ExternalInterrupt = 0x04, - /** The Z-Wave API Module has been woken up by a powering up. */ + /** The Z-Wave API Module has been woken up by powering up. */ PowerUp = 0x05, /** The Z-Wave API Module has been woken up by USB Suspend. */ USBSuspend = 0x06, From 9549a040477364b54a2df617a42fd30639e67e14 Mon Sep 17 00:00:00 2001 From: Dominic Griesel Date: Sat, 9 Dec 2023 13:44:43 +0100 Subject: [PATCH 18/20] chore: release v12.4.1 ### Bugfixes * Handle more cases of unexpected Serial API restarts (#6551) ### Config file changes * Add wakeup instructions for Nexia ZSENS930 (#6545) * Correct parameter 5 size for Zooz ZEN34 (#6546) --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- packages/cc/package.json | 2 +- packages/config/package.json | 2 +- packages/flash/package.json | 2 +- packages/host/package.json | 2 +- packages/serial/package.json | 2 +- packages/testing/package.json | 2 +- packages/zwave-js/package.json | 2 +- 9 files changed, 16 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a28a39b0276..d7954647940d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ +## 12.4.1 (2023-12-09) +### Bugfixes +* Handle more cases of unexpected Serial API restarts (#6551) + +### Config file changes +* Add wakeup instructions for Nexia ZSENS930 (#6545) +* Correct parameter 5 size for Zooz ZEN34 (#6546) + ## 12.4.0 (2023-11-30) ### Features * Expose rebuild routes progress as a controller property (#6525) diff --git a/package.json b/package.json index 27e7e8c67ea3..98a926b084ac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/repo", - "version": "12.4.0", + "version": "12.4.1", "private": true, "description": "Z-Wave driver written entirely in JavaScript/TypeScript", "keywords": [], diff --git a/packages/cc/package.json b/packages/cc/package.json index 64791d3e69fa..5fd64e719fc6 100644 --- a/packages/cc/package.json +++ b/packages/cc/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/cc", - "version": "12.4.0", + "version": "12.4.1", "description": "zwave-js: Command Classes", "keywords": [], "publishConfig": { diff --git a/packages/config/package.json b/packages/config/package.json index e3381b67378a..682677e051bc 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/config", - "version": "12.4.0", + "version": "12.4.1", "description": "zwave-js: configuration files", "publishConfig": { "access": "public" diff --git a/packages/flash/package.json b/packages/flash/package.json index 0f36a1681b24..f1c9cae7b054 100644 --- a/packages/flash/package.json +++ b/packages/flash/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/flash", - "version": "12.4.0", + "version": "12.4.1", "description": "zwave-js: firmware flash utility", "keywords": [], "publishConfig": { diff --git a/packages/host/package.json b/packages/host/package.json index 2599b8bb2acf..21b160226788 100644 --- a/packages/host/package.json +++ b/packages/host/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/host", - "version": "12.4.0", + "version": "12.4.1", "description": "zwave-js: Host abstractions", "keywords": [], "publishConfig": { diff --git a/packages/serial/package.json b/packages/serial/package.json index 345173c93b2c..9d280deeab57 100644 --- a/packages/serial/package.json +++ b/packages/serial/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/serial", - "version": "12.4.0", + "version": "12.4.1", "description": "zwave-js: Serialport driver", "publishConfig": { "access": "public" diff --git a/packages/testing/package.json b/packages/testing/package.json index f840d897783e..76c49dd96ec9 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -1,6 +1,6 @@ { "name": "@zwave-js/testing", - "version": "12.4.0", + "version": "12.4.1", "description": "zwave-js: testing utilities", "keywords": [], "publishConfig": { diff --git a/packages/zwave-js/package.json b/packages/zwave-js/package.json index 22d34fe9530b..7607744253bb 100644 --- a/packages/zwave-js/package.json +++ b/packages/zwave-js/package.json @@ -1,6 +1,6 @@ { "name": "zwave-js", - "version": "12.4.0", + "version": "12.4.1", "description": "Z-Wave driver written entirely in JavaScript/TypeScript", "keywords": [], "main": "build/index.js", From 86b137ef54357e84fc7e50df8a558a7b2f540525 Mon Sep 17 00:00:00 2001 From: zackbcom Date: Mon, 1 Jan 2024 12:49:32 -0600 Subject: [PATCH 19/20] fix(lint): compatibility of ESLint plugin with Node.js 18 (#6580) --- .../src/rules/consistent-device-config-property-order.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/src/rules/consistent-device-config-property-order.ts b/packages/eslint-plugin/src/rules/consistent-device-config-property-order.ts index 34d30146ad1d..28d530ffa930 100644 --- a/packages/eslint-plugin/src/rules/consistent-device-config-property-order.ts +++ b/packages/eslint-plugin/src/rules/consistent-device-config-property-order.ts @@ -80,8 +80,8 @@ export const consistentDeviceConfigPropertyOrder: JSONCRule.RuleModule = { 0, withRanges[0].property.loc.start.column, ); - - const desiredOrder = propsWithComments.toSorted((a, b) => + // TODO: Change to .toSorted() once on node 20. + const desiredOrder = [...propsWithComments].sort((a, b) => a.index - b.index ).map((prop) => { const start = Math.min( From fb93b59c2dcccf687afd58222509191c90022b48 Mon Sep 17 00:00:00 2001 From: Zac Date: Wed, 10 Jan 2024 13:55:24 -0800 Subject: [PATCH 20/20] fix(config): add 2nd product ID for Ring Panic Button Gen2 (#6595) --- packages/config/config/devices/0x0346/panic_button_gen2.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/config/config/devices/0x0346/panic_button_gen2.json b/packages/config/config/devices/0x0346/panic_button_gen2.json index 270beb721857..5f65017d5a9a 100644 --- a/packages/config/config/devices/0x0346/panic_button_gen2.json +++ b/packages/config/config/devices/0x0346/panic_button_gen2.json @@ -7,6 +7,10 @@ { "productType": "0x0801", "productId": "0x0401" + }, + { + "productType": "0x0801", + "productId": "0x0301" } ], "firmwareVersion": {