UNPKG

inventoresed

Version:

Z-Wave driver written entirely in JavaScript/TypeScript

448 lines (412 loc) 12.5 kB
import { DoorLockCCCapabilitiesGet, DoorLockCCCapabilitiesReport, DoorLockCCConfigurationGet, DoorLockCCConfigurationReport, DoorLockCCConfigurationSet, DoorLockCCOperationGet, DoorLockCCOperationReport, DoorLockCCOperationSet, DoorLockCommand, DoorLockMode, DoorLockOperationType, } from "@zwave-js/cc"; import { DoorLockCCValues } from "@zwave-js/cc/DoorLockCC"; import { CommandClasses, Duration } from "@zwave-js/core"; import { createTestingHost, TestingHost } from "@zwave-js/host"; function buildCCBuffer(payload: Buffer): Buffer { return Buffer.concat([ Buffer.from([ CommandClasses["Door Lock"], // CC ]), payload, ]); } describe("lib/commandclass/DoorLockCC => ", () => { let host: TestingHost; beforeAll(() => { host = createTestingHost(); // Node 1 supports all Door Lock sensors const valueDB1 = host.getValueDB(1); valueDB1.setValue(DoorLockCCValues.doorSupported.id, true); valueDB1.setValue(DoorLockCCValues.boltSupported.id, true); valueDB1.setValue(DoorLockCCValues.latchSupported.id, true); // Node 2 doesn't support the door sensor const valueDB2 = host.getValueDB(2); valueDB2.setValue(DoorLockCCValues.doorSupported.id, false); valueDB2.setValue(DoorLockCCValues.boltSupported.id, true); valueDB2.setValue(DoorLockCCValues.latchSupported.id, true); }); it("the OperationGet command should serialize correctly", () => { const cc = new DoorLockCCOperationGet(host, { nodeId: 1 }); const expected = buildCCBuffer( Buffer.from([ DoorLockCommand.OperationGet, // CC Command ]), ); expect(cc.serialize()).toEqual(expected); }); it("the OperationSet command should serialize correctly", () => { const cc = new DoorLockCCOperationSet(host, { nodeId: 2, mode: DoorLockMode.OutsideUnsecured, }); const expected = buildCCBuffer( Buffer.from([ DoorLockCommand.OperationSet, // CC Command 0x20, // target value ]), ); expect(cc.serialize()).toEqual(expected); }); it("the OperationReport command (v1-v3) should be deserialized correctly", () => { const ccData = buildCCBuffer( Buffer.from([ DoorLockCommand.OperationReport, // CC Command DoorLockMode.InsideUnsecuredWithTimeout, // lock mode 0b1000_0010, // handles mode 0b010, // condition 50, // timeout minutes 20, // timeout seconds ]), ); const cc = new DoorLockCCOperationReport(host, { nodeId: 1, data: ccData, }); expect(cc.currentMode).toBe(DoorLockMode.InsideUnsecuredWithTimeout); expect(cc.outsideHandlesCanOpenDoor).toEqual([ false, false, false, true, ]); expect(cc.insideHandlesCanOpenDoor).toEqual([ false, true, false, false, ]); expect(cc.lockTimeout).toBe(50 * 60 + 20); expect(cc.latchStatus).toBe("open"); expect(cc.boltStatus).toBe("unlocked"); expect(cc.doorStatus).toBe("open"); expect(cc.targetMode).toBeUndefined(); expect(cc.duration).toBeUndefined(); }); it("the OperationReport command (v4) should be deserialized correctly", () => { const ccData = buildCCBuffer( Buffer.from([ DoorLockCommand.OperationReport, // CC Command DoorLockMode.OutsideUnsecured, // lock mode 0b0100_1111, // handles mode 0b101, // condition 0x00, // timeout minutes 0xfe, // invalid timeout seconds DoorLockMode.Secured, 0x01, // 1 second left ]), ); const cc = new DoorLockCCOperationReport(host, { nodeId: 2, data: ccData, }); cc.persistValues(host); expect(cc.currentMode).toBe(DoorLockMode.OutsideUnsecured); expect(cc.outsideHandlesCanOpenDoor).toEqual([ false, false, true, false, ]); expect(cc.insideHandlesCanOpenDoor).toEqual([true, true, true, true]); expect(cc.lockTimeout).toBeUndefined(); expect(cc.latchStatus).toBe("closed"); expect(cc.boltStatus).toBe("locked"); // The CC itself contains the door status, but it does not get persisted (unsupported) expect(cc.doorStatus).toBe("closed"); expect( host .getValueDB(cc.nodeId as number) .getValue( DoorLockCCValues.doorStatus.endpoint(cc.endpointIndex), ), ).toBe(undefined); expect(cc.targetMode).toBe(DoorLockMode.Secured); expect(cc.duration).toEqual(new Duration(1, "seconds")); }); it("the ConfigurationGet command should serialize correctly", () => { const cc = new DoorLockCCConfigurationGet(host, { nodeId: 1 }); const expected = buildCCBuffer( Buffer.from([ DoorLockCommand.ConfigurationGet, // CC Command ]), ); expect(cc.serialize()).toEqual(expected); }); it("the ConfigurationReport command (v1-v3) should be deserialized correctly", () => { const ccData = buildCCBuffer( Buffer.from([ DoorLockCommand.ConfigurationReport, // CC Command DoorLockOperationType.Timed, // operation type 0b1000_0010, // handles mode 50, // timeout minutes 20, // timeout seconds ]), ); const cc = new DoorLockCCConfigurationReport(host, { nodeId: 1, data: ccData, }); expect(cc.operationType).toBe(DoorLockOperationType.Timed); expect(cc.outsideHandlesCanOpenDoorConfiguration).toEqual([ false, false, false, true, ]); expect(cc.insideHandlesCanOpenDoorConfiguration).toEqual([ false, true, false, false, ]); expect(cc.lockTimeoutConfiguration).toBe(50 * 60 + 20); expect(cc.autoRelockTime).toBeUndefined(); expect(cc.holdAndReleaseTime).toBeUndefined(); expect(cc.twistAssist).toBeUndefined(); expect(cc.blockToBlock).toBeUndefined(); }); it("the ConfigurationReport command must ignore invalid timeouts (constant)", () => { const ccData = buildCCBuffer( Buffer.from([ DoorLockCommand.ConfigurationReport, // CC Command DoorLockOperationType.Constant, // operation type 0b1000_0010, // handles mode 50, // timeout minutes 20, // timeout seconds ]), ); const cc = new DoorLockCCConfigurationReport(host, { nodeId: 1, data: ccData, }); expect(cc.lockTimeoutConfiguration).toBeUndefined(); }); it("the ConfigurationReport command must ignore invalid timeouts (invalid minutes)", () => { const ccData = buildCCBuffer( Buffer.from([ DoorLockCommand.ConfigurationReport, // CC Command DoorLockOperationType.Constant, // operation type 0b1000_0010, // handles mode 0xff, // timeout minutes 20, // timeout seconds ]), ); const cc = new DoorLockCCConfigurationReport(host, { nodeId: 1, data: ccData, }); expect(cc.lockTimeoutConfiguration).toBeUndefined(); }); it("the ConfigurationReport command must ignore invalid timeouts (invalid seconds)", () => { const ccData = buildCCBuffer( Buffer.from([ DoorLockCommand.ConfigurationReport, // CC Command DoorLockOperationType.Constant, // operation type 0b1000_0010, // handles mode 20, // timeout minutes 0xff, // timeout seconds ]), ); const cc = new DoorLockCCConfigurationReport(host, { nodeId: 1, data: ccData, }); expect(cc.lockTimeoutConfiguration).toBeUndefined(); }); it("the ConfigurationReport command (v4) should be deserialized correctly", () => { const ccData = buildCCBuffer( Buffer.from([ DoorLockCommand.ConfigurationReport, // CC Command DoorLockOperationType.Timed, // operation type 0b1000_0010, // handles mode 50, // timeout minutes 20, // timeout seconds 0xff, // auto relock 0x01, 0x02, // hold and release 0x03, 0b01, // flags ]), ); const cc = new DoorLockCCConfigurationReport(host, { nodeId: 1, data: ccData, }); expect(cc.autoRelockTime).toBe(0xff01); expect(cc.holdAndReleaseTime).toBe(0x0203); expect(cc.twistAssist).toBeTrue(); expect(cc.blockToBlock).toBeFalse(); }); it("the ConfigurationSet command (v1-3) should serialize correctly (timed)", () => { const cc = new DoorLockCCConfigurationSet(host, { nodeId: 2, operationType: DoorLockOperationType.Timed, outsideHandlesCanOpenDoorConfiguration: [false, true, true, true], insideHandlesCanOpenDoorConfiguration: [true, false, true, false], lockTimeoutConfiguration: 60 * 15 + 18, }); const expected = buildCCBuffer( Buffer.from([ DoorLockCommand.ConfigurationSet, // CC Command DoorLockOperationType.Timed, 0b1110_0101, 15, 18, ]), ); expect(cc.serialize()).toEqual(expected); }); it("the ConfigurationSet command (v1-3) should serialize correctly (constant)", () => { const cc = new DoorLockCCConfigurationSet(host, { nodeId: 2, operationType: DoorLockOperationType.Constant, outsideHandlesCanOpenDoorConfiguration: [false, true, true, true], insideHandlesCanOpenDoorConfiguration: [true, false, true, false], }); const expected = buildCCBuffer( Buffer.from([ DoorLockCommand.ConfigurationSet, // CC Command DoorLockOperationType.Constant, 0b1110_0101, 0xfe, 0xfe, ]), ); expect(cc.serialize()).toEqual(expected); }); it("the ConfigurationSet command (v4) should serialize correctly", () => { const cc = new DoorLockCCConfigurationSet(host, { nodeId: 2, operationType: DoorLockOperationType.Timed, outsideHandlesCanOpenDoorConfiguration: [false, true, true, true], insideHandlesCanOpenDoorConfiguration: [true, false, true, false], lockTimeoutConfiguration: 60 * 15 + 18, autoRelockTime: 0xfefd, holdAndReleaseTime: undefined, blockToBlock: undefined, twistAssist: true, }); const expected = buildCCBuffer( Buffer.from([ DoorLockCommand.ConfigurationSet, // CC Command DoorLockOperationType.Timed, 0b1110_0101, 15, 18, 0xfe, 0xfd, 0, 0, 0b1, ]), ); expect(cc.serialize()).toEqual(expected); }); it("the CapabilitiesGet command should serialize correctly", () => { const cc = new DoorLockCCCapabilitiesGet(host, { nodeId: 1 }); const expected = buildCCBuffer( Buffer.from([ DoorLockCommand.CapabilitiesGet, // CC Command ]), ); expect(cc.serialize()).toEqual(expected); }); it("the CapabilitiesReport command should be deserialized correctly", () => { const ccData = buildCCBuffer( Buffer.from([ DoorLockCommand.CapabilitiesReport, // CC Command 1, // bit mask length 0b110, // operation types 3, // list length DoorLockMode.Unsecured, DoorLockMode.InsideUnsecured, DoorLockMode.Secured, 0b0000_0000, // handle modes 0b111, // components 0b1010, // feature flags ]), ); const cc = new DoorLockCCCapabilitiesReport(host, { nodeId: 1, data: ccData, }); expect(cc.supportedOperationTypes).toEqual([ DoorLockOperationType.Constant, DoorLockOperationType.Timed, ]); expect(cc.supportedDoorLockModes).toEqual([ DoorLockMode.Unsecured, DoorLockMode.InsideUnsecured, DoorLockMode.Secured, ]); expect(cc.latchSupported).toBeTrue(); expect(cc.boltSupported).toBeTrue(); expect(cc.doorSupported).toBeTrue(); expect(cc.autoRelockSupported).toBeTrue(); expect(cc.holdAndReleaseSupported).toBeFalse(); expect(cc.twistAssistSupported).toBeTrue(); expect(cc.blockToBlockSupported).toBeFalse(); }); // it("the Report command (v2) should be deserialized correctly", () => { // const ccData = buildCCBuffer( // 1, // Buffer.from([ // DoorLockCommand.Report, // CC Command // 55, // current value // 66, // target value // 1, // duration // ]), // ); // const cc = new DoorLockCCReport(host, { data: ccData }); // expect(cc.currentValue).toBe(55); // expect(cc.targetValue).toBe(66); // expect(cc.duration!.unit).toBe("seconds"); // expect(cc.duration!.value).toBe(1); // }); // it("deserializing an unsupported command should return an unspecified version of DoorLockCC", () => { // const serializedCC = buildCCBuffer( // 1, // Buffer.from([255]), // not a valid command // ); // const cc: any = new DoorLockCC(host, { // data: serializedCC, // }); // expect(cc.constructor).toBe(DoorLockCC); // }); // it("the CC values should have the correct metadata", () => { // // Readonly, 0-99 // const currentValueMeta = getCCValueMetadata( // CommandClasses.DoorLock, // "currentValue", // ); // expect(currentValueMeta).toMatchObject({ // readable: true, // writeable: false, // min: 0, // max: 99, // }); // // Writeable, 0-99 // const targetValueMeta = getCCValueMetadata( // CommandClasses.DoorLock, // "targetValue", // ); // expect(targetValueMeta).toMatchObject({ // readable: true, // writeable: true, // min: 0, // max: 99, // }); // }); });