UNPKG

inventoresed

Version:

Z-Wave driver written entirely in JavaScript/TypeScript

304 lines (272 loc) 7.71 kB
import { BasicCC, BasicCCGet, BasicCCReport, BasicCCSet, BasicCCValues, BasicCommand, getCCValues, } from "@zwave-js/cc"; import { CommandClasses } from "@zwave-js/core"; import { createTestingHost } from "@zwave-js/host"; import type { ThrowingMap } from "@zwave-js/shared"; import { MockController } from "@zwave-js/testing"; import { createDefaultMockControllerBehaviors } from "../../../Utils"; import type { Driver } from "../../driver/Driver"; import { createAndStartTestingDriver } from "../../driver/DriverMock"; import { ZWaveNode } from "../../node/Node"; import * as nodeUtils from "../../node/utils"; import { createTestNode } from "../mocks"; const host = createTestingHost(); function buildCCBuffer(payload: Buffer): Buffer { return Buffer.concat([ Buffer.from([ CommandClasses.Basic, // CC ]), payload, ]); } describe("lib/commandclass/BasicCC => ", () => { it("the Get command should serialize correctly", () => { const basicCC = new BasicCCGet(host, { nodeId: 1 }); const expected = buildCCBuffer( Buffer.from([ BasicCommand.Get, // CC Command ]), ); expect(basicCC.serialize()).toEqual(expected); }); it("the Set command should serialize correctly", () => { const basicCC = new BasicCCSet(host, { nodeId: 2, targetValue: 55, }); const expected = buildCCBuffer( Buffer.from([ BasicCommand.Set, // CC Command 55, // target value ]), ); expect(basicCC.serialize()).toEqual(expected); }); it("the Report command (v1) should be deserialized correctly", () => { const ccData = buildCCBuffer( Buffer.from([ BasicCommand.Report, // CC Command 55, // current value ]), ); const basicCC = new BasicCCReport(host, { nodeId: 2, data: ccData, }); expect(basicCC.currentValue).toBe(55); expect(basicCC.targetValue).toBeUndefined(); expect(basicCC.duration).toBeUndefined(); }); it("the Report command (v2) should be deserialized correctly", () => { const ccData = buildCCBuffer( Buffer.from([ BasicCommand.Report, // CC Command 55, // current value 66, // target value 1, // duration ]), ); const basicCC = new BasicCCReport(host, { nodeId: 2, data: ccData, }); expect(basicCC.currentValue).toBe(55); expect(basicCC.targetValue).toBe(66); expect(basicCC.duration!.unit).toBe("seconds"); expect(basicCC.duration!.value).toBe(1); }); it("deserializing an unsupported command should return an unspecified version of BasicCC", () => { const serializedCC = buildCCBuffer( Buffer.from([255]), // not a valid command ); const basicCC: any = new BasicCC(host, { nodeId: 2, data: serializedCC, }); expect(basicCC.constructor).toBe(BasicCC); }); // it("the CC values should have the correct metadata", () => { // // Readonly, 0-99 // const currentValueMeta = getCCValueMetadata( // CommandClasses.Basic, // "currentValue", // ); // expect(currentValueMeta).toMatchObject({ // readable: true, // writeable: false, // min: 0, // max: 99, // }); // // Writeable, 0-99 // const targetValueMeta = getCCValueMetadata( // CommandClasses.Basic, // "targetValue", // ); // expect(targetValueMeta).toMatchObject({ // readable: true, // writeable: true, // min: 0, // max: 99, // }); // }); describe("getDefinedValueIDs()", () => { it("should include the target value for all endpoints except the node itself", () => { // Repro for GH#377 const node2 = createTestNode(host, { id: 2, numEndpoints: 2, supportsCC(cc) { switch (cc) { case CommandClasses.Basic: case CommandClasses["Multi Channel"]: return true; } return false; }, getCCVersion(cc) { switch (cc) { case CommandClasses.Basic: // We only support V1, so no report of the target value return 1; case CommandClasses["Multi Channel"]: return 2; } return 0; }, }); host.nodes.set(node2.id, node2); const valueIDs = nodeUtils .getDefinedValueIDs(host as any, node2) .filter( ({ commandClass, property }) => commandClass === CommandClasses.Basic && property === "targetValue", ); const endpointIndizes = valueIDs.map(({ endpoint }) => endpoint); expect(endpointIndizes).toEqual([1, 2]); }); }); describe("getDefinedValueIDs() part 2", () => { let driver: Driver; let node2: ZWaveNode; let controller: MockController; beforeAll(async () => { ({ driver } = await createAndStartTestingDriver({ skipNodeInterview: true, loadConfiguration: false, beforeStartup(mockPort) { controller = new MockController({ serial: mockPort }); controller.defineBehavior( ...createDefaultMockControllerBehaviors(), ); }, })); node2 = new ZWaveNode(2, driver); (driver.controller.nodes as ThrowingMap<number, ZWaveNode>).set( node2.id, node2, ); node2.addCC(CommandClasses.Basic, { isSupported: true, }); }, 30000); afterAll(async () => { await driver.destroy(); }); it("should NOT include the compat event value", () => { const valueIDs = node2.getDefinedValueIDs(); expect(valueIDs.map(({ property }) => property)).not.toContain( BasicCCValues.compatEvent.id.property, ); }); it("except when the corresponding compat flag is set", () => { // @ts-expect-error node2["_deviceConfig"] = { compat: { treatBasicSetAsEvent: true, }, }; const valueIDs = node2.getDefinedValueIDs(); expect(valueIDs.map(({ property }) => property)).toContain( BasicCCValues.compatEvent.id.property, ); }); }); describe("responses should be detected correctly", () => { it("BasicCCSet should expect no response", () => { const cc = new BasicCCSet(host, { nodeId: 2, endpoint: 2, targetValue: 7, }); expect(cc.expectsCCResponse()).toBeFalse(); }); it("BasicCCSet => BasicCCReport = unexpected", () => { const ccRequest = new BasicCCSet(host, { nodeId: 2, endpoint: 2, targetValue: 7, }); const ccResponse = new BasicCCReport(host, { nodeId: ccRequest.nodeId, currentValue: 7, }); expect(ccRequest.isExpectedCCResponse(ccResponse)).toBeFalse(); }); it("BasicCCGet should expect a response", () => { const cc = new BasicCCGet(host, { nodeId: 2, }); expect(cc.expectsCCResponse()).toBeTrue(); }); it("BasicCCGet => BasicCCReport = expected", () => { const ccRequest = new BasicCCGet(host, { nodeId: 2, }); const ccResponse = new BasicCCReport(host, { nodeId: ccRequest.nodeId, currentValue: 7, }); expect(ccRequest.isExpectedCCResponse(ccResponse)).toBeTrue(); }); it("BasicCCGet => BasicCCReport (wrong node) = unexpected", () => { const ccRequest = new BasicCCGet(host, { nodeId: 2, }); const ccResponse = new BasicCCReport(host, { nodeId: (ccRequest.nodeId as number) + 1, currentValue: 7, }); expect(ccRequest.isExpectedCCResponse(ccResponse)).toBeFalse(); }); it("BasicCCGet => BasicCCSet = unexpected", () => { const ccRequest = new BasicCCGet(host, { nodeId: 2, }); const ccResponse = new BasicCCSet(host, { nodeId: ccRequest.nodeId, targetValue: 7, }); expect(ccRequest.isExpectedCCResponse(ccResponse)).toBeFalse(); }); }); describe("Looking up CC values for a CC instance", () => { it("should work", () => { const cc = new BasicCCGet(host, { nodeId: 2, }); const values = getCCValues(cc) as typeof BasicCCValues; expect(values.currentValue.id).toMatchObject({ commandClass: CommandClasses.Basic, property: "currentValue", }); }); }); });