diff --git a/.vscode/settings.json b/.vscode/settings.json index dbdd0c04e3ae..f20727d8acce 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,7 +21,7 @@ } ], "dprint.experimentalLsp": true, - "dprint.path": "./node_modules/dprint/dprint", + "dprint.path": "./node_modules/dprint/bin.js", "editor.defaultFormatter": "dprint.dprint", "[jsonc]": { "editor.formatOnSave": true, diff --git a/packages/cc/package.json b/packages/cc/package.json index 665ba75ddbd8..cb95716a95e0 100644 --- a/packages/cc/package.json +++ b/packages/cc/package.json @@ -78,7 +78,6 @@ "@types/fs-extra": "^11.0.4", "@types/node": "^18.19.31", "@zwave-js/maintenance": "workspace:*", - "@zwave-js/testing": "workspace:*", "@zwave-js/transformers": "workspace:*", "ava": "^6.1.2", "del-cli": "^5.1.0", diff --git a/packages/cc/tsconfig.build.json b/packages/cc/tsconfig.build.json index b438c45d7e9b..ce700310e0a9 100644 --- a/packages/cc/tsconfig.build.json +++ b/packages/cc/tsconfig.build.json @@ -23,9 +23,6 @@ { "path": "../maintenance/tsconfig.build.json" }, - { - "path": "../testing/tsconfig.build.json" - }, { "path": "../transformers/tsconfig.build.json" } diff --git a/packages/core/src/values/Primitive.ts b/packages/core/src/values/Primitive.ts index 522976755924..0e4bc75384a5 100644 --- a/packages/core/src/values/Primitive.ts +++ b/packages/core/src/values/Primitive.ts @@ -262,6 +262,8 @@ export function encodeBitMask( maxValue: number = Math.max(...values), startValue: number = 1, ): Buffer { + if (values.length === 0) return Buffer.from([0]); + const numBytes = Math.ceil((maxValue - startValue + 1) / 8); const ret = Buffer.alloc(numBytes, 0); for (let val = startValue; val <= maxValue; val++) { diff --git a/packages/serial/src/message/ZnifferMessages.ts b/packages/serial/src/message/ZnifferMessages.ts index 7a5f90fd0a12..fcbe6883613d 100644 --- a/packages/serial/src/message/ZnifferMessages.ts +++ b/packages/serial/src/message/ZnifferMessages.ts @@ -245,7 +245,7 @@ export class ZnifferDataMessage extends ZnifferMessage this.checksumOK = true; this.payload = Buffer.alloc(0); } else { - validatePayload.fail( + throw validatePayload.fail( `Unsupported frame type ${ getEnumMemberName(ZnifferFrameType, this.frameType) }`, diff --git a/packages/testing/package.json b/packages/testing/package.json index 740fb46ca3d3..2756845254d2 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -56,6 +56,7 @@ "@microsoft/api-extractor": "^7.47.0", "@types/node": "^18.19.31", "@types/triple-beam": "^1.3.5", + "@zwave-js/cc": "workspace:*", "del-cli": "^5.1.0", "esbuild": "0.21.5", "esbuild-register": "^3.5.0", diff --git a/packages/testing/src/MockNode.ts b/packages/testing/src/MockNode.ts index e3029f50f4b1..7d869e7c5cb4 100644 --- a/packages/testing/src/MockNode.ts +++ b/packages/testing/src/MockNode.ts @@ -1,3 +1,4 @@ +import type { CommandClass } from "@zwave-js/cc"; import { type CommandClassInfo, type CommandClasses, @@ -26,6 +27,7 @@ import { MockZWaveFrameType, type MockZWaveRequestFrame, createMockZWaveAckFrame, + createMockZWaveRequestFrame, } from "./MockZWaveFrame"; const defaultCCInfo: CommandClassInfo = { @@ -293,18 +295,57 @@ export class MockNode { ); if (handler) { handler.resolve(frame); - } else { + } else if (frame.type === MockZWaveFrameType.Request) { + let cc = frame.payload; + let response: MockNodeResponse | undefined; + + // Transform incoming frames with hooks, e.g. to support unwrapping encapsulated CCs + for (const behavior of this.behaviors) { + if (behavior.transformIncomingCC) { + cc = await behavior.transformIncomingCC( + this.controller, + this, + cc, + ); + } + } + + // Figure out what to do with the frame + for (const behavior of this.behaviors) { + response = await behavior.handleCC?.( + this.controller, + this, + cc, + ); + if (response) break; + } + + // If no behavior handled the frame, or we're supposed to stop, stop + if (!response || response.action === "stop") return; + + // Transform responses with hooks, e.g. to support Supervision or other encapsulation for (const behavior of this.behaviors) { - if ( - await behavior.onControllerFrame?.( + if (behavior.transformResponse) { + response = await behavior.transformResponse( this.controller, this, - frame, - ) - ) { - return; + cc, + response, + ); } } + + // Finally send a CC to the controller if we're supposed to + if (response.action === "sendCC") { + await this.sendToController( + createMockZWaveRequestFrame(response.cc, { + ackRequested: response.ackRequested, + }), + ); + } else if (response.action === "ack") { + // Or ack the frame + await this.ackControllerRequestFrame(frame); + } } } @@ -419,11 +460,46 @@ export class MockNode { } } +/** What the mock node should do after receiving a controller frame */ +export type MockNodeResponse = { + // Send a CC + action: "sendCC"; + cc: CommandClass; + ackRequested?: boolean; // Defaults to false +} | { + // Acknowledge the incoming frame + action: "ack"; +} | { + // do nothing + action: "stop"; +} | { + // indicate success to the sending node + action: "ok"; +} | { + // indicate failure to the sending node + action: "fail"; +}; + export interface MockNodeBehavior { - /** Gets called when a message from the controller is received. Return `true` to indicate that the message has been handled. */ - onControllerFrame?: ( + /** Gets called before the `handleCC` handlers and can transform an incoming `CommandClass` into another */ + transformIncomingCC?: ( + controller: MockController, + self: MockNode, + cc: CommandClass, + ) => Promise | CommandClass; + + /** Gets called when a CC from the controller is received. Returns an action to be performed in response, or `undefined` if there is nothing to do. */ + handleCC?: ( + controller: MockController, + self: MockNode, + receivedCC: CommandClass, + ) => Promise | MockNodeResponse | undefined; + + /** Gets called after the `onControllerFrame` handlers and can transform one `MockNodeResponse` into another */ + transformResponse?: ( controller: MockController, self: MockNode, - frame: MockZWaveFrame, - ) => Promise | boolean | undefined; + receivedCC: CommandClass, + response: MockNodeResponse, + ) => Promise | MockNodeResponse; } diff --git a/packages/testing/src/MockZWaveFrame.ts b/packages/testing/src/MockZWaveFrame.ts index 0ab043682aa7..37221f783560 100644 --- a/packages/testing/src/MockZWaveFrame.ts +++ b/packages/testing/src/MockZWaveFrame.ts @@ -1,4 +1,4 @@ -import type { ICommandClass } from "@zwave-js/core"; +import { type CommandClass } from "@zwave-js/cc"; /** * Is used to simulate communication between a {@link MockController} and a {@link MockNode}. @@ -15,7 +15,7 @@ export interface MockZWaveRequestFrame { /** Whether an ACK is requested from the destination */ ackRequested: boolean; /** The Command Class contained in the frame */ - payload: ICommandClass; + payload: CommandClass; } export interface LazyMockZWaveRequestFrame { @@ -25,7 +25,7 @@ export interface LazyMockZWaveRequestFrame { /** Whether an ACK is requested from the destination */ ackRequested: boolean; /** The Command Class contained in the frame */ - payload: ICommandClass | (() => ICommandClass); + payload: CommandClass | (() => CommandClass); } export interface MockZWaveAckFrame { @@ -44,7 +44,7 @@ export enum MockZWaveFrameType { } export function createMockZWaveRequestFrame( - payload: ICommandClass | (() => ICommandClass), + payload: CommandClass | (() => CommandClass), options: Partial> = {}, ): LazyMockZWaveRequestFrame { const { repeaters = [], ackRequested = true } = options; diff --git a/packages/testing/tsconfig.build.json b/packages/testing/tsconfig.build.json index 137d01b61051..33c071766e8a 100644 --- a/packages/testing/tsconfig.build.json +++ b/packages/testing/tsconfig.build.json @@ -19,8 +19,15 @@ }, { "path": "../shared/tsconfig.build.json" + }, + { + "path": "../cc/tsconfig.build.json" } ], - "include": ["src/**/*.ts"], - "exclude": ["src/**/*.test.ts"] + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/**/*.test.ts" + ] } diff --git a/packages/zwave-js/src/lib/controller/MockControllerBehaviors.ts b/packages/zwave-js/src/lib/controller/MockControllerBehaviors.ts index 73b85d9148e9..9f4fa93d8754 100644 --- a/packages/zwave-js/src/lib/controller/MockControllerBehaviors.ts +++ b/packages/zwave-js/src/lib/controller/MockControllerBehaviors.ts @@ -6,7 +6,6 @@ import { ZWaveProtocolCCRequestNodeInformationFrame, } from "@zwave-js/cc/ZWaveProtocolCC"; import { - type ICommandClass, NodeType, TransmitOptions, TransmitStatus, @@ -92,7 +91,7 @@ function createLazySendDataPayload( controller: MockController, node: MockNode, msg: SendDataRequest | SendDataMulticastRequest, -): () => ICommandClass { +): () => CommandClass { return () => { try { const cmd = CommandClass.from(node.host, { diff --git a/packages/zwave-js/src/lib/node/MockNodeBehaviors.ts b/packages/zwave-js/src/lib/node/MockNodeBehaviors.ts index 7897789d4e20..bc336b1dff4b 100644 --- a/packages/zwave-js/src/lib/node/MockNodeBehaviors.ts +++ b/packages/zwave-js/src/lib/node/MockNodeBehaviors.ts @@ -1,11 +1,5 @@ import { type CommandClass, - MultiChannelCCCapabilityGet, - MultiChannelCCCapabilityReport, - MultiChannelCCEndPointFind, - MultiChannelCCEndPointFindReport, - MultiChannelCCEndPointGet, - MultiChannelCCEndPointReport, Security2CC, Security2CCMessageEncapsulation, SecurityCC, @@ -20,19 +14,19 @@ import { ZWaveProtocolCCNodeInformationFrame, ZWaveProtocolCCRequestNodeInformationFrame, } from "@zwave-js/cc/ZWaveProtocolCC"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; - import { CommandClasses } from "@zwave-js/core"; +import { type MockNodeBehavior } from "@zwave-js/testing"; + import { BasicCCBehaviors } from "./mockCCBehaviors/Basic"; import { BinarySensorCCBehaviors } from "./mockCCBehaviors/BinarySensor"; import { ConfigurationCCBehaviors } from "./mockCCBehaviors/Configuration"; import { EnergyProductionCCBehaviors } from "./mockCCBehaviors/EnergyProduction"; import { ManufacturerSpecificCCBehaviors } from "./mockCCBehaviors/ManufacturerSpecific"; import { MeterCCBehaviors } from "./mockCCBehaviors/Meter"; +import { + MultiChannelCCBehaviors, + MultiChannelCCHooks, +} from "./mockCCBehaviors/MultiChannel"; import { MultilevelSensorCCBehaviors } from "./mockCCBehaviors/MultilevelSensor"; import { NotificationCCBehaviors } from "./mockCCBehaviors/Notification"; import { ScheduleEntryLockCCBehaviors } from "./mockCCBehaviors/ScheduleEntryLock"; @@ -43,10 +37,9 @@ import { UserCodeCCBehaviors } from "./mockCCBehaviors/UserCode"; import { WindowCoveringCCBehaviors } from "./mockCCBehaviors/WindowCovering"; const respondToRequestNodeInfo: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof ZWaveProtocolCCRequestNodeInformationFrame ) { const cc = new ZWaveProtocolCCNodeInformationFrame(self.host, { @@ -59,30 +52,22 @@ const respondToRequestNodeInfo: MockNodeBehavior = { .filter(([, info]) => info.isSupported) .map(([ccId]) => ccId), }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } }, }; const respondToVersionCCCommandClassGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof VersionCCCommandClassGet - ) { - const endpoint = frame.payload.endpointIndex === 0 + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof VersionCCCommandClassGet) { + const endpoint = receivedCC.endpointIndex === 0 ? self - : self.endpoints.get(frame.payload.endpointIndex); - if (!endpoint) return false; + : self.endpoints.get(receivedCC.endpointIndex); + if (!endpoint) return; let version = 0; for (const ep of [self, ...self.endpoints.values()]) { - const info = ep.implementedCCs.get(frame.payload.requestedCC); + const info = ep.implementedCCs.get(receivedCC.requestedCC); if (info?.version) { version = info.version; break; @@ -91,8 +76,7 @@ const respondToVersionCCCommandClassGet: MockNodeBehavior = { // Basic CC is always supported implicitly if ( - version === 0 - && frame.payload.requestedCC === CommandClasses.Basic + version === 0 && receivedCC.requestedCC === CommandClasses.Basic ) { version = 1; } @@ -100,105 +84,17 @@ const respondToVersionCCCommandClassGet: MockNodeBehavior = { const cc = new VersionCCCommandClassReport(self.host, { nodeId: self.id, endpoint: "index" in endpoint ? endpoint.index : undefined, - requestedCC: frame.payload.requestedCC, + requestedCC: receivedCC.requestedCC, ccVersion: version, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - - return true; - } - }, -}; - -const respondToMultiChannelCCEndPointGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof MultiChannelCCEndPointGet - ) { - const cc = new MultiChannelCCEndPointReport(self.host, { - nodeId: controller.host.ownNodeId, - countIsDynamic: false, - identicalCapabilities: false, - individualCount: self.endpoints.size, - }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; - }, -}; - -const respondToMultiChannelCCEndPointFind: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof MultiChannelCCEndPointFind - ) { - const request = frame.payload; - const cc = new MultiChannelCCEndPointFindReport(self.host, { - nodeId: controller.host.ownNodeId, - genericClass: request.genericClass, - specificClass: request.specificClass, - foundEndpoints: [...self.endpoints.keys()], - reportsToFollow: 0, - }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; - } - return false; - }, -}; - -const respondToMultiChannelCCCapabilityGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof MultiChannelCCCapabilityGet - ) { - const endpoint = self.endpoints.get( - frame.payload.requestedEndpoint, - )!; - const cc = new MultiChannelCCCapabilityReport(self.host, { - nodeId: controller.host.ownNodeId, - endpointIndex: endpoint.index, - genericDeviceClass: endpoint?.capabilities.genericDeviceClass - ?? self.capabilities.genericDeviceClass, - specificDeviceClass: endpoint?.capabilities.specificDeviceClass - ?? self.capabilities.specificDeviceClass, - isDynamic: false, - wasRemoved: false, - supportedCCs: [...endpoint.implementedCCs.keys()], - }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; - } - return false; }, }; const respondToZWavePlusCCGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ZWavePlusCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ZWavePlusCCGet) { const cc = new ZWavePlusCCReport(self.host, { nodeId: controller.host.ownNodeId, zwavePlusVersion: 2, @@ -211,23 +107,17 @@ const respondToZWavePlusCCGet: MockNodeBehavior = { installerIcon: 0x0000, userIcon: 0x0000, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: true, - }), - ); - return true; + return { action: "sendCC", cc, ackRequested: true }; } }, }; // TODO: We should handle this more generically: const respondToS0ZWavePlusCCGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SecurityCCCommandEncapsulation - && frame.payload.encapsulated instanceof ZWavePlusCCGet + receivedCC instanceof SecurityCCCommandEncapsulation + && receivedCC.encapsulated instanceof ZWavePlusCCGet ) { let cc: CommandClass = new ZWavePlusCCReport(self.host, { nodeId: controller.host.ownNodeId, @@ -242,22 +132,16 @@ const respondToS0ZWavePlusCCGet: MockNodeBehavior = { userIcon: 0x0000, }); cc = SecurityCC.encapsulate(self.host, cc); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: true, - }), - ); - return true; + return { action: "sendCC", cc, ackRequested: true }; } }, }; const respondToS2ZWavePlusCCGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof Security2CCMessageEncapsulation - && frame.payload.encapsulated instanceof ZWavePlusCCGet + receivedCC instanceof Security2CCMessageEncapsulation + && receivedCC.encapsulated instanceof ZWavePlusCCGet ) { let cc: CommandClass = new ZWavePlusCCReport(self.host, { nodeId: controller.host.ownNodeId, @@ -272,12 +156,7 @@ const respondToS2ZWavePlusCCGet: MockNodeBehavior = { userIcon: 0x0000, }); cc = Security2CC.encapsulate(self.host, cc); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: true, - }), - ); - return true; + return { action: "sendCC", cc }; } }, }; @@ -286,10 +165,11 @@ const respondToS2ZWavePlusCCGet: MockNodeBehavior = { export function createDefaultBehaviors(): MockNodeBehavior[] { return [ respondToRequestNodeInfo, + + ...MultiChannelCCHooks, + ...MultiChannelCCBehaviors, + respondToVersionCCCommandClassGet, - respondToMultiChannelCCEndPointGet, - respondToMultiChannelCCEndPointFind, - respondToMultiChannelCCCapabilityGet, respondToZWavePlusCCGet, respondToS0ZWavePlusCCGet, diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/Basic.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/Basic.ts index 66ce55ecfff5..cccd5e04a575 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/Basic.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/Basic.ts @@ -1,10 +1,6 @@ import { BasicCCGet, BasicCCReport, BasicCCSet } from "@zwave-js/cc/BasicCC"; import { CommandClasses } from "@zwave-js/core/safe"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior } from "@zwave-js/testing"; const STATE_KEY_PREFIX = "Basic_"; const StateKeys = { @@ -12,14 +8,11 @@ const StateKeys = { } as const; const respondToBasicGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof BasicCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof BasicCCGet) { // Do not respond if BasicCC is not explicitly listed as supported if (!self.implementedCCs.get(CommandClasses.Basic)?.isSupported) { - return false; + return; } const cc = new BasicCCReport(self.host, { @@ -27,28 +20,17 @@ const respondToBasicGet: MockNodeBehavior = { currentValue: (self.state.get(StateKeys.currentValue) ?? 0) as number, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToBasicSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof BasicCCSet - ) { - self.state.set(StateKeys.currentValue, frame.payload.targetValue); - - return true; + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof BasicCCSet) { + self.state.set(StateKeys.currentValue, receivedCC.targetValue); + return { action: "ok" }; } - return false; }, }; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/BinarySensor.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/BinarySensor.ts index 0788c94e14ba..93b02bb9d0ed 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/BinarySensor.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/BinarySensor.ts @@ -7,67 +7,51 @@ import { } from "@zwave-js/cc"; import { CommandClasses } from "@zwave-js/core"; import type { BinarySensorCCCapabilities } from "@zwave-js/testing"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior } from "@zwave-js/testing"; const defaultCapabilities: BinarySensorCCCapabilities = { supportedSensorTypes: [], }; const respondToBinarySensorSupportedGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof BinarySensorCCSupportedGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof BinarySensorCCSupportedGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Binary Sensor"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const cc = new BinarySensorCCSupportedReport(self.host, { nodeId: controller.host.ownNodeId, supportedSensorTypes: capabilities.supportedSensorTypes, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToBinarySensorGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof BinarySensorCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof BinarySensorCCGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Binary Sensor"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; let sensorType: BinarySensorType | undefined; if ( - frame.payload.sensorType == undefined - || frame.payload.sensorType === BinarySensorType.Any + receivedCC.sensorType == undefined + || receivedCC.sensorType === BinarySensorType.Any ) { // If the sensor type is not specified, use the first supported one sensorType = capabilities.supportedSensorTypes[0]; } else { - sensorType = frame.payload.sensorType; + sensorType = receivedCC.sensorType; } if (sensorType != undefined) { @@ -77,15 +61,10 @@ const respondToBinarySensorGet: MockNodeBehavior = { type: sensorType, value, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); + return { action: "sendCC", cc }; } - return true; + return { action: "stop" }; } - return false; }, }; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/Configuration.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/Configuration.ts index ea6524a57f51..6fa5b3dc00b7 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/Configuration.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/Configuration.ts @@ -14,8 +14,6 @@ import { CommandClasses, ConfigValueFormat } from "@zwave-js/core/safe"; import { type ConfigurationCCCapabilities, type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, } from "@zwave-js/testing"; const defaultCapabilities: ConfigurationCCCapabilities = { @@ -29,27 +27,24 @@ const StateKeys = { } as const; const respondToConfigurationGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ConfigurationCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ConfigurationCCGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses.Configuration, - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const parameter = frame.payload.parameter; + const parameter = receivedCC.parameter; const paramInfo = capabilities.parameters.find( (p) => p["#"] === parameter, ); // Do not respond if the parameter is not supported - if (!paramInfo) return true; + if (!paramInfo) return { action: "stop" }; const value = (self.state.get(StateKeys.value(parameter)) as number) ?? paramInfo.defaultValue @@ -62,104 +57,85 @@ const respondToConfigurationGet: MockNodeBehavior = { valueSize: paramInfo.valueSize, valueFormat: paramInfo.format, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToConfigurationSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ConfigurationCCSet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ConfigurationCCSet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses.Configuration, - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const parameter = frame.payload.parameter; + const parameter = receivedCC.parameter; const paramInfo = capabilities.parameters.find( (p) => p["#"] === parameter, ); // Do nothing if the parameter is not supported - if (!paramInfo) return true; + if (!paramInfo) return { action: "fail" }; - if (frame.payload.resetToDefault) { + if (receivedCC.resetToDefault) { self.state.delete(StateKeys.value(parameter)); - return true; + return { action: "ok" }; } - const value = frame.payload.value!; + const value = receivedCC.value!; // Do nothing if the value is out of range if (paramInfo.minValue != undefined && value < paramInfo.minValue) { - return true; + return { action: "fail" }; } else if ( paramInfo.maxValue != undefined && value > paramInfo.maxValue ) { - return true; + return { action: "fail" }; } self.state.set(StateKeys.value(parameter), value); - - return true; + return { action: "ok" }; } - return false; }, }; const respondToConfigurationDefaultReset: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ConfigurationCCDefaultReset - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ConfigurationCCDefaultReset) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses.Configuration, - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; for (const paramInfo of capabilities.parameters) { self.state.delete(StateKeys.value(paramInfo["#"])); } - - return true; + return { action: "ok" }; } - return false; }, }; const respondToConfigurationNameGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ConfigurationCCNameGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ConfigurationCCNameGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses.Configuration, - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const parameter = frame.payload.parameter; + const parameter = receivedCC.parameter; const paramInfo = capabilities.parameters.find( (p) => p["#"] === parameter, ); // Do nothing if the parameter is not supported - if (!paramInfo) return true; + if (!paramInfo) return { action: "fail" }; const cc = new ConfigurationCCNameReport(self.host, { nodeId: controller.host.ownNodeId, @@ -167,36 +143,27 @@ const respondToConfigurationNameGet: MockNodeBehavior = { name: paramInfo.name ?? "", reportsToFollow: 0, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToConfigurationInfoGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ConfigurationCCInfoGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ConfigurationCCInfoGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses.Configuration, - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const parameter = frame.payload.parameter; + const parameter = receivedCC.parameter; const paramInfo = capabilities.parameters.find( (p) => p["#"] === parameter, ); // Do nothing if the parameter is not supported - if (!paramInfo) return true; + if (!paramInfo) return { action: "fail" }; const cc = new ConfigurationCCInfoReport(self.host, { nodeId: controller.host.ownNodeId, @@ -204,31 +171,22 @@ const respondToConfigurationInfoGet: MockNodeBehavior = { info: paramInfo.info ?? "", reportsToFollow: 0, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToConfigurationPropertiesGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ConfigurationCCPropertiesGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ConfigurationCCPropertiesGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses.Configuration, - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const parameter = frame.payload.parameter; + const parameter = receivedCC.parameter; const paramIndex = capabilities.parameters.findIndex( (p) => p["#"] === parameter, ); @@ -263,15 +221,8 @@ const respondToConfigurationPropertiesGet: MockNodeBehavior = { nextParameter: nextParameter?.["#"] ?? 0, }); } - - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/EnergyProduction.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/EnergyProduction.ts index ffd93cddcf49..a25b3b9bf62c 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/EnergyProduction.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/EnergyProduction.ts @@ -11,8 +11,6 @@ import { getEnumMemberName } from "@zwave-js/shared"; import { type EnergyProductionCCCapabilities, type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, } from "@zwave-js/testing"; const defaultCapabilities: EnergyProductionCCCapabilities = { @@ -37,43 +35,34 @@ const defaultCapabilities: EnergyProductionCCCapabilities = { }; const respondToEnergyProductionGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof EnergyProductionCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof EnergyProductionCCGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Energy Production"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const result = capabilities.values[ getEnumMemberName( EnergyProductionParameter, - frame.payload.parameter, + receivedCC.parameter, ) as unknown as keyof typeof capabilities.values ]; const cc = new EnergyProductionCCReport(self.host, { nodeId: controller.host.ownNodeId, - parameter: frame.payload.parameter, + parameter: receivedCC.parameter, value: result?.value ?? 0, scale: getEnergyProductionScale( - frame.payload.parameter, + receivedCC.parameter, result?.scale ?? 0, ), }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/ManufacturerSpecific.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/ManufacturerSpecific.ts index 83d858e44422..1ca966debef4 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/ManufacturerSpecific.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/ManufacturerSpecific.ts @@ -2,31 +2,18 @@ import { ManufacturerSpecificCCGet, ManufacturerSpecificCCReport, } from "@zwave-js/cc/ManufacturerSpecificCC"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior } from "@zwave-js/testing"; const respondToManufacturerSpecificGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ManufacturerSpecificCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ManufacturerSpecificCCGet) { const cc = new ManufacturerSpecificCCReport(self.host, { nodeId: self.id, manufacturerId: self.capabilities.manufacturerId, productType: self.capabilities.productType, productId: self.capabilities.productId, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - - return true; + return { action: "sendCC", cc }; } }, }; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/Meter.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/Meter.ts index 0528c811e40f..b3bb9097d1f9 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/Meter.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/Meter.ts @@ -10,8 +10,6 @@ import { CommandClasses } from "@zwave-js/core"; import { type MeterCCCapabilities, type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, } from "@zwave-js/testing"; export const defaultCapabilities: MeterCCCapabilities = { @@ -22,16 +20,13 @@ export const defaultCapabilities: MeterCCCapabilities = { }; const respondToMeterSupportedGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof MeterCCSupportedGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof MeterCCSupportedGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses.Meter, - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const cc = new MeterCCSupportedReport(self.host, { @@ -41,33 +36,24 @@ const respondToMeterSupportedGet: MockNodeBehavior = { supportedRateTypes: capabilities.supportedRateTypes, supportsReset: capabilities.supportsReset, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToMeterGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof MeterCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof MeterCCGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses.Meter, - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const scale = frame.payload.scale + const scale = receivedCC.scale ?? capabilities.supportedScales[0]; - const rateType = frame.payload.rateType + const rateType = receivedCC.rateType ?? capabilities.supportedRateTypes[0] ?? RateType.Consumed; @@ -89,32 +75,23 @@ const respondToMeterGet: MockNodeBehavior = { rateType, ...normalizedValue, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToMeterReset: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof MeterCCReset - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof MeterCCReset) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses.Meter, - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const cc = frame.payload; + const cc = receivedCC; if ( cc.type != undefined && cc.scale != undefined @@ -129,10 +106,8 @@ const respondToMeterReset: MockNodeBehavior = { } else { capabilities.onReset?.(); } - - return true; + return { action: "ok" }; } - return false; }, }; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/MultiChannel.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/MultiChannel.ts new file mode 100644 index 000000000000..1017522d3d84 --- /dev/null +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/MultiChannel.ts @@ -0,0 +1,121 @@ +import { + CommandClass, + MultiChannelCCCapabilityGet, + MultiChannelCCCapabilityReport, + MultiChannelCCCommandEncapsulation, + MultiChannelCCEndPointFind, + MultiChannelCCEndPointFindReport, + MultiChannelCCEndPointGet, + MultiChannelCCEndPointReport, +} from "@zwave-js/cc"; +import { CommandClasses } from "@zwave-js/core"; +import { type MockNodeBehavior } from "@zwave-js/testing"; + +const encapsulateMultiChannelCC: MockNodeBehavior = { + transformIncomingCC(controller, self, receivedCC) { + if (receivedCC instanceof MultiChannelCCCommandEncapsulation) { + // The existing machinery interprets endpointIndex from the view + // of the controller, but we are the end node here, so re-interpret + // the destination as the endpoint index + receivedCC.encapsulated.endpointIndex = receivedCC + .destination as number; + receivedCC = receivedCC.encapsulated; + } + return receivedCC; + }, + + transformResponse(controller, self, receivedCC, response) { + if ( + response.action === "sendCC" + && receivedCC instanceof CommandClass + && receivedCC.isEncapsulatedWith( + CommandClasses["Multi Channel"], + ) + && !response.cc.isEncapsulatedWith(CommandClasses["Multi Channel"]) + ) { + const multiChannelEncap = receivedCC.getEncapsulatingCC( + CommandClasses["Multi Channel"], + ); + if (!multiChannelEncap) return response; + + // FIXME: Consider V1 of the CC + const destination = multiChannelEncap.endpointIndex; + const source = + (multiChannelEncap as MultiChannelCCCommandEncapsulation) + .destination as number; + + response.cc = new MultiChannelCCCommandEncapsulation(self.host, { + nodeId: response.cc.nodeId, + encapsulated: response.cc, + endpoint: source, + destination, + }); + } + + return response; + }, +}; + +const respondToMultiChannelCCEndPointGet: MockNodeBehavior = { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof MultiChannelCCEndPointGet) { + const cc = new MultiChannelCCEndPointReport(self.host, { + nodeId: controller.host.ownNodeId, + countIsDynamic: false, + identicalCapabilities: false, + individualCount: self.endpoints.size, + }); + return { action: "sendCC", cc }; + } + }, +}; + +const respondToMultiChannelCCEndPointFind: MockNodeBehavior = { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof MultiChannelCCEndPointFind) { + const request = receivedCC; + const cc = new MultiChannelCCEndPointFindReport(self.host, { + nodeId: controller.host.ownNodeId, + genericClass: request.genericClass, + specificClass: request.specificClass, + foundEndpoints: [...self.endpoints.keys()], + reportsToFollow: 0, + }); + return { action: "sendCC", cc }; + } + }, +}; + +const respondToMultiChannelCCCapabilityGet: MockNodeBehavior = { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof MultiChannelCCCapabilityGet) { + const endpoint = self.endpoints.get( + receivedCC.requestedEndpoint, + )!; + const cc = new MultiChannelCCCapabilityReport(self.host, { + nodeId: controller.host.ownNodeId, + endpointIndex: endpoint.index, + genericDeviceClass: endpoint?.capabilities.genericDeviceClass + ?? self.capabilities.genericDeviceClass, + specificDeviceClass: endpoint?.capabilities.specificDeviceClass + ?? self.capabilities.specificDeviceClass, + isDynamic: false, + wasRemoved: false, + supportedCCs: [...endpoint.implementedCCs.keys()] + // Basic CC must not be included in the NIF + .filter((ccId) => ccId !== CommandClasses.Basic), + }); + return { action: "sendCC", cc }; + } + }, +}; + +export const MultiChannelCCHooks = [ + encapsulateMultiChannelCC, +]; + +export const MultiChannelCCBehaviors = [ + respondToMultiChannelCCEndPointGet, + respondToMultiChannelCCEndPointFind, + respondToMultiChannelCCCapabilityGet, +]; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/MultilevelSensor.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/MultilevelSensor.ts index 8409069e26de..417b16a4dc5f 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/MultilevelSensor.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/MultilevelSensor.ts @@ -8,27 +8,20 @@ import { } 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"; +import { type MockNodeBehavior } 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 - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof MultilevelSensorCCGetSupportedSensor) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Multilevel Sensor"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const cc = new MultilevelSensorCCSupportedSensorReport(self.host, { @@ -37,31 +30,22 @@ const respondToMultilevelSensorGetSupportedSensor: MockNodeBehavior = { capabilities.sensors, ).map((t) => parseInt(t)), }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToMultilevelSensorGetSupportedScale: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof MultilevelSensorCCGetSupportedScale - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof MultilevelSensorCCGetSupportedScale) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Multilevel Sensor"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const sensorType = frame.payload.sensorType; + const sensorType = receivedCC.sensorType; const supportedScales = capabilities.sensors[sensorType]?.supportedScales ?? []; const cc = new MultilevelSensorCCSupportedScaleReport(self.host, { @@ -69,38 +53,29 @@ const respondToMultilevelSensorGetSupportedScale: MockNodeBehavior = { sensorType, supportedScales, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToMultilevelSensorGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof MultilevelSensorCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof MultilevelSensorCCGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Multilevel Sensor"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const firstSupportedSensorType = Object.keys(capabilities.sensors).length > 0 ? parseInt(Object.keys(capabilities.sensors)[0]) : undefined; - const sensorType = frame.payload.sensorType + const sensorType = receivedCC.sensorType ?? firstSupportedSensorType ?? 1; - const scale = frame.payload.scale + const scale = receivedCC.scale ?? capabilities.sensors[sensorType].supportedScales[0] ?? 0; const value = capabilities.getValue?.(sensorType, scale) ?? 0; @@ -110,14 +85,8 @@ const respondToMultilevelSensorGet: MockNodeBehavior = { scale, value, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/Notification.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/Notification.ts index f594fecd3d69..6a723b81025a 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/Notification.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/Notification.ts @@ -6,11 +6,7 @@ import { } from "@zwave-js/cc/NotificationCC"; import { CommandClasses } from "@zwave-js/core"; import type { NotificationCCCapabilities } from "@zwave-js/testing"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior } from "@zwave-js/testing"; const defaultCapabilities: NotificationCCCapabilities = { supportsV1Alarm: false, @@ -18,16 +14,13 @@ const defaultCapabilities: NotificationCCCapabilities = { }; const respondToNotificationSupportedGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof NotificationCCSupportedGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof NotificationCCSupportedGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses.Notification, - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const cc = new NotificationCCSupportedReport(self.host, { @@ -37,50 +30,36 @@ const respondToNotificationSupportedGet: MockNodeBehavior = { capabilities.notificationTypesAndEvents, ).map((t) => parseInt(t)), }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToNotificationEventSupportedGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof NotificationCCEventSupportedGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof NotificationCCEventSupportedGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses.Notification, - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; if ( - frame.payload.notificationType + receivedCC.notificationType in capabilities.notificationTypesAndEvents ) { const cc = new NotificationCCEventSupportedReport(self.host, { nodeId: controller.host.ownNodeId, - notificationType: frame.payload.notificationType, + notificationType: receivedCC.notificationType, supportedEvents: capabilities.notificationTypesAndEvents[ - frame.payload.notificationType + receivedCC.notificationType ], }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } + return { action: "stop" }; } - return false; }, }; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/ScheduleEntryLock.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/ScheduleEntryLock.ts index c403fafc4368..70aa3181fc58 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/ScheduleEntryLock.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/ScheduleEntryLock.ts @@ -27,9 +27,7 @@ import { CommandClasses } from "@zwave-js/core/safe"; import { type AllOrNone } from "@zwave-js/shared/safe"; import { type MockNodeBehavior, - MockZWaveFrameType, type ScheduleEntryLockCCCapabilities, - createMockZWaveRequestFrame, } from "@zwave-js/testing"; import { defaultCapabilities as defaultUserCodeCapabilities } from "./UserCode"; @@ -51,176 +49,145 @@ const StateKeys = { } as const; const respondToScheduleEntryLockSupportedGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ScheduleEntryLockCCSupportedGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ScheduleEntryLockCCSupportedGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Schedule Entry Lock"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const cc = new ScheduleEntryLockCCSupportedReport(self.host, { nodeId: controller.host.ownNodeId, ...capabilities, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToScheduleEntryLockTimeOffsetSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ScheduleEntryLockCCTimeOffsetSet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ScheduleEntryLockCCTimeOffsetSet) { self.state.set( StateKeys.standardOffset, - frame.payload.standardOffset, + receivedCC.standardOffset, ); - self.state.set(StateKeys.dstOffset, frame.payload.dstOffset); - - return true; + self.state.set(StateKeys.dstOffset, receivedCC.dstOffset); + return { action: "ok" }; } - return false; }, }; const respondToScheduleEntryLockTimeOffsetGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ScheduleEntryLockCCTimeOffsetGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ScheduleEntryLockCCTimeOffsetGet) { const cc = new ScheduleEntryLockCCTimeOffsetReport(self.host, { nodeId: controller.host.ownNodeId, standardOffset: (self.state.get(StateKeys.standardOffset) ?? 0) as number, dstOffset: (self.state.get(StateKeys.dstOffset) ?? 0) as number, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToScheduleEntryLockEnableSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ScheduleEntryLockCCEnableSet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ScheduleEntryLockCCEnableSet) { // No need to do anything, this cannot be queried - return true; + return { action: "ok" }; } - return false; }, }; const respondToScheduleEntryLockEnableAllSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ScheduleEntryLockCCEnableAllSet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ScheduleEntryLockCCEnableAllSet) { // No need to do anything, this cannot be queried - return true; + return { action: "ok" }; } - return false; }, }; const respondToScheduleEntryLockWeekDayScheduleSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ScheduleEntryLockCCWeekDayScheduleSet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ScheduleEntryLockCCWeekDayScheduleSet) { const userCodeCapabilities = { ...defaultUserCodeCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; // If the user identifier is out of range, the command will be ignored - const userId = frame.payload.userId; - if (userId > userCodeCapabilities.numUsers) return true; + const userId = receivedCC.userId; + if (userId > userCodeCapabilities.numUsers) { + return { action: "fail" }; + } const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Schedule Entry Lock"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const slotId = frame.payload.slotId; + const slotId = receivedCC.slotId; // Ignore out of range slot queries - if (slotId > capabilities.numWeekDaySlots) return true; + if (slotId > capabilities.numWeekDaySlots) { + return { action: "fail" }; + } const kind = ScheduleEntryLockScheduleKind.WeekDay; const schedule = - frame.payload.action === ScheduleEntryLockSetAction.Set + receivedCC.action === ScheduleEntryLockSetAction.Set ? { - weekday: frame.payload.weekday!, - startHour: frame.payload.startHour!, - startMinute: frame.payload.startMinute!, - stopHour: frame.payload.stopHour!, - stopMinute: frame.payload.stopMinute!, + weekday: receivedCC.weekday!, + startHour: receivedCC.startHour!, + startMinute: receivedCC.startMinute!, + stopHour: receivedCC.stopHour!, + stopMinute: receivedCC.stopMinute!, } : undefined; self.state.set(StateKeys.schedule(userId, slotId, kind), schedule); - - return true; + return { action: "ok" }; } - return false; }, }; const respondToScheduleEntryLockWeekDayScheduleGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ScheduleEntryLockCCWeekDayScheduleGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ScheduleEntryLockCCWeekDayScheduleGet) { const userCodeCapabilities = { ...defaultUserCodeCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; // If the user identifier is out of range, the command will be ignored - const userId = frame.payload.userId; - if (userId > userCodeCapabilities.numUsers) return true; + const userId = receivedCC.userId; + if (userId > userCodeCapabilities.numUsers) { + return { action: "fail" }; + } const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Schedule Entry Lock"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const slotId = frame.payload.slotId; + const slotId = receivedCC.slotId; // Ignore out of range slot queries - if (slotId > capabilities.numWeekDaySlots) return true; + if (slotId > capabilities.numWeekDaySlots) { + return { action: "fail" }; + } const kind = ScheduleEntryLockScheduleKind.WeekDay; @@ -234,98 +201,92 @@ const respondToScheduleEntryLockWeekDayScheduleGet: MockNodeBehavior = { slotId, ...schedule, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToScheduleEntryLockYearDayScheduleSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ScheduleEntryLockCCYearDayScheduleSet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ScheduleEntryLockCCYearDayScheduleSet) { const userCodeCapabilities = { ...defaultUserCodeCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; // If the user identifier is out of range, the command will be ignored - const userId = frame.payload.userId; - if (userId > userCodeCapabilities.numUsers) return true; + const userId = receivedCC.userId; + if (userId > userCodeCapabilities.numUsers) { + return { action: "fail" }; + } const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Schedule Entry Lock"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const slotId = frame.payload.slotId; + const slotId = receivedCC.slotId; // Ignore out of range slot queries - if (slotId > capabilities.numYearDaySlots) return true; + if (slotId > capabilities.numYearDaySlots) { + return { action: "fail" }; + } const kind = ScheduleEntryLockScheduleKind.YearDay; const schedule = - frame.payload.action === ScheduleEntryLockSetAction.Set + receivedCC.action === ScheduleEntryLockSetAction.Set ? { - startYear: frame.payload.startYear!, - startMonth: frame.payload.startMonth!, - startDay: frame.payload.startDay!, - startHour: frame.payload.startHour!, - startMinute: frame.payload.startMinute!, - stopYear: frame.payload.stopYear!, - stopMonth: frame.payload.stopMonth!, - stopDay: frame.payload.stopDay!, - stopHour: frame.payload.stopHour!, - stopMinute: frame.payload.stopMinute!, + startYear: receivedCC.startYear!, + startMonth: receivedCC.startMonth!, + startDay: receivedCC.startDay!, + startHour: receivedCC.startHour!, + startMinute: receivedCC.startMinute!, + stopYear: receivedCC.stopYear!, + stopMonth: receivedCC.stopMonth!, + stopDay: receivedCC.stopDay!, + stopHour: receivedCC.stopHour!, + stopMinute: receivedCC.stopMinute!, } : undefined; self.state.set(StateKeys.schedule(userId, slotId, kind), schedule); - - return true; + return { action: "ok" }; } - return false; }, }; const respondToScheduleEntryLockYearDayScheduleGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ScheduleEntryLockCCYearDayScheduleGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ScheduleEntryLockCCYearDayScheduleGet) { const userCodeCapabilities = { ...defaultUserCodeCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; // If the user identifier is out of range, the command will be ignored - const userId = frame.payload.userId; - if (userId > userCodeCapabilities.numUsers) return true; + const userId = receivedCC.userId; + if (userId > userCodeCapabilities.numUsers) { + return { action: "fail" }; + } const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Schedule Entry Lock"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const slotId = frame.payload.slotId; + const slotId = receivedCC.slotId; // Ignore out of range slot queries - if (slotId > capabilities.numYearDaySlots) return true; + if (slotId > capabilities.numYearDaySlots) { + return { action: "fail" }; + } const kind = ScheduleEntryLockScheduleKind.YearDay; @@ -339,95 +300,93 @@ const respondToScheduleEntryLockYearDayScheduleGet: MockNodeBehavior = { slotId, ...schedule, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToScheduleEntryLockDailyRepeatingScheduleSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof ScheduleEntryLockCCDailyRepeatingScheduleSet ) { const userCodeCapabilities = { ...defaultUserCodeCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; // If the user identifier is out of range, the command will be ignored - const userId = frame.payload.userId; - if (userId > userCodeCapabilities.numUsers) return true; + const userId = receivedCC.userId; + if (userId > userCodeCapabilities.numUsers) { + return { action: "fail" }; + } const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Schedule Entry Lock"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const slotId = frame.payload.slotId; + const slotId = receivedCC.slotId; // Ignore out of range slot queries - if (slotId > capabilities.numDailyRepeatingSlots) return true; + if (slotId > capabilities.numDailyRepeatingSlots) { + return { action: "fail" }; + } const kind = ScheduleEntryLockScheduleKind.DailyRepeating; const schedule = - frame.payload.action === ScheduleEntryLockSetAction.Set + receivedCC.action === ScheduleEntryLockSetAction.Set ? { - weekdays: frame.payload.weekdays!, - startHour: frame.payload.startHour!, - startMinute: frame.payload.startMinute!, - durationHour: frame.payload.durationHour!, - durationMinute: frame.payload.durationMinute!, + weekdays: receivedCC.weekdays!, + startHour: receivedCC.startHour!, + startMinute: receivedCC.startMinute!, + durationHour: receivedCC.durationHour!, + durationMinute: receivedCC.durationMinute!, } : undefined; self.state.set(StateKeys.schedule(userId, slotId, kind), schedule); - - return true; + return { action: "ok" }; } - return false; }, }; const respondToScheduleEntryLockDailyRepeatingScheduleGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof ScheduleEntryLockCCDailyRepeatingScheduleGet ) { const userCodeCapabilities = { ...defaultUserCodeCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; // If the user identifier is out of range, the command will be ignored - const userId = frame.payload.userId; - if (userId > userCodeCapabilities.numUsers) return true; + const userId = receivedCC.userId; + if (userId > userCodeCapabilities.numUsers) { + return { action: "fail" }; + } const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Schedule Entry Lock"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const slotId = frame.payload.slotId; + const slotId = receivedCC.slotId; // Ignore out of range slot queries - if (slotId > capabilities.numDailyRepeatingSlots) return true; + if (slotId > capabilities.numDailyRepeatingSlots) { + return { action: "fail" }; + } const kind = ScheduleEntryLockScheduleKind.DailyRepeating; @@ -444,14 +403,8 @@ const respondToScheduleEntryLockDailyRepeatingScheduleGet: MockNodeBehavior = { ...schedule, }, ); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/SoundSwitch.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/SoundSwitch.ts index 2aea80a41fa0..a4956b19ca80 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/SoundSwitch.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/SoundSwitch.ts @@ -10,9 +10,7 @@ import { import { CommandClasses } from "@zwave-js/core/safe"; import { type MockNodeBehavior, - MockZWaveFrameType, type SoundSwitchCCCapabilities, - createMockZWaveRequestFrame, } from "@zwave-js/testing"; const defaultCapabilities: SoundSwitchCCCapabilities = { @@ -28,16 +26,13 @@ const StateKeys = { } as const; const respondToSoundSwitchConfigurationGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SoundSwitchCCConfigurationGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SoundSwitchCCConfigurationGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Sound Switch"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const cc = new SoundSwitchCCConfigurationReport(self.host, { @@ -49,95 +44,67 @@ const respondToSoundSwitchConfigurationGet: MockNodeBehavior = { (self.state.get(StateKeys.defaultVolume) as number) ?? capabilities.defaultVolume, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToSoundSwitchConfigurationSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SoundSwitchCCConfigurationSet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SoundSwitchCCConfigurationSet) { self.state.set( StateKeys.defaultToneId, - frame.payload.defaultToneId, + receivedCC.defaultToneId, ); self.state.set( StateKeys.defaultVolume, - frame.payload.defaultVolume, + receivedCC.defaultVolume, ); - - return true; + return { action: "ok" }; } - return false; }, }; const respondToSoundSwitchToneNumberGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SoundSwitchCCTonesNumberGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SoundSwitchCCTonesNumberGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Sound Switch"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const cc = new SoundSwitchCCTonesNumberReport(self.host, { nodeId: controller.host.ownNodeId, toneCount: capabilities.tones.length, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToSoundSwitchToneInfoGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SoundSwitchCCToneInfoGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SoundSwitchCCToneInfoGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Sound Switch"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const tone = capabilities.tones[frame.payload.toneId - 1]; + const tone = capabilities.tones[receivedCC.toneId - 1]; if (tone) { const cc = new SoundSwitchCCToneInfoReport(self.host, { nodeId: controller.host.ownNodeId, - toneId: frame.payload.toneId, + toneId: receivedCC.toneId, ...tone, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } + return { action: "stop" }; } - return false; }, }; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/ThermostatMode.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/ThermostatMode.ts index b01e3bd09e7c..afbc3b2635df 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/ThermostatMode.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/ThermostatMode.ts @@ -9,9 +9,7 @@ import { import { CommandClasses } from "@zwave-js/core/safe"; import { type MockNodeBehavior, - MockZWaveFrameType, type ThermostatModeCCCapabilities, - createMockZWaveRequestFrame, } from "@zwave-js/testing"; const defaultCapabilities: ThermostatModeCCCapabilities = { @@ -25,28 +23,21 @@ const StateKeys = { } as const; const respondToThermostatModeSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ThermostatModeCCSet - ) { - self.state.set(StateKeys.mode, frame.payload.mode); + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ThermostatModeCCSet) { + self.state.set(StateKeys.mode, receivedCC.mode); self.state.set( StateKeys.manufacturerData, - frame.payload.manufacturerData, + receivedCC.manufacturerData, ); - return true; + return { action: "ok" }; } - return false; }, }; const respondToThermostatModeGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ThermostatModeCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ThermostatModeCCGet) { const mode = (self.state.get(StateKeys.mode) ?? ThermostatMode.Off) as ThermostatMode; const manufacturerData = @@ -61,28 +52,19 @@ const respondToThermostatModeGet: MockNodeBehavior = { // @ts-expect-error I know... manufacturerData, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToThermostatModeSupportedGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ThermostatModeCCSupportedGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ThermostatModeCCSupportedGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Thermostat Mode"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; @@ -90,14 +72,8 @@ const respondToThermostatModeSupportedGet: MockNodeBehavior = { nodeId: controller.host.ownNodeId, supportedModes: capabilities.supportedModes, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/ThermostatSetpoint.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/ThermostatSetpoint.ts index afd869d7c850..2209f732c553 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/ThermostatSetpoint.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/ThermostatSetpoint.ts @@ -11,9 +11,7 @@ import { import { CommandClasses } from "@zwave-js/core/safe"; import { type MockNodeBehavior, - MockZWaveFrameType, type ThermostatSetpointCCCapabilities, - createMockZWaveRequestFrame, } from "@zwave-js/testing"; const defaultCapabilities: ThermostatSetpointCCCapabilities = { @@ -34,59 +32,52 @@ const StateKeys = { } as const; const respondToThermostatSetpointSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ThermostatSetpointCCSet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ThermostatSetpointCCSet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Thermostat Setpoint"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const setpointCaps = - capabilities.setpoints[frame.payload.setpointType]; - if (!setpointCaps) return true; + capabilities.setpoints[receivedCC.setpointType]; + if (!setpointCaps) return { action: "fail" }; - const value = frame.payload.value; + const value = receivedCC.value; if ( value > setpointCaps.minValue || value > setpointCaps.maxValue ) { - return true; + return { action: "fail" }; } self.state.set( - StateKeys.setpoint(frame.payload.setpointType), + StateKeys.setpoint(receivedCC.setpointType), value, ); self.state.set( - StateKeys.scale(frame.payload.setpointType), - frame.payload.scale, + StateKeys.scale(receivedCC.setpointType), + receivedCC.scale, ); - return true; + return { action: "ok" }; } - return false; }, }; const respondToThermostatSetpointGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ThermostatSetpointCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ThermostatSetpointCCGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Thermostat Setpoint"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const setpointType = frame.payload.setpointType; + const setpointType = receivedCC.setpointType; const setpointCaps = capabilities.setpoints[setpointType]; @@ -121,29 +112,19 @@ const respondToThermostatSetpointGet: MockNodeBehavior = { value: 0, }); } - - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToThermostatSetpointSupportedGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ThermostatSetpointCCSupportedGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ThermostatSetpointCCSupportedGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Thermostat Setpoint"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; @@ -153,32 +134,23 @@ const respondToThermostatSetpointSupportedGet: MockNodeBehavior = { (k) => parseInt(k), ), }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToThermostatSetpointCapabilitiesGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ThermostatSetpointCCCapabilitiesGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ThermostatSetpointCCCapabilitiesGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Thermostat Setpoint"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const setpointType = frame.payload.setpointType; + const setpointType = receivedCC.setpointType; const setpointCaps = capabilities.setpoints[setpointType]; let cc: ThermostatSetpointCCCapabilitiesReport; @@ -201,15 +173,8 @@ const respondToThermostatSetpointCapabilitiesGet: MockNodeBehavior = { maxValueScale: 0, }); } - - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/UserCode.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/UserCode.ts index d61491896b18..7661f011c99b 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/UserCode.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/UserCode.ts @@ -19,9 +19,7 @@ import { import { CRC16_CCITT, CommandClasses } from "@zwave-js/core/safe"; import { type MockNodeBehavior, - MockZWaveFrameType, type UserCodeCCCapabilities, - createMockZWaveRequestFrame, } from "@zwave-js/testing"; export const defaultCapabilities: UserCodeCCCapabilities = { @@ -48,47 +46,35 @@ const StateKeys = { } as const; const respondToUsersNumberGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof UserCodeCCUsersNumberGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof UserCodeCCUsersNumberGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const cc = new UserCodeCCUsersNumberReport(self.host, { nodeId: controller.host.ownNodeId, supportedUsers: capabilities.numUsers ?? 1, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToUserGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof UserCodeCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof UserCodeCCGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const userId = frame.payload.userId; + const userId = receivedCC.userId; let cc: UserCodeCCReport; if (capabilities.numUsers >= userId) { cc = new UserCodeCCReport(self.host, { @@ -108,60 +94,47 @@ const respondToUserGet: MockNodeBehavior = { userIdStatus: UserIDStatus.StatusNotAvailable, }); } - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToUserCodeSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof UserCodeCCSet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof UserCodeCCSet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const userId = frame.payload.userId; - const userIdStatus = frame.payload.userIdStatus; + const userId = receivedCC.userId; + const userIdStatus = receivedCC.userIdStatus; if (capabilities.numUsers >= userId) { self.state.set(StateKeys.userIdStatus(userId), userIdStatus); const code = userIdStatus !== UserIDStatus.Available && userIdStatus !== UserIDStatus.StatusNotAvailable - ? frame.payload.userCode + ? receivedCC.userCode : undefined; self.state.set(StateKeys.userCode(userId), code); + return { action: "ok" }; } - - return true; + return { action: "fail" }; } - return false; }, }; const respondToUserCodeCapabilitiesGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof UserCodeCCCapabilitiesGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof UserCodeCCCapabilitiesGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const cc = new UserCodeCCCapabilitiesReport(self.host, { @@ -177,29 +150,19 @@ const respondToUserCodeCapabilitiesGet: MockNodeBehavior = { supportedKeypadModes: capabilities.supportedKeypadModes!, supportedASCIIChars: capabilities.supportedASCIIChars!, }); - - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToUserCodeKeypadModeGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof UserCodeCCKeypadModeGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof UserCodeCCKeypadModeGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const cc = new UserCodeCCKeypadModeReport(self.host, { @@ -208,58 +171,45 @@ const respondToUserCodeKeypadModeGet: MockNodeBehavior = { ?? capabilities.supportedKeypadModes?.[0] ?? KeypadMode.Normal) as KeypadMode, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToUserCodeKeypadModeSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof UserCodeCCKeypadModeSet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof UserCodeCCKeypadModeSet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; if ( capabilities.supportedKeypadModes?.includes( - frame.payload.keypadMode, + receivedCC.keypadMode, ) ) { - self.state.set(StateKeys.keypadMode, frame.payload.keypadMode); + self.state.set(StateKeys.keypadMode, receivedCC.keypadMode); + return { action: "ok" }; } - - return true; + return { action: "fail" }; } - return false; }, }; const respondToUserCodeAdminCodeSet: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof UserCodeCCAdminCodeSet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof UserCodeCCAdminCodeSet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; - const adminCode = frame.payload.adminCode; + const adminCode = receivedCC.adminCode; if (capabilities.supportsAdminCode) { if ( adminCode.length > 0 @@ -267,28 +217,24 @@ const respondToUserCodeAdminCodeSet: MockNodeBehavior = { ) { self.state.set( StateKeys.adminCode, - frame.payload.adminCode, + receivedCC.adminCode, ); + return { action: "ok" }; } } - - return true; + return { action: "fail" }; } - return false; }, }; const respondToUserCodeAdminCodeGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof UserCodeCCAdminCodeGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof UserCodeCCAdminCodeGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; let adminCode: string | undefined; @@ -300,28 +246,19 @@ const respondToUserCodeAdminCodeGet: MockNodeBehavior = { nodeId: controller.host.ownNodeId, adminCode: adminCode ?? "", }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; const respondToUserCodeUserCodeChecksumGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof UserCodeCCUserCodeChecksumGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof UserCodeCCUserCodeChecksumGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["User Code"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; if (capabilities.supportsUserCodeChecksum) { @@ -356,16 +293,10 @@ const respondToUserCodeUserCodeChecksumGet: MockNodeBehavior = { nodeId: controller.host.ownNodeId, userCodeChecksum: checksum, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); + return { action: "sendCC", cc }; } - - return true; + return { action: "stop" }; } - return false; }, }; diff --git a/packages/zwave-js/src/lib/node/mockCCBehaviors/WindowCovering.ts b/packages/zwave-js/src/lib/node/mockCCBehaviors/WindowCovering.ts index 845375e44f25..a72707d27d06 100644 --- a/packages/zwave-js/src/lib/node/mockCCBehaviors/WindowCovering.ts +++ b/packages/zwave-js/src/lib/node/mockCCBehaviors/WindowCovering.ts @@ -5,9 +5,7 @@ import { import { CommandClasses } from "@zwave-js/core/safe"; import { type MockNodeBehavior, - MockZWaveFrameType, type WindowCoveringCCCapabilities, - createMockZWaveRequestFrame, } from "@zwave-js/testing"; const defaultCapabilities: WindowCoveringCCCapabilities = { @@ -15,30 +13,21 @@ const defaultCapabilities: WindowCoveringCCCapabilities = { }; const respondToWindowCoveringSupportedGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof WindowCoveringCCSupportedGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof WindowCoveringCCSupportedGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Window Covering"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; const cc = new WindowCoveringCCSupportedReport(self.host, { nodeId: controller.host.ownNodeId, supportedParameters: capabilities.supportedParameters, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; diff --git a/packages/zwave-js/src/lib/test/cc/API.test.ts b/packages/zwave-js/src/lib/test/cc/API.test.ts index 4fa9724c9524..97762861ac6e 100644 --- a/packages/zwave-js/src/lib/test/cc/API.test.ts +++ b/packages/zwave-js/src/lib/test/cc/API.test.ts @@ -1,5 +1,5 @@ import { API, CCAPI } from "@zwave-js/cc"; -import { unknownBoolean } from "@zwave-js/core"; +import { NOT_KNOWN } from "@zwave-js/core"; import type { ThrowingMap } from "@zwave-js/shared"; import { MockController } from "@zwave-js/testing"; import ava, { type TestFn } from "ava"; @@ -16,7 +16,7 @@ interface TestContext { const test = ava as TestFn; -@API(0xff) +@API(0xff as any) export class DummyCCAPI extends CCAPI {} test.before(async (t) => { @@ -49,8 +49,8 @@ test.after.always(async (t) => { driver.removeAllListeners(); }); -test.serial(`supportsCommand() returns "unknown" by default`, (t) => { +test.serial(`supportsCommand() returns NOT_KNOWN by default`, (t) => { const { node2, driver } = t.context; const API = new DummyCCAPI(driver, node2); - t.is(API.supportsCommand(null as any), unknownBoolean); + t.is(API.supportsCommand(null as any), NOT_KNOWN); }); diff --git a/packages/zwave-js/src/lib/test/compat/binarySensorReportAnyUseFirstSupported.test.ts b/packages/zwave-js/src/lib/test/compat/binarySensorReportAnyUseFirstSupported.test.ts index 0a3db216b072..063e5f569ba6 100644 --- a/packages/zwave-js/src/lib/test/compat/binarySensorReportAnyUseFirstSupported.test.ts +++ b/packages/zwave-js/src/lib/test/compat/binarySensorReportAnyUseFirstSupported.test.ts @@ -5,12 +5,7 @@ import { BinarySensorType, } from "@zwave-js/cc"; import { CommandClasses } from "@zwave-js/core"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - ccCaps, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior, ccCaps } from "@zwave-js/testing"; import { defaultCapabilities } from "../../node/mockCCBehaviors/UserCode"; import { integrationTest } from "../integrationTestSuite"; @@ -33,16 +28,13 @@ integrationTest( customSetup: async (driver, mockController, mockNode) => { const respondToBinarySensorGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof BinarySensorCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof BinarySensorCCGet) { const capabilities = { ...defaultCapabilities, ...self.getCCCapabilities( CommandClasses["Binary Sensor"], - frame.payload.endpointIndex, + receivedCC.endpointIndex, ), }; @@ -52,15 +44,8 @@ integrationTest( type: BinarySensorType.Any, value: true, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToBinarySensorGet); diff --git a/packages/zwave-js/src/lib/test/compliance/decodeLowerS2Keys.test.ts b/packages/zwave-js/src/lib/test/compliance/decodeLowerS2Keys.test.ts index a79c93b452d8..c299f7530787 100644 --- a/packages/zwave-js/src/lib/test/compliance/decodeLowerS2Keys.test.ts +++ b/packages/zwave-js/src/lib/test/compliance/decodeLowerS2Keys.test.ts @@ -54,11 +54,8 @@ integrationTest( // Respond to S2 Nonce Get const respondToS2NonceGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof Security2CCNonceGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof Security2CCNonceGet) { const nonce = sm2Node.generateNonce( controller.host.ownNodeId, ); @@ -68,14 +65,8 @@ integrationTest( MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToS2NonceGet); diff --git a/packages/zwave-js/src/lib/test/compliance/discardInsecureCommands.test.ts b/packages/zwave-js/src/lib/test/compliance/discardInsecureCommands.test.ts index 3b6e6ad90ae2..47a527cda2f9 100644 --- a/packages/zwave-js/src/lib/test/compliance/discardInsecureCommands.test.ts +++ b/packages/zwave-js/src/lib/test/compliance/discardInsecureCommands.test.ts @@ -14,7 +14,6 @@ import { } from "@zwave-js/core"; import { type MockNodeBehavior, - MockZWaveFrameType, createMockZWaveRequestFrame, } from "@zwave-js/testing"; import { wait } from "alcalzone-shared/async"; @@ -70,11 +69,8 @@ integrationTest( // Respond to Nonce Get const respondToNonceGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof Security2CCNonceGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof Security2CCNonceGet) { const nonce = smNode.generateNonce( controller.host.ownNodeId, ); @@ -84,29 +80,20 @@ integrationTest( MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToNonceGet); // Handle decode errors const handleInvalidCC: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof InvalidCC - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof InvalidCC) { if ( - frame.payload.reason + receivedCC.reason === ZWaveErrorCodes.Security2CC_CannotDecode - || frame.payload.reason + || receivedCC.reason === ZWaveErrorCodes.Security2CC_NoSPAN ) { const nonce = smNode.generateNonce( @@ -118,15 +105,9 @@ integrationTest( MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } } - return false; }, }; mockNode.defineBehavior(handleInvalidCC); diff --git a/packages/zwave-js/src/lib/test/compliance/secureNodeSecureEndpoint.test.ts b/packages/zwave-js/src/lib/test/compliance/secureNodeSecureEndpoint.test.ts index f37be7c6a4f4..f05e0fa95292 100644 --- a/packages/zwave-js/src/lib/test/compliance/secureNodeSecureEndpoint.test.ts +++ b/packages/zwave-js/src/lib/test/compliance/secureNodeSecureEndpoint.test.ts @@ -21,11 +21,7 @@ import { SecurityManager2, ZWaveErrorCodes, } from "@zwave-js/core"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior, MockZWaveFrameType } from "@zwave-js/testing"; import { integrationTest } from "../integrationTestSuite"; integrationTest( @@ -124,11 +120,8 @@ integrationTest( // Respond to Nonce Get const respondToNonceGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof Security2CCNonceGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof Security2CCNonceGet) { const nonce = smNode.generateNonce( controller.host.ownNodeId, ); @@ -138,29 +131,20 @@ integrationTest( MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToNonceGet); // Handle decode errors const handleInvalidCC: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof InvalidCC - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof InvalidCC) { if ( - frame.payload.reason + receivedCC.reason === ZWaveErrorCodes.Security2CC_CannotDecode - || frame.payload.reason + || receivedCC.reason === ZWaveErrorCodes.Security2CC_NoSPAN ) { const nonce = smNode.generateNonce( @@ -172,30 +156,23 @@ integrationTest( MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } } - return false; }, }; mockNode.defineBehavior(handleInvalidCC); // The node was granted the S2_Unauthenticated key const respondToS2CommandsSupportedGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof Security2CCMessageEncapsulation - && frame.payload.encapsulated + && receivedCC.encapsulated instanceof Security2CCCommandsSupportedGet ) { - const isHighestGranted = frame.payload.securityClass + const isHighestGranted = receivedCC.securityClass === self.host.getHighestSecurityClass(self.id); const cc = Security2CC.encapsulate( @@ -216,25 +193,18 @@ integrationTest( : [], }), ); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToS2CommandsSupportedGet); const respondToS2MultiChannelCCEndPointGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof Security2CCMessageEncapsulation - && frame.payload.encapsulated + && receivedCC.encapsulated instanceof MultiChannelCCEndPointGet ) { const cc = Security2CC.encapsulate( @@ -246,28 +216,21 @@ integrationTest( individualCount: self.endpoints.size, }), ); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToS2MultiChannelCCEndPointGet); const respondToS2MultiChannelCCEndPointFind: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof Security2CCMessageEncapsulation - && frame.payload.encapsulated + && receivedCC.encapsulated instanceof MultiChannelCCEndPointFind ) { - const request = frame.payload.encapsulated; + const request = receivedCC.encapsulated; const cc = Security2CC.encapsulate( self.host, new MultiChannelCCEndPointFindReport(self.host, { @@ -278,29 +241,22 @@ integrationTest( reportsToFollow: 0, }), ); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToS2MultiChannelCCEndPointFind); const respondToS2MultiChannelCCCapabilityGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof Security2CCMessageEncapsulation - && frame.payload.encapsulated + && receivedCC.encapsulated instanceof MultiChannelCCCapabilityGet ) { const endpoint = self.endpoints.get( - frame.payload.encapsulated.requestedEndpoint, + receivedCC.encapsulated.requestedEndpoint, )!; const cc = Security2CC.encapsulate( self.host, @@ -320,14 +276,8 @@ integrationTest( ], }), ); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToS2MultiChannelCCCapabilityGet); diff --git a/packages/zwave-js/src/lib/test/driver/ignoreCCVersion0ForKnownSupportedCCs.test.ts b/packages/zwave-js/src/lib/test/driver/ignoreCCVersion0ForKnownSupportedCCs.test.ts index 6e0c00cbec5c..943f0472c536 100644 --- a/packages/zwave-js/src/lib/test/driver/ignoreCCVersion0ForKnownSupportedCCs.test.ts +++ b/packages/zwave-js/src/lib/test/driver/ignoreCCVersion0ForKnownSupportedCCs.test.ts @@ -71,11 +71,8 @@ integrationTest( // Respond to Nonce Get const respondToNonceGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof Security2CCNonceGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof Security2CCNonceGet) { const nonce = smNode.generateNonce( controller.host.ownNodeId, ); @@ -85,29 +82,20 @@ integrationTest( MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToNonceGet); // Handle decode errors const handleInvalidCC: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof InvalidCC - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof InvalidCC) { if ( - frame.payload.reason + receivedCC.reason === ZWaveErrorCodes.Security2CC_CannotDecode - || frame.payload.reason + || receivedCC.reason === ZWaveErrorCodes.Security2CC_NoSPAN ) { const nonce = smNode.generateNonce( @@ -119,28 +107,21 @@ integrationTest( MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } } - return false; }, }; mockNode.defineBehavior(handleInvalidCC); const reportSecurelySupportedCCs: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof Security2CCMessageEncapsulation - && frame.payload.securityClass + && receivedCC.securityClass === SecurityClass.S2_Unauthenticated - && frame.payload.encapsulated + && receivedCC.encapsulated instanceof Security2CCCommandsSupportedGet ) { let cc: CommandClass = @@ -155,27 +136,20 @@ integrationTest( }, ); cc = Security2CC.encapsulate(self.host, cc); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(reportSecurelySupportedCCs); const respondWithInvalidVersionReport: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof Security2CCMessageEncapsulation - && frame.payload.encapsulated + && receivedCC.encapsulated instanceof VersionCCCommandClassGet - && frame.payload.encapsulated.requestedCC + && receivedCC.encapsulated.requestedCC === CommandClasses["Security 2"] ) { let cc: CommandClass = new VersionCCCommandClassReport( @@ -183,19 +157,13 @@ integrationTest( { nodeId: controller.host.ownNodeId, requestedCC: - frame.payload.encapsulated.requestedCC, + receivedCC.encapsulated.requestedCC, ccVersion: 0, }, ); cc = Security2CC.encapsulate(self.host, cc); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondWithInvalidVersionReport); @@ -238,11 +206,8 @@ integrationTest( // Respond to S0 Nonce Get const respondToS0NonceGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SecurityCCNonceGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SecurityCCNonceGet) { const nonce = sm0Node.generateNonce( controller.host.ownNodeId, 8, @@ -251,25 +216,17 @@ integrationTest( nodeId: controller.host.ownNodeId, nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToS0NonceGet); const reportSecurelySupportedCCs: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + async handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload - instanceof SecurityCCCommandEncapsulation - && frame.payload.encapsulated + receivedCC instanceof SecurityCCCommandEncapsulation + && receivedCC.encapsulated instanceof SecurityCCCommandsSupportedGet ) { const nonceGet = new SecurityCCNonceGet(self.host, { @@ -308,28 +265,26 @@ integrationTest( ); const cc = SecurityCC.encapsulate(self.host, response); cc.nonce = receiverNonce; - await self.sendToController( createMockZWaveRequestFrame(cc, { ackRequested: false, }), ); - return true; + + return { action: "stop" }; } - return false; }, }; mockNode.defineBehavior(reportSecurelySupportedCCs); const respondWithInvalidVersionReport: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + async handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof SecurityCCCommandEncapsulation - && frame.payload.encapsulated + && receivedCC.encapsulated instanceof VersionCCCommandClassGet - && frame.payload.encapsulated.requestedCC + && receivedCC.encapsulated.requestedCC === CommandClasses.Security ) { await wait(100); @@ -361,38 +316,36 @@ integrationTest( { nodeId: controller.host.ownNodeId, requestedCC: - frame.payload.encapsulated.requestedCC, + receivedCC.encapsulated.requestedCC, ccVersion: 0, }, ); const cc = SecurityCC.encapsulate(self.host, response); cc.nonce = receiverNonce; - await self.sendToController( createMockZWaveRequestFrame(cc, { ackRequested: false, }), ); - return true; + + return { action: "stop" }; } - return false; }, }; mockNode.defineBehavior(respondWithInvalidVersionReport); // Parse Security CC commands const parseS0CC: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { // We don't support sequenced commands here if ( - frame.type === MockZWaveFrameType.Request - && frame.payload - instanceof SecurityCCCommandEncapsulation + receivedCC instanceof SecurityCCCommandEncapsulation ) { - frame.payload.mergePartialCCs(undefined as any, []); + receivedCC.mergePartialCCs(undefined as any, []); } - return false; + + return undefined; }, }; mockNode.defineBehavior(parseS0CC); diff --git a/packages/zwave-js/src/lib/test/driver/multiStageResponseNoTimeout.test.ts b/packages/zwave-js/src/lib/test/driver/multiStageResponseNoTimeout.test.ts index d0cdcc412739..c835f75e5036 100644 --- a/packages/zwave-js/src/lib/test/driver/multiStageResponseNoTimeout.test.ts +++ b/packages/zwave-js/src/lib/test/driver/multiStageResponseNoTimeout.test.ts @@ -11,7 +11,6 @@ import { import { CommandClasses } from "@zwave-js/core"; import { type MockNodeBehavior, - MockZWaveFrameType, createMockZWaveRequestFrame, } from "@zwave-js/testing"; import { wait } from "alcalzone-shared/async"; @@ -35,15 +34,12 @@ integrationTest( async customSetup(driver, mockController, mockNode) { const respondToConfigurationNameGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ConfigurationCCNameGet - ) { + async handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ConfigurationCCNameGet) { await wait(700); let cc = new ConfigurationCCNameReport(self.host, { nodeId: controller.host.ownNodeId, - parameter: frame.payload.parameter, + parameter: receivedCC.parameter, name: "Test para", reportsToFollow: 1, }); @@ -57,7 +53,7 @@ integrationTest( cc = new ConfigurationCCNameReport(self.host, { nodeId: controller.host.ownNodeId, - parameter: frame.payload.parameter, + parameter: receivedCC.parameter, name: "meter", reportsToFollow: 0, }); @@ -66,9 +62,9 @@ integrationTest( ackRequested: false, }), ); - return true; + + return { action: "stop" }; } - return false; }, }; mockNode.defineBehavior(respondToConfigurationNameGet); @@ -102,16 +98,13 @@ integrationTest( async customSetup(driver, mockController, mockNode) { const respondToConfigurationNameGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ConfigurationCCNameGet - ) { + async handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ConfigurationCCNameGet) { const configCC = new ConfigurationCCNameReport( self.host, { nodeId: controller.host.ownNodeId, - parameter: frame.payload.parameter, + parameter: receivedCC.parameter, name: "Veeeeeeeeeeeeeeeeeeeeeeeeery loooooooooooooooooong parameter name", reportsToFollow: 0, @@ -159,9 +152,8 @@ integrationTest( ackRequested: false, }), ); - return true; + return { action: "stop" }; } - return false; }, }; mockNode.defineBehavior(respondToConfigurationNameGet); @@ -190,24 +182,15 @@ integrationTest("GET requests DO time out if there's no matching response", { async customSetup(driver, mockController, mockNode) { const respondToConfigurationNameGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof ConfigurationCCNameGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof ConfigurationCCNameGet) { // This is not the response you're looking for const cc = new BasicCCReport(self.host, { nodeId: controller.host.ownNodeId, currentValue: 1, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToConfigurationNameGet); diff --git a/packages/zwave-js/src/lib/test/driver/nodeAsleepBlockNonceReport.test.ts b/packages/zwave-js/src/lib/test/driver/nodeAsleepBlockNonceReport.test.ts index aa674185e16f..8692762b305a 100644 --- a/packages/zwave-js/src/lib/test/driver/nodeAsleepBlockNonceReport.test.ts +++ b/packages/zwave-js/src/lib/test/driver/nodeAsleepBlockNonceReport.test.ts @@ -43,11 +43,8 @@ integrationTest( // Respond to S0 Nonce Get const respondToS0NonceGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SecurityCCNonceGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SecurityCCNonceGet) { const nonce = sm0Node.generateNonce( controller.host.ownNodeId, 8, @@ -56,31 +53,24 @@ integrationTest( nodeId: controller.host.ownNodeId, nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToS0NonceGet); // Parse Security CC commands. This MUST be defined last, since defineBehavior will prepend it to the list const parseS0CC: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { // We don't support sequenced commands here if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof SecurityCCCommandEncapsulation ) { - frame.payload.mergePartialCCs(undefined as any, []); + receivedCC.mergePartialCCs(undefined as any, []); } // This just decodes - we need to call further handlers - return false; + return undefined; }, }; mockNode.defineBehavior(parseS0CC); diff --git a/packages/zwave-js/src/lib/test/driver/nodeAsleepMessageOrder.test.ts b/packages/zwave-js/src/lib/test/driver/nodeAsleepMessageOrder.test.ts index 97194b4a6ea2..412b62834e73 100644 --- a/packages/zwave-js/src/lib/test/driver/nodeAsleepMessageOrder.test.ts +++ b/packages/zwave-js/src/lib/test/driver/nodeAsleepMessageOrder.test.ts @@ -142,8 +142,10 @@ integrationTest( const [mockNode10] = mockNodes; const doNotAnswerWhenAsleep: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if (!mockNode10.autoAckControllerFrames) return true; + handleCC(controller, self, receivedCC) { + if (!mockNode10.autoAckControllerFrames) { + return { action: "stop" }; + } }, }; mockNode10.defineBehavior(doNotAnswerWhenAsleep); @@ -257,8 +259,10 @@ integrationTest( const [mockNode10] = mockNodes; const doNotAnswerWhenAsleep: MockNodeBehavior = { - onControllerFrame(controller, self, frame) { - if (!mockNode10.autoAckControllerFrames) return true; + handleCC(controller, self, receivedCC) { + if (!mockNode10.autoAckControllerFrames) { + return { action: "stop" }; + } }, }; mockNode10.defineBehavior(doNotAnswerWhenAsleep); diff --git a/packages/zwave-js/src/lib/test/driver/nodeUpdateBeforeCallback.test.ts b/packages/zwave-js/src/lib/test/driver/nodeUpdateBeforeCallback.test.ts index acd21d1f500d..62db5673455f 100644 --- a/packages/zwave-js/src/lib/test/driver/nodeUpdateBeforeCallback.test.ts +++ b/packages/zwave-js/src/lib/test/driver/nodeUpdateBeforeCallback.test.ts @@ -1,7 +1,6 @@ import { BasicCCGet, BasicCCReport } from "@zwave-js/cc"; import { type MockNodeBehavior, - MockZWaveFrameType, createMockZWaveRequestFrame, } from "@zwave-js/testing"; import { wait } from "alcalzone-shared/async"; @@ -29,11 +28,8 @@ integrationTest( mockNode.autoAckControllerFrames = false; const respondToBasicGetWithDelayedAck: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof BasicCCGet - ) { + async handleCC(controller, self, receivedCC) { + if (receivedCC instanceof BasicCCGet) { const cc = new BasicCCReport(controller.host, { nodeId: self.id, currentValue: 55, @@ -46,10 +42,8 @@ integrationTest( await wait(100); - await self.ackControllerRequestFrame(frame); - return true; + return { action: "ack" }; } - return false; }, }; mockNode.defineBehavior(respondToBasicGetWithDelayedAck); diff --git a/packages/zwave-js/src/lib/test/driver/notificationPushNoAGI.test.ts b/packages/zwave-js/src/lib/test/driver/notificationPushNoAGI.test.ts index 1a333edaccd5..6c93deb2f757 100644 --- a/packages/zwave-js/src/lib/test/driver/notificationPushNoAGI.test.ts +++ b/packages/zwave-js/src/lib/test/driver/notificationPushNoAGI.test.ts @@ -4,12 +4,7 @@ import { NotificationCCValues, } from "@zwave-js/cc/NotificationCC"; import { CommandClasses } from "@zwave-js/core"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - ccCaps, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior, ccCaps } from "@zwave-js/testing"; import { integrationTest } from "../integrationTestSuite"; integrationTest( @@ -36,12 +31,9 @@ integrationTest( customSetup: async (driver, controller, mockNode) => { const respondToNotificationGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof NotificationCCGet - ) { - const notificationType = frame.payload.notificationType + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof NotificationCCGet) { + const notificationType = receivedCC.notificationType || 0x06; const cc = new NotificationCCReport(self.host, { nodeId: controller.host.ownNodeId, @@ -50,14 +42,8 @@ integrationTest( ? 0x06 /* Keypad unlock */ : 0xfe, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToNotificationGet); diff --git a/packages/zwave-js/src/lib/test/driver/s0AndS2Encapsulation.test.ts b/packages/zwave-js/src/lib/test/driver/s0AndS2Encapsulation.test.ts index 8fb235016495..fab63ac425c9 100644 --- a/packages/zwave-js/src/lib/test/driver/s0AndS2Encapsulation.test.ts +++ b/packages/zwave-js/src/lib/test/driver/s0AndS2Encapsulation.test.ts @@ -19,11 +19,7 @@ import { SupervisionStatus, ZWaveErrorCodes, } from "@zwave-js/core"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior, MockZWaveFrameType } from "@zwave-js/testing"; import { wait } from "alcalzone-shared/async"; import path from "node:path"; import { integrationTest } from "../integrationTestSuite"; @@ -92,11 +88,8 @@ integrationTest("S0 commands are S0-encapsulated, even when S2 is supported", { // Respond to S0 Nonce Get const respondToS0NonceGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SecurityCCNonceGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SecurityCCNonceGet) { const nonce = sm0Node.generateNonce( controller.host.ownNodeId, 8, @@ -105,40 +98,28 @@ integrationTest("S0 commands are S0-encapsulated, even when S2 is supported", { nodeId: controller.host.ownNodeId, nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToS0NonceGet); // Parse Security CC commands const parseS0CC: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { // We don't support sequenced commands here - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SecurityCCCommandEncapsulation - ) { - frame.payload.mergePartialCCs(undefined as any, []); + if (receivedCC instanceof SecurityCCCommandEncapsulation) { + receivedCC.mergePartialCCs(undefined as any, []); } - return false; + return undefined; }, }; mockNode.defineBehavior(parseS0CC); // Respond to S2 Nonce Get const respondToS2NonceGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof Security2CCNonceGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof Security2CCNonceGet) { const nonce = sm2Node.generateNonce( controller.host.ownNodeId, ); @@ -148,29 +129,20 @@ integrationTest("S0 commands are S0-encapsulated, even when S2 is supported", { MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToS2NonceGet); // Handle decode errors const handleInvalidCC: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof InvalidCC - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof InvalidCC) { if ( - frame.payload.reason + receivedCC.reason === ZWaveErrorCodes.Security2CC_CannotDecode - || frame.payload.reason + || receivedCC.reason === ZWaveErrorCodes.Security2CC_NoSPAN ) { const nonce = sm2Node.generateNonce( @@ -182,42 +154,29 @@ integrationTest("S0 commands are S0-encapsulated, even when S2 is supported", { MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } } - return false; }, }; mockNode.defineBehavior(handleInvalidCC); // Just have the node respond to all Supervision Get positively const respondToSupervisionGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof Security2CCMessageEncapsulation - && frame.payload.encapsulated instanceof SupervisionCCGet + receivedCC instanceof Security2CCMessageEncapsulation + && receivedCC.encapsulated instanceof SupervisionCCGet ) { let cc: CommandClass = new SupervisionCCReport(self.host, { nodeId: controller.host.ownNodeId, - sessionId: frame.payload.encapsulated.sessionId, + sessionId: receivedCC.encapsulated.sessionId, moreUpdatesFollow: false, status: SupervisionStatus.Success, }); cc = Security2CC.encapsulate(self.host, cc); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToSupervisionGet); diff --git a/packages/zwave-js/src/lib/test/driver/s0Encapsulation.test.ts b/packages/zwave-js/src/lib/test/driver/s0Encapsulation.test.ts index cd68a9816b0b..1f5d451ecec9 100644 --- a/packages/zwave-js/src/lib/test/driver/s0Encapsulation.test.ts +++ b/packages/zwave-js/src/lib/test/driver/s0Encapsulation.test.ts @@ -43,11 +43,8 @@ integrationTest("Communication via Security S0 works", { // Respond to S0 Nonce Get const respondToS0NonceGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SecurityCCNonceGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SecurityCCNonceGet) { const nonce = sm0Node.generateNonce( controller.host.ownNodeId, 8, @@ -56,25 +53,18 @@ integrationTest("Communication via Security S0 works", { nodeId: controller.host.ownNodeId, nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToS0NonceGet); // Respond to S0 Commands Supported Get const respondToS0CommandsSupportedGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + async handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SecurityCCCommandEncapsulation - && frame.payload.encapsulated + receivedCC instanceof SecurityCCCommandEncapsulation + && receivedCC.encapsulated instanceof SecurityCCCommandsSupportedGet ) { const nonceGet = new SecurityCCNonceGet(self.host, { @@ -115,9 +105,8 @@ integrationTest("Communication via Security S0 works", { }), ); - return true; + return { action: "stop" }; } - return false; }, }; mockNode.defineBehavior(respondToS0CommandsSupportedGet); @@ -125,11 +114,10 @@ integrationTest("Communication via Security S0 works", { // Respond to S0-encapsulated Basic Get with a level that increases with each request let queryCount = 0; const respondToS0BasicGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + async handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SecurityCCCommandEncapsulation - && frame.payload.encapsulated instanceof BasicCCGet + receivedCC instanceof SecurityCCCommandEncapsulation + && receivedCC.encapsulated instanceof BasicCCGet ) { const nonceGet = new SecurityCCNonceGet(self.host, { nodeId: controller.host.ownNodeId, @@ -165,25 +153,21 @@ integrationTest("Communication via Security S0 works", { }), ); - return true; + return { action: "stop" }; } - return false; }, }; mockNode.defineBehavior(respondToS0BasicGet); // Parse Security CC commands. This MUST be defined last, since defineBehavior will prepend it to the list const parseS0CC: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { // We don't support sequenced commands here - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SecurityCCCommandEncapsulation - ) { - frame.payload.mergePartialCCs(undefined as any, []); + if (receivedCC instanceof SecurityCCCommandEncapsulation) { + receivedCC.mergePartialCCs(undefined as any, []); } // This just decodes - we need to call further handlers - return false; + return undefined; }, }; mockNode.defineBehavior(parseS0CC); diff --git a/packages/zwave-js/src/lib/test/driver/s0EncapsulationTwoNodes.test.ts b/packages/zwave-js/src/lib/test/driver/s0EncapsulationTwoNodes.test.ts index d36faba215ab..f7bb62b37dec 100644 --- a/packages/zwave-js/src/lib/test/driver/s0EncapsulationTwoNodes.test.ts +++ b/packages/zwave-js/src/lib/test/driver/s0EncapsulationTwoNodes.test.ts @@ -64,11 +64,8 @@ integrationTest( // Respond to S0 Nonce Get const respondToS0NonceGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SecurityCCNonceGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SecurityCCNonceGet) { const nonce = sm0Node.generateNonce( controller.host.ownNodeId, 8, @@ -77,26 +74,18 @@ integrationTest( nodeId: controller.host.ownNodeId, nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToS0NonceGet); // Respond to S0 Commands Supported Get const respondToS0CommandsSupportedGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + async handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload - instanceof SecurityCCCommandEncapsulation - && frame.payload.encapsulated + receivedCC instanceof SecurityCCCommandEncapsulation + && receivedCC.encapsulated instanceof SecurityCCCommandsSupportedGet ) { const nonceGet = new SecurityCCNonceGet(self.host, { @@ -144,9 +133,8 @@ integrationTest( }), ); - return true; + return { action: "stop" }; } - return false; }, }; mockNode.defineBehavior(respondToS0CommandsSupportedGet); @@ -154,12 +142,10 @@ integrationTest( // Respond to S0-encapsulated Basic Get with a level that increases with each request let queryCount = 0; const respondToS0BasicGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + async handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload - instanceof SecurityCCCommandEncapsulation - && frame.payload.encapsulated instanceof BasicCCGet + receivedCC instanceof SecurityCCCommandEncapsulation + && receivedCC.encapsulated instanceof BasicCCGet ) { // Introduce a delay in the response for the second query (after interview) // so we can simulate the other node interfering @@ -208,26 +194,23 @@ integrationTest( }), ); - return true; + return { action: "stop" }; } - return false; }, }; mockNode.defineBehavior(respondToS0BasicGet); // Parse Security CC commands. This MUST be defined last, since defineBehavior will prepend it to the list const parseS0CC: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { // We don't support sequenced commands here if ( - frame.type === MockZWaveFrameType.Request - && frame.payload - instanceof SecurityCCCommandEncapsulation + receivedCC instanceof SecurityCCCommandEncapsulation ) { - frame.payload.mergePartialCCs(undefined as any, []); + receivedCC.mergePartialCCs(undefined as any, []); } // This just decodes - we need to call further handlers - return false; + return undefined; }, }; mockNode.defineBehavior(parseS0CC); diff --git a/packages/zwave-js/src/lib/test/driver/s2Collisions.test.ts b/packages/zwave-js/src/lib/test/driver/s2Collisions.test.ts index af92f197979f..74992534b704 100644 --- a/packages/zwave-js/src/lib/test/driver/s2Collisions.test.ts +++ b/packages/zwave-js/src/lib/test/driver/s2Collisions.test.ts @@ -81,11 +81,8 @@ integrationTest( // Respond to Nonce Get const respondToNonceGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof Security2CCNonceGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof Security2CCNonceGet) { const nonce = smNode.generateNonce( controller.host.ownNodeId, ); @@ -95,29 +92,20 @@ integrationTest( MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToNonceGet); // Handle decode errors const handleInvalidCC: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof InvalidCC - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof InvalidCC) { if ( - frame.payload.reason + receivedCC.reason === ZWaveErrorCodes.Security2CC_CannotDecode - || frame.payload.reason + || receivedCC.reason === ZWaveErrorCodes.Security2CC_NoSPAN ) { const nonce = smNode.generateNonce( @@ -129,47 +117,34 @@ integrationTest( MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } } - return false; }, }; mockNode.defineBehavior(handleInvalidCC); // Just have the node respond to all Supervision Get positively const respondToSupervisionGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof Security2CCMessageEncapsulation - && frame.payload.encapsulated + && receivedCC.encapsulated instanceof SupervisionCCGet ) { let cc: CommandClass = new SupervisionCCReport( self.host, { nodeId: controller.host.ownNodeId, - sessionId: frame.payload.encapsulated.sessionId, + sessionId: receivedCC.encapsulated.sessionId, moreUpdatesFollow: false, status: SupervisionStatus.Success, }, ); cc = Security2CC.encapsulate(self.host, cc); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToSupervisionGet); @@ -271,11 +246,8 @@ integrationTest( // Respond to Nonce Get const respondToNonceGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof Security2CCNonceGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof Security2CCNonceGet) { const nonce = smNode.generateNonce( controller.host.ownNodeId, ); @@ -285,29 +257,20 @@ integrationTest( MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToNonceGet); // Handle decode errors const handleInvalidCC: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof InvalidCC - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof InvalidCC) { if ( - frame.payload.reason + receivedCC.reason === ZWaveErrorCodes.Security2CC_CannotDecode - || frame.payload.reason + || receivedCC.reason === ZWaveErrorCodes.Security2CC_NoSPAN ) { const nonce = smNode.generateNonce( @@ -319,15 +282,9 @@ integrationTest( MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } } - return false; }, }; mockNode.defineBehavior(handleInvalidCC); @@ -423,11 +380,8 @@ integrationTest( // Respond to Nonce Get const respondToNonceGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof Security2CCNonceGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof Security2CCNonceGet) { const nonce = smNode.generateNonce( controller.host.ownNodeId, ); @@ -437,29 +391,20 @@ integrationTest( MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToNonceGet); // Handle decode errors const handleInvalidCC: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof InvalidCC - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof InvalidCC) { if ( - frame.payload.reason + receivedCC.reason === ZWaveErrorCodes.Security2CC_CannotDecode - || frame.payload.reason + || receivedCC.reason === ZWaveErrorCodes.Security2CC_NoSPAN ) { const nonce = smNode.generateNonce( @@ -471,47 +416,34 @@ integrationTest( MOS: false, receiverEI: nonce, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } } - return false; }, }; mockNode.defineBehavior(handleInvalidCC); // Just have the node respond to all Supervision Get positively const respondToSupervisionGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof Security2CCMessageEncapsulation - && frame.payload.encapsulated + && receivedCC.encapsulated instanceof SupervisionCCGet ) { let cc: CommandClass = new SupervisionCCReport( self.host, { nodeId: controller.host.ownNodeId, - sessionId: frame.payload.encapsulated.sessionId, + sessionId: receivedCC.encapsulated.sessionId, moreUpdatesFollow: false, status: SupervisionStatus.Success, }, ); cc = Security2CC.encapsulate(self.host, cc); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToSupervisionGet); diff --git a/packages/zwave-js/src/lib/test/driver/setValueFailedSupervisionGet.test.ts b/packages/zwave-js/src/lib/test/driver/setValueFailedSupervisionGet.test.ts index ee703b281f34..dcf1e2a39911 100644 --- a/packages/zwave-js/src/lib/test/driver/setValueFailedSupervisionGet.test.ts +++ b/packages/zwave-js/src/lib/test/driver/setValueFailedSupervisionGet.test.ts @@ -7,11 +7,7 @@ import { SupervisionCCReport, } from "@zwave-js/cc"; import { CommandClasses, SupervisionStatus } from "@zwave-js/core"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior, MockZWaveFrameType } from "@zwave-js/testing"; import { wait } from "alcalzone-shared/async"; import { integrationTest } from "../integrationTestSuite"; @@ -34,47 +30,29 @@ integrationTest( customSetup: async (driver, controller, mockNode) => { // Have the node respond to all Supervision Get negatively const respondToSupervisionGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SupervisionCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SupervisionCCGet) { const cc = new SupervisionCCReport(self.host, { nodeId: controller.host.ownNodeId, - sessionId: frame.payload.sessionId, + sessionId: receivedCC.sessionId, moreUpdatesFollow: false, status: SupervisionStatus.Fail, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; // and always report OFF const respondToBinarySwitchGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof BinarySwitchCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof BinarySwitchCCGet) { const cc = new BinarySwitchCCReport(self.host, { nodeId: controller.host.ownNodeId, currentValue: false, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior( diff --git a/packages/zwave-js/src/lib/test/driver/setValueNoSupervision.test.ts b/packages/zwave-js/src/lib/test/driver/setValueNoSupervision.test.ts index 63acd75e858d..d58686b1606a 100644 --- a/packages/zwave-js/src/lib/test/driver/setValueNoSupervision.test.ts +++ b/packages/zwave-js/src/lib/test/driver/setValueNoSupervision.test.ts @@ -5,11 +5,7 @@ import { BinarySwitchCCValues, } from "@zwave-js/cc"; import { CommandClasses } from "@zwave-js/core"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior, MockZWaveFrameType } from "@zwave-js/testing"; import { wait } from "alcalzone-shared/async"; import { integrationTest } from "../integrationTestSuite"; @@ -31,23 +27,14 @@ integrationTest("setValue without supervision: expect validation GET", { // and always report OFF const respondToBinarySwitchGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof BinarySwitchCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof BinarySwitchCCGet) { const cc = new BinarySwitchCCReport(self.host, { nodeId: controller.host.ownNodeId, currentValue: false, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToBinarySwitchGet); diff --git a/packages/zwave-js/src/lib/test/driver/setValueSucceedAfterFailure.test.ts b/packages/zwave-js/src/lib/test/driver/setValueSucceedAfterFailure.test.ts index 90ab97642b72..b917f86bc453 100644 --- a/packages/zwave-js/src/lib/test/driver/setValueSucceedAfterFailure.test.ts +++ b/packages/zwave-js/src/lib/test/driver/setValueSucceedAfterFailure.test.ts @@ -5,8 +5,6 @@ import { CommandClasses, NodeStatus } from "@zwave-js/core"; import { MOCK_FRAME_ACK_TIMEOUT, type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, } from "@zwave-js/testing"; import { wait } from "alcalzone-shared/async"; import { integrationTest } from "../integrationTestSuite"; @@ -37,16 +35,15 @@ integrationTest( async customSetup(driver, mockController, mockNode) { // The default mock implementation does not support endpoints const respondToBasicGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload + receivedCC instanceof MultiChannelCCCommandEncapsulation - && frame.payload.encapsulated instanceof BasicCCGet + && receivedCC.encapsulated instanceof BasicCCGet ) { // Do not respond if BasicCC is not explicitly listed as supported if (!self.implementedCCs.has(CommandClasses.Basic)) { - return false; + return { action: "stop" }; } let cc: CommandClass = new BasicCCReport(self.host, { @@ -55,18 +52,12 @@ integrationTest( }); cc = new MultiChannelCCCommandEncapsulation(self.host, { nodeId: controller.host.ownNodeId, - destination: frame.payload.endpointIndex, - endpoint: frame.payload.destination as number, + destination: receivedCC.endpointIndex, + endpoint: receivedCC.destination as number, encapsulated: cc, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToBasicGet); diff --git a/packages/zwave-js/src/lib/test/driver/setValueSuccessfulSupervisionNoGet.test.ts b/packages/zwave-js/src/lib/test/driver/setValueSuccessfulSupervisionNoGet.test.ts index b0ecf4d7c9e8..8feb0bf5a816 100644 --- a/packages/zwave-js/src/lib/test/driver/setValueSuccessfulSupervisionNoGet.test.ts +++ b/packages/zwave-js/src/lib/test/driver/setValueSuccessfulSupervisionNoGet.test.ts @@ -6,11 +6,7 @@ import { SupervisionCCReport, } from "@zwave-js/cc"; import { CommandClasses, SupervisionStatus } from "@zwave-js/core"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior, MockZWaveFrameType } from "@zwave-js/testing"; import { wait } from "alcalzone-shared/async"; import sinon from "sinon"; import { integrationTest } from "../integrationTestSuite"; @@ -34,25 +30,16 @@ integrationTest( customSetup: async (driver, controller, mockNode) => { // Just have the node respond to all Supervision Get positively const respondToSupervisionGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SupervisionCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SupervisionCCGet) { const cc = new SupervisionCCReport(self.host, { nodeId: controller.host.ownNodeId, - sessionId: frame.payload.sessionId, + sessionId: receivedCC.sessionId, moreUpdatesFollow: false, status: SupervisionStatus.Success, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToSupervisionGet); diff --git a/packages/zwave-js/src/lib/test/driver/setValueSupervision255Get.test.ts b/packages/zwave-js/src/lib/test/driver/setValueSupervision255Get.test.ts index baf1650695a3..576d25fe5c99 100644 --- a/packages/zwave-js/src/lib/test/driver/setValueSupervision255Get.test.ts +++ b/packages/zwave-js/src/lib/test/driver/setValueSupervision255Get.test.ts @@ -30,51 +30,41 @@ integrationTest( customSetup: async (driver, controller, mockNode) => { // Just have the node respond to all Supervision Get positively const respondToSupervisionGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SupervisionCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SupervisionCCGet) { const cc = new SupervisionCCReport(self.host, { nodeId: controller.host.ownNodeId, - sessionId: frame.payload.sessionId, + sessionId: receivedCC.sessionId, moreUpdatesFollow: false, status: SupervisionStatus.Success, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToSupervisionGet); // Except the ones with a duration in the command, those need special handling const respondToSupervisionGetWithDuration: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { + handleCC(controller, self, receivedCC) { if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SupervisionCCGet - && frame.payload.encapsulated + receivedCC instanceof SupervisionCCGet + && receivedCC.encapsulated instanceof MultilevelSwitchCCSet - && !!frame.payload.encapsulated.duration + && !!receivedCC.encapsulated.duration ?.toMilliseconds() ) { const cc1 = new SupervisionCCReport(self.host, { nodeId: controller.host.ownNodeId, - sessionId: frame.payload.sessionId, + sessionId: receivedCC.sessionId, moreUpdatesFollow: true, status: SupervisionStatus.Working, - duration: frame.payload.encapsulated.duration, + duration: receivedCC.encapsulated.duration, }); const cc2 = new SupervisionCCReport(self.host, { nodeId: controller.host.ownNodeId, - sessionId: frame.payload.sessionId, + sessionId: receivedCC.sessionId, moreUpdatesFollow: false, status: SupervisionStatus.Success, }); @@ -93,13 +83,12 @@ integrationTest( }), ); }, - frame.payload.encapsulated.duration + receivedCC.encapsulated.duration .toMilliseconds(), ); - return true; + return { action: "stop" }; } - return false; }, }; mockNode.defineBehavior(respondToSupervisionGetWithDuration); @@ -107,12 +96,9 @@ integrationTest( let lastBrightness = 88; let currentBrightness = 0; const respondToMultilevelSwitchSet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof MultilevelSwitchCCSet - ) { - const targetValue = frame.payload.targetValue; + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof MultilevelSwitchCCSet) { + const targetValue = receivedCC.targetValue; if (targetValue === 255) { currentBrightness = lastBrightness; } else { @@ -122,33 +108,23 @@ integrationTest( } } - return true; + return { action: "ok" }; } - return false; }, }; mockNode.defineBehavior(respondToMultilevelSwitchSet); // Report Multilevel Switch status const respondToMultilevelSwitchGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof MultilevelSwitchCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof MultilevelSwitchCCGet) { const cc = new MultilevelSwitchCCReport(self.host, { nodeId: controller.host.ownNodeId, targetValue: 88, currentValue: 88, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToMultilevelSwitchGet); diff --git a/packages/zwave-js/src/lib/test/driver/setValueSupervisionSuccessMoreUpdates.test.ts b/packages/zwave-js/src/lib/test/driver/setValueSupervisionSuccessMoreUpdates.test.ts index 559976e55fba..6dea3ea9684d 100644 --- a/packages/zwave-js/src/lib/test/driver/setValueSupervisionSuccessMoreUpdates.test.ts +++ b/packages/zwave-js/src/lib/test/driver/setValueSupervisionSuccessMoreUpdates.test.ts @@ -5,11 +5,7 @@ import { ThermostatSetpointType, } from "@zwave-js/cc"; import { CommandClasses, SupervisionStatus } from "@zwave-js/core"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior } from "@zwave-js/testing"; import { wait } from "alcalzone-shared/async"; import sinon from "sinon"; import { integrationTest } from "../integrationTestSuite"; @@ -33,26 +29,17 @@ integrationTest( customSetup: async (_driver, _controller, mockNode) => { // Just have the node respond to all Supervision Get positively, but claim that more updates follow const respondToSupervisionGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SupervisionCCGet - ) { + async handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SupervisionCCGet) { const cc = new SupervisionCCReport(self.host, { nodeId: controller.host.ownNodeId, - sessionId: frame.payload.sessionId, + sessionId: receivedCC.sessionId, moreUpdatesFollow: true, // <-- this is the important part status: SupervisionStatus.Success, }); await wait(500); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToSupervisionGet); diff --git a/packages/zwave-js/src/lib/test/driver/setValueSupervisionWorking.test.ts b/packages/zwave-js/src/lib/test/driver/setValueSupervisionWorking.test.ts index c481c68d64da..43a916321b24 100644 --- a/packages/zwave-js/src/lib/test/driver/setValueSupervisionWorking.test.ts +++ b/packages/zwave-js/src/lib/test/driver/setValueSupervisionWorking.test.ts @@ -6,7 +6,6 @@ import { import { CommandClasses, Duration, SupervisionStatus } from "@zwave-js/core"; import { type MockNodeBehavior, - MockZWaveFrameType, createMockZWaveRequestFrame, } from "@zwave-js/testing"; import { wait } from "alcalzone-shared/async"; @@ -31,14 +30,11 @@ integrationTest( customSetup: async (_driver, _controller, mockNode) => { // When receiving a Supervision Get, first respond with "Working" and after a delay with "Success" const respondToSupervisionGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SupervisionCCGet - ) { + async handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SupervisionCCGet) { let cc = new SupervisionCCReport(self.host, { nodeId: controller.host.ownNodeId, - sessionId: frame.payload.sessionId, + sessionId: receivedCC.sessionId, moreUpdatesFollow: true, status: SupervisionStatus.Working, duration: new Duration(10, "seconds"), @@ -53,7 +49,7 @@ integrationTest( cc = new SupervisionCCReport(self.host, { nodeId: controller.host.ownNodeId, - sessionId: frame.payload.sessionId, + sessionId: receivedCC.sessionId, moreUpdatesFollow: false, status: SupervisionStatus.Success, }); @@ -63,9 +59,8 @@ integrationTest( }), ); - return true; + return { action: "stop" }; } - return false; }, }; mockNode.defineBehavior(respondToSupervisionGet); diff --git a/packages/zwave-js/src/lib/test/driver/supervisionRepeatedReport.test.ts b/packages/zwave-js/src/lib/test/driver/supervisionRepeatedReport.test.ts index 8f6b1e80415c..3e212e4ec7b5 100644 --- a/packages/zwave-js/src/lib/test/driver/supervisionRepeatedReport.test.ts +++ b/packages/zwave-js/src/lib/test/driver/supervisionRepeatedReport.test.ts @@ -4,11 +4,7 @@ import { SupervisionCCReport, } from "@zwave-js/cc"; import { CommandClasses, SupervisionStatus } from "@zwave-js/core"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior } from "@zwave-js/testing"; import path from "node:path"; import { integrationTest } from "../integrationTestSuite"; @@ -44,25 +40,16 @@ integrationTest( customSetup: async (driver, controller, mockNode) => { // Just have the node respond to all Supervision Get positively const respondToSupervisionGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof SupervisionCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof SupervisionCCGet) { const cc = new SupervisionCCReport(controller.host, { nodeId: self.id, - sessionId: frame.payload.sessionId, + sessionId: receivedCC.sessionId, moreUpdatesFollow: false, status: SupervisionStatus.Success, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToSupervisionGet); diff --git a/packages/zwave-js/src/lib/test/driver/targetValueVersionUnknown.test.ts b/packages/zwave-js/src/lib/test/driver/targetValueVersionUnknown.test.ts index 3156d6ad574a..fd296d90b871 100644 --- a/packages/zwave-js/src/lib/test/driver/targetValueVersionUnknown.test.ts +++ b/packages/zwave-js/src/lib/test/driver/targetValueVersionUnknown.test.ts @@ -5,11 +5,7 @@ import { VersionCCCommandClassGet, } from "@zwave-js/cc"; import { CommandClasses } from "@zwave-js/core"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior } from "@zwave-js/testing"; import { integrationTest } from "../integrationTestSuite"; integrationTest( @@ -29,37 +25,24 @@ integrationTest( customSetup: async (driver, controller, mockNode) => { // Do not respond to CC version queries const noResponseToVersionCommandClassGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof VersionCCCommandClassGet - ) { - return true; + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof VersionCCCommandClassGet) { + return { action: "stop" }; } - return false; }, }; mockNode.defineBehavior(noResponseToVersionCommandClassGet); // Respond to binary switch state const respondToBinarySwitchGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof BinarySwitchCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof BinarySwitchCCGet) { const cc = new BinarySwitchCCReport(self.host, { nodeId: controller.host.ownNodeId, currentValue: true, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToBinarySwitchGet); @@ -88,23 +71,14 @@ integrationTest( customSetup: async (driver, controller, mockNode) => { // Respond to binary switch state const respondToBinarySwitchGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof BinarySwitchCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof BinarySwitchCCGet) { const cc = new BinarySwitchCCReport(self.host, { nodeId: controller.host.ownNodeId, currentValue: true, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToBinarySwitchGet); diff --git a/packages/zwave-js/src/lib/test/driver/unknownValues.test.ts b/packages/zwave-js/src/lib/test/driver/unknownValues.test.ts index 8ee9974c7c3f..b8d97ab6d182 100644 --- a/packages/zwave-js/src/lib/test/driver/unknownValues.test.ts +++ b/packages/zwave-js/src/lib/test/driver/unknownValues.test.ts @@ -15,7 +15,6 @@ import { } from "@zwave-js/core"; import { type MockNodeBehavior, - MockZWaveFrameType, createMockZWaveRequestFrame, } from "@zwave-js/testing"; import { wait } from "alcalzone-shared/async"; @@ -42,25 +41,16 @@ integrationTest(`Basic Reports with the UNKNOWN state are correctly handled`, { customSetup: async (driver, controller, mockNode) => { // Respond to Basic CC Get, so the driver doesn't assume Basic CC is unsupported const respondToBasicGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof BasicCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof BasicCCGet) { const cc = new BasicCCReport(self.host, { nodeId: controller.host.ownNodeId, currentValue: 0, targetValue: 0, duration: new Duration(0, "seconds"), }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToBasicGet); diff --git a/packages/zwave-js/src/lib/test/node/legacyRefreshActuatorSensorCCs.test.ts b/packages/zwave-js/src/lib/test/node/legacyRefreshActuatorSensorCCs.test.ts index d67157c6d35b..0dc97d35cc31 100644 --- a/packages/zwave-js/src/lib/test/node/legacyRefreshActuatorSensorCCs.test.ts +++ b/packages/zwave-js/src/lib/test/node/legacyRefreshActuatorSensorCCs.test.ts @@ -4,11 +4,7 @@ import { MultilevelSwitchCCSet, } from "@zwave-js/cc"; import { CommandClasses } from "@zwave-js/core"; -import { - type MockNodeBehavior, - MockZWaveFrameType, - createMockZWaveRequestFrame, -} from "@zwave-js/testing"; +import { type MockNodeBehavior, MockZWaveFrameType } from "@zwave-js/testing"; import { wait } from "alcalzone-shared/async"; import { ApplicationUpdateRequestNodeInfoReceived } from "../../serialapi/application/ApplicationUpdateRequest"; import { integrationTest } from "../integrationTestSuite"; @@ -33,12 +29,9 @@ integrationTest( let lastBrightness = 88; let currentBrightness = 0; const respondToMultilevelSwitchSet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof MultilevelSwitchCCSet - ) { - const targetValue = frame.payload.targetValue; + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof MultilevelSwitchCCSet) { + const targetValue = receivedCC.targetValue; if (targetValue === 255) { currentBrightness = lastBrightness; } else { @@ -48,33 +41,23 @@ integrationTest( } } - return true; + return { action: "ok" }; } - return false; }, }; mockNode.defineBehavior(respondToMultilevelSwitchSet); // Report Multilevel Switch status const respondToMultilevelSwitchGet: MockNodeBehavior = { - async onControllerFrame(controller, self, frame) { - if ( - frame.type === MockZWaveFrameType.Request - && frame.payload instanceof MultilevelSwitchCCGet - ) { + handleCC(controller, self, receivedCC) { + if (receivedCC instanceof MultilevelSwitchCCGet) { const cc = new MultilevelSwitchCCReport(self.host, { nodeId: controller.host.ownNodeId, targetValue: 88, currentValue: 88, }); - await self.sendToController( - createMockZWaveRequestFrame(cc, { - ackRequested: false, - }), - ); - return true; + return { action: "sendCC", cc }; } - return false; }, }; mockNode.defineBehavior(respondToMultilevelSwitchGet); diff --git a/packages/zwave-js/src/lib/zniffer/MPDU.ts b/packages/zwave-js/src/lib/zniffer/MPDU.ts index 29f36d7c07d6..931318453830 100644 --- a/packages/zwave-js/src/lib/zniffer/MPDU.ts +++ b/packages/zwave-js/src/lib/zniffer/MPDU.ts @@ -128,7 +128,7 @@ export function parseMPDU( case 3: return LongRangeMPDU.from(frame); default: - validatePayload.fail( + throw validatePayload.fail( `Unsupported channel ${frame.channel}. MPDU payload: ${ buffer2hex(frame.payload) }`, @@ -142,7 +142,7 @@ export class LongRangeMPDU implements MPDU { this.frameInfo = options.frameInfo; if (options.frameInfo.channel !== 3) { - validatePayload.fail( + throw validatePayload.fail( `Unsupported channel ${options.frameInfo.channel} for LongRangeMPDU`, ); } @@ -179,7 +179,7 @@ export class LongRangeMPDU implements MPDU { ? SinglecastLongRangeMPDU : undefined; if (!Constructor) { - validatePayload.fail( + throw validatePayload.fail( `Unsupported Long Range MPDU header type ${this.headerType}`, ); } else if ( @@ -330,12 +330,12 @@ export class ZWaveMPDU implements MPDU { break; } case 3: { - validatePayload.fail( + throw validatePayload.fail( `Channel 3 (ZWLR) must be parsed as a LongRangeMPDU!`, ); } default: { - validatePayload.fail( + throw validatePayload.fail( `Unsupported channel ${options.frameInfo.channel}. MPDU payload: ${ buffer2hex(data) }`, @@ -357,7 +357,7 @@ export class ZWaveMPDU implements MPDU { ? ExplorerZWaveMPDU : undefined; if (!Constructor) { - validatePayload.fail( + throw validatePayload.fail( `Unsupported MPDU header type ${this.headerType}`, ); } else if ( @@ -645,7 +645,7 @@ export class ExplorerZWaveMPDU extends ZWaveMPDU { : undefined; if (!Constructor) { - validatePayload.fail( + throw validatePayload.fail( `Unsupported Explorer MPDU command ${this.command}`, ); } else if ( @@ -813,7 +813,7 @@ export function parseBeamFrame( }); } default: - validatePayload.fail( + throw validatePayload.fail( // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `Unsupported channel configuration ${channelConfig}. MPDU payload: ${ buffer2hex(frame.payload) @@ -834,12 +834,12 @@ export class ZWaveBeamStart { // OK break; case "4": { - validatePayload.fail( + throw validatePayload.fail( `Channel configuration 4 (ZWLR) must be parsed as a LongRangeMPDU!`, ); } default: { - validatePayload.fail( + throw validatePayload.fail( // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `Unsupported channel configuration ${channelConfig}. MPDU payload: ${ buffer2hex(data) @@ -891,12 +891,12 @@ export class LongRangeBeamStart { // OK break; case "4": { - validatePayload.fail( + throw validatePayload.fail( `Channel configuration 4 (ZWLR) must be parsed as a LongRangeMPDU!`, ); } default: { - validatePayload.fail( + throw validatePayload.fail( // eslint-disable-next-line @typescript-eslint/restrict-template-expressions `Unsupported channel configuration ${channelConfig}. MPDU payload: ${ buffer2hex(data) diff --git a/yarn.lock b/yarn.lock index d0046a199cfd..3d61389554a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1884,7 +1884,6 @@ __metadata: "@zwave-js/maintenance": "workspace:*" "@zwave-js/serial": "workspace:*" "@zwave-js/shared": "workspace:*" - "@zwave-js/testing": "workspace:*" "@zwave-js/transformers": "workspace:*" alcalzone-shared: "npm:^4.0.8" ansi-colors: "npm:^4.1.3" @@ -2203,6 +2202,7 @@ __metadata: "@microsoft/api-extractor": "npm:^7.47.0" "@types/node": "npm:^18.19.31" "@types/triple-beam": "npm:^1.3.5" + "@zwave-js/cc": "workspace:*" "@zwave-js/core": "workspace:*" "@zwave-js/host": "workspace:*" "@zwave-js/serial": "workspace:*"