UNPKG

zigbee-herdsman

Version:

An open source ZigBee gateway solution with node.js.

1,277 lines (1,130 loc) 108 kB
import * as Zcl from "../src/zspec/zcl"; import {BuffaloZcl} from "../src/zspec/zcl/buffaloZcl"; import {BuffaloZclDataType, DataType, Direction, FrameType, StructuredIndicatorType} from "../src/zspec/zcl/definition/enums"; describe("Zcl", () => { it("Get cluster by name", () => { const cluster = Zcl.Utils.getCluster("genIdentify", undefined, {}); expect(cluster.ID).toBe(3); expect(cluster.name).toBe("genIdentify"); expect(cluster.commands.identifyQuery.ID).toBe(1); expect(cluster.commands.identifyQuery.name).toBe("identifyQuery"); expect(cluster.commandsResponse.identifyQueryRsp.ID).toBe(0); expect(cluster.commandsResponse.identifyQueryRsp.name).toBe("identifyQueryRsp"); }); it("Get cluster by ID", () => { const cluster1 = Zcl.Utils.getCluster(0, undefined, {}); // @ts-expect-error testing delete cluster1.getAttribute; // @ts-expect-error testing delete cluster1.getCommand; // @ts-expect-error testing delete cluster1.hasAttribute; // @ts-expect-error testing delete cluster1.getCommandResponse; const cluster2 = Zcl.Utils.getCluster("genBasic", undefined, {}); // @ts-expect-error testing delete cluster2.getAttribute; // @ts-expect-error testing delete cluster2.getCommand; // @ts-expect-error testing delete cluster2.hasAttribute; // @ts-expect-error testing delete cluster2.getCommandResponse; expect(cluster1).toStrictEqual(cluster2); }); it("Get cluster attribute by ID", () => { const cluster = Zcl.Utils.getCluster(0, undefined, {}); const attribute = cluster.getAttribute(1); expect(attribute).toStrictEqual({ID: 1, type: DataType.UINT8, name: "appVersion"}); }); it("Cluster has attribute", () => { const cluster = Zcl.Utils.getCluster(0, undefined, {}); expect(cluster.hasAttribute("zclVersion")).toBeTruthy(); expect(cluster.hasAttribute("NOTEXISTING")).toBeFalsy(); expect(cluster.hasAttribute(0)).toBeTruthy(); expect(cluster.hasAttribute(910293)).toBeFalsy(); }); it("Get specific command by name", () => { const cluster = Zcl.Utils.getCluster("genIdentify", undefined, {}); const command = cluster.getCommand("ezmodeInvoke"); expect(command.ID).toBe(2); expect(command.name).toBe("ezmodeInvoke"); }); it("Get global command by name", () => { const command = Zcl.Utils.getGlobalCommand("readRsp"); expect(command.ID).toBe(1); expect(command.name).toBe("readRsp"); }); it("Get global command non existing", () => { expect(() => { Zcl.Utils.getGlobalCommand("nonexisting"); }).toThrow("Global command with key 'nonexisting' does not exist"); }); it("Get cluster by name non-existing", () => { expect(() => { Zcl.Utils.getCluster("notExisting", undefined, {}); }).toThrow("Cluster with name 'notExisting' does not exist"); }); it("Get cluster by id non-existing", () => { expect(JSON.parse(JSON.stringify(Zcl.Utils.getCluster(0x190231, undefined, {})))).toStrictEqual({ ID: 1638961, attributes: {}, name: "1638961", commands: {}, commandsResponse: {}, }); }); it("Get specific command by ID", () => { const cluster = Zcl.Utils.getCluster("genIdentify", undefined, {}); const command = cluster.getCommand(2); expect(command).toStrictEqual(cluster.getCommand("ezmodeInvoke")); }); it("Get specific command by name server to client", () => { const cluster = Zcl.Utils.getCluster("genIdentify", undefined, {}); const command = cluster.getCommandResponse(0); expect(command.ID).toBe(0); expect(command.name).toBe("identifyQueryRsp"); }); it("Get specific command by name non existing", () => { expect(() => { const cluster = Zcl.Utils.getCluster("genIdentify", undefined, {}); cluster.getCommandResponse("nonexisting"); }).toThrow("Cluster 'genIdentify' has no command response 'nonexisting'"); }); it("Get discrete or analog of unkown type", () => { expect(() => { // @ts-expect-error invalid on purpose Zcl.Utils.getDataTypeClass(99999); }).toThrow("Don't know value type for 'undefined'"); }); it("ZclFrame from buffer parse payload with unknown frame type", () => { expect(() => { // @ts-ignore Zcl.Frame.parsePayload({frameControl: {frameType: 9}}, undefined); }).toThrow("Unsupported frameType '9'"); }); it("ZclFrame from buffer report", () => { const buffer = Buffer.from([0x18, 0x4a, 0x0a, 0x55, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genAnalogInput.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: true, frameType: 0, manufacturerSpecific: false, }, undefined, 74, 10, ); const payload = [ { attrData: 0, attrId: 85, dataType: 57, }, ]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); expect(frame.header.isGlobal).toBe(true); expect(frame.header.isSpecific).toBe(false); expect(frame.isCluster("genAnalogInput")).toBe(true); expect(frame.isCommand("report")).toBe(true); }); it("ZclFrame from buffer tradfriArrowSingle", () => { const buffer = Buffer.from([0x05, 0x7c, 0x11, 0x1d, 0x07, 0x00, 0x01, 0x0d, 0x00]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genScenes.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 0, disableDefaultResponse: false, frameType: 1, manufacturerSpecific: true, }, 4476, 29, 7, ); const payload = {value: 256, value2: 13}; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); expect(frame.command.ID).toStrictEqual(7); expect(frame.command.name).toStrictEqual("tradfriArrowSingle"); }); it("ZclFrame from buffer genGroups getMembership", () => { const buffer = Buffer.from([0x11, 0x7c, 0x02, 2, 10, 0, 20, 0]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genGroups.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 0, disableDefaultResponse: true, frameType: 1, manufacturerSpecific: false, }, undefined, 124, 2, ); const payload = {groupcount: 2, grouplist: [10, 20]}; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer genGroups getMembership", () => { const buffer = Buffer.from([0x19, 0x7c, 0x03, 0, 10, 0]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genGroups.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: true, frameType: 1, manufacturerSpecific: false, }, undefined, 124, 3, ); const payload = {groupid: 10, status: 0}; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer occupancy report", () => { const buffer = Buffer.from([24, 169, 10, 0, 0, 24, 1]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.msOccupancySensing.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: true, frameType: 0, manufacturerSpecific: false, }, undefined, 169, 10, ); const payload = [{attrId: 0, dataType: 24, attrData: 1}]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer configReportRsp - short", () => { const buffer = Buffer.from([0x08, 0x01, 0x07, 0x00]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genPowerCfg.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: false, frameType: 0, manufacturerSpecific: false, }, undefined, 1, 7, ); const payload = [{status: 0}]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer configReportRsp - long", () => { const buffer = Buffer.from([0x08, 0x01, 0x07, 0x00, 0x01, 0x34, 0x12, 0x01, 0x01, 0x35, 0x12]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genPowerCfg.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: false, frameType: 0, manufacturerSpecific: false, }, undefined, 1, 7, ); const payload = [ {status: 0, direction: 1, attrId: 0x1234}, {status: 1, direction: 1, attrId: 0x1235}, ]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer configReportRsp (hvacThermostat)", () => { const buffer = Buffer.from([0x18, 0x03, 0x07, 0x00, 0x00, 0x12, 0x00]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.hvacThermostat.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: true, frameType: 0, manufacturerSpecific: false, }, undefined, 3, 7, ); const payload = [{status: 0, direction: 0, attrId: 18}]; expect(frame.payload).toStrictEqual(payload); expect(frame.header).toStrictEqual(header); }); it("ZclFrame from buffer getWeeklyScheduleRsp (hvacThermostat)", () => { const bufferHeat = Buffer.from([ 9, 7, 0, 6, 64, 1, 104, 1, 252, 8, 58, 2, 152, 8, 208, 2, 102, 8, 72, 3, 102, 8, 222, 3, 252, 8, 100, 5, 52, 8, ]); const frameHeat = Zcl.Frame.fromBuffer(Zcl.Clusters.hvacThermostat.ID, Zcl.Header.fromBuffer(bufferHeat)!, bufferHeat, {}); expect(frameHeat.payload).toStrictEqual({ numoftrans: 6, dayofweek: 64, mode: 1, transitions: [ {transitionTime: 360, heatSetpoint: 2300}, {transitionTime: 570, heatSetpoint: 2200}, {transitionTime: 720, heatSetpoint: 2150}, {transitionTime: 840, heatSetpoint: 2150}, {transitionTime: 990, heatSetpoint: 2300}, {transitionTime: 1380, heatSetpoint: 2100}, ], }); const bufferCool = Buffer.from([ 9, 7, 0, 6, 64, 2, 104, 1, 252, 8, 58, 2, 152, 8, 208, 2, 102, 8, 72, 3, 102, 8, 222, 3, 252, 8, 100, 5, 52, 8, ]); const frameCool = Zcl.Frame.fromBuffer(Zcl.Clusters.hvacThermostat.ID, Zcl.Header.fromBuffer(bufferCool)!, bufferCool, {}); expect(frameCool.payload).toStrictEqual({ numoftrans: 6, dayofweek: 64, mode: 2, transitions: [ {transitionTime: 360, coolSetpoint: 2300}, {transitionTime: 570, coolSetpoint: 2200}, {transitionTime: 720, coolSetpoint: 2150}, {transitionTime: 840, coolSetpoint: 2150}, {transitionTime: 990, coolSetpoint: 2300}, {transitionTime: 1380, coolSetpoint: 2100}, ], }); const bufferHeatAndCool = Buffer.from([9, 7, 0, 1, 64, 3, 104, 1, 252, 8, 58, 2]); const frameHeatAndCool = Zcl.Frame.fromBuffer( Zcl.Clusters.hvacThermostat.ID, Zcl.Header.fromBuffer(bufferHeatAndCool)!, bufferHeatAndCool, {}, ); expect(frameHeatAndCool.payload).toStrictEqual({ numoftrans: 1, dayofweek: 64, mode: 3, transitions: [{transitionTime: 360, coolSetpoint: 570, heatSetpoint: 2300}], }); }); it("ZclFrame to buffer setWeeklyScheduleRsp (hvacThermostat)", () => { const payloadHeat = { numoftrans: 6, dayofweek: 64, mode: 1, transitions: [ {transitionTime: 360, heatSetpoint: 23}, {transitionTime: 570, heatSetpoint: 2200}, {transitionTime: 720, heatSetpoint: 2150}, {transitionTime: 840, heatSetpoint: 2150}, {transitionTime: 990, heatSetpoint: 2300}, {transitionTime: 1380, heatSetpoint: 2100}, ], }; const frameHeat = Zcl.Frame.create( FrameType.SPECIFIC, Direction.CLIENT_TO_SERVER, false, undefined, 8, "setWeeklySchedule", 513, payloadHeat, {}, ); expect(frameHeat.toBuffer()).toStrictEqual( Buffer.from([1, 8, 1, 6, 64, 1, 104, 1, 23, 0, 58, 2, 152, 8, 208, 2, 102, 8, 72, 3, 102, 8, 222, 3, 252, 8, 100, 5, 52, 8]), ); const payloadCool = { numoftrans: 6, dayofweek: 64, mode: 2, transitions: [ {transitionTime: 360, coolSetpoint: 2300}, {transitionTime: 570, coolSetpoint: 2200}, {transitionTime: 720, coolSetpoint: 2150}, {transitionTime: 840, coolSetpoint: 2150}, {transitionTime: 990, coolSetpoint: 2300}, {transitionTime: 1380, coolSetpoint: 2100}, ], }; const frameCool = Zcl.Frame.create( FrameType.SPECIFIC, Direction.CLIENT_TO_SERVER, false, undefined, 8, "setWeeklySchedule", 513, payloadCool, {}, ); expect(frameCool.toBuffer()).toStrictEqual( Buffer.from([1, 8, 1, 6, 64, 2, 104, 1, 252, 8, 58, 2, 152, 8, 208, 2, 102, 8, 72, 3, 102, 8, 222, 3, 252, 8, 100, 5, 52, 8]), ); const payloadHeatAndCool = { numoftrans: 6, dayofweek: 64, mode: 2, transitions: [{transitionTime: 360, coolSetpoint: 570, heatSetpoint: 2300}], }; const frameHeatAndCool = Zcl.Frame.create( FrameType.SPECIFIC, Direction.CLIENT_TO_SERVER, false, undefined, 8, "setWeeklySchedule", 513, payloadHeatAndCool, {}, ); expect(frameHeatAndCool.toBuffer()).toStrictEqual(Buffer.from([1, 8, 1, 6, 64, 2, 104, 1, 252, 8, 58, 2])); }); it("ZclFrame from buffer configReportRsp failed", () => { const buffer = Buffer.from([0x08, 0x01, 0x07, 0x02, 0x01, 0x01, 0x01]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genPowerCfg.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: false, frameType: 0, manufacturerSpecific: false, }, undefined, 1, 7, ); const payload = [{status: 2, direction: 1, attrId: 257}]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer defaultRsp", () => { const buffer = Buffer.from([0x18, 0x04, 0x0b, 0x0c, 0x82]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genBasic.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: true, frameType: 0, manufacturerSpecific: false, }, undefined, 4, 11, ); const payload = {cmdId: 12, statusCode: 130}; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); test.each([ [ [ 28, 95, 17, 3, 10, 1, 255, 66, 68, 3, 40, 29, 5, 33, 190, 45, 8, 33, 47, 18, 9, 33, 2, 21, 100, 16, 1, 101, 16, 0, 110, 32, 255, 111, 32, 255, 148, 32, 4, 149, 57, 184, 30, 21, 62, 150, 57, 211, 249, 17, 69, 151, 57, 0, 48, 104, 59, 152, 57, 0, 0, 0, 0, 155, 33, 1, 0, 156, 32, 1, 10, 33, 56, 38, 12, 40, 0, 0, ], [ { attrId: 65281, dataType: 66, attrData: { "3": 29, "5": 11710, "8": 4655, "9": 5378, "10": 9784, "12": 0, "100": 1, "101": 0, "110": 255, "111": 255, "148": 4, "149": 0.14562499523162842, "150": 2335.614013671875, "151": 0.0035429000854492188, "152": 0, "155": 1, "156": 1, }, }, ], ], [ [ 28, 95, 17, 3, 10, 5, 0, 66, 21, 108, 117, 109, 105, 46, 115, 101, 110, 115, 111, 114, 95, 119, 108, 101, 97, 107, 46, 97, 113, 49, 1, 255, 66, 34, 1, 33, 213, 12, 3, 40, 33, 4, 33, 168, 19, 5, 33, 43, 0, 6, 36, 0, 0, 5, 0, 0, 8, 33, 4, 2, 10, 33, 0, 0, 100, 16, 0, ], [ {attrId: 5, dataType: 66, attrData: "lumi.sensor_wleak.aq1"}, {attrId: 65281, dataType: 66, attrData: {"1": 3285, "3": 33, "4": 5032, "5": 43, "6": 327680, "8": 516, "10": 0, "100": 0}}, ], ], ])("ZclFrame from buffer xiaomiStruct", (data, payload) => { const buffer = Buffer.from(data); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genBasic.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: true, frameType: 0, manufacturerSpecific: true, }, 4447, 3, 10, ); expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer struct", () => { const buffer = Buffer.from([28, 52, 18, 194, 10, 2, 255, 76, 6, 0, 16, 1, 33, 206, 11, 33, 168, 67, 36, 1, 0, 0, 0, 0, 33, 48, 2, 32, 86]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genBasic.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: true, frameType: 0, manufacturerSpecific: true, }, 4660, 194, 10, ); const payload = [ { attrId: 65282, dataType: 76, numElms: 6, structElms: [ {elmType: 16, elmVal: 1}, {elmType: 33, elmVal: 3022}, {elmType: 33, elmVal: 17320}, {elmType: 36, elmVal: 1}, {elmType: 33, elmVal: 560}, {elmType: 32, elmVal: 86}, ], attrData: [ {elmType: 16, elmVal: 1}, {elmType: 33, elmVal: 3022}, {elmType: 33, elmVal: 17320}, {elmType: 36, elmVal: 1}, {elmType: 33, elmVal: 560}, {elmType: 32, elmVal: 86}, ], }, ]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer discoverRsp", () => { const buffer = Buffer.from([24, 23, 13, 0, 32, 0, 32, 33, 0, 32, 49, 0, 48, 51, 0, 32, 53, 0, 24]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genPowerCfg.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: true, frameType: 0, manufacturerSpecific: false, }, undefined, 23, 13, ); const payload = { discComplete: 0, attrInfos: [ {attrId: 32, dataType: 32}, {attrId: 33, dataType: 32}, {attrId: 49, dataType: 48}, {attrId: 51, dataType: 32}, {attrId: 53, dataType: 24}, ], }; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); expect(frame.cluster.name).toEqual("genPowerCfg"); expect(frame.command.name).toEqual("discoverRsp"); }); it("ZclFrame from buffer error on malformed", () => { const buffer = Buffer.from([0x08, 0x01]); expect(() => { Zcl.Frame.fromBuffer(Zcl.Clusters.genPowerCfg.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); }).toThrow("Invalid ZclHeader"); }); it("ZclFrame from buffer readRsp failed", () => { const buffer = Buffer.from([8, 1, 1, 1, 0, 2]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genBasic.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: false, frameType: 0, manufacturerSpecific: false, }, undefined, 1, 1, ); const payload = [{status: 2, attrId: 1}]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer readRsp success", () => { const buffer = Buffer.from([8, 1, 1, 1, 0, 0, 32, 3]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genBasic.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: false, frameType: 0, manufacturerSpecific: false, }, undefined, 1, 1, ); const payload = [{status: Zcl.Status.SUCCESS, attrId: 1, dataType: Zcl.DataType.UINT8, attrData: 3}]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer GPD commission", () => { const buffer = Buffer.from([ 0x11, 0x00, 0x04, 0x00, 0x00, 0xfe, 0xf4, 0x46, 0x00, 0xf9, 0x00, 0x00, 0x00, 0xe0, 0x1b, 0x02, 0x81, 0xf2, 0xf1, 0xec, 0x92, 0xab, 0xff, 0x8f, 0x13, 0x63, 0xe1, 0x46, 0xbe, 0xb5, 0x18, 0xc9, 0x0c, 0xab, 0xa4, 0x46, 0xd4, 0xd5, 0xf9, 0x01, 0x00, 0x00, ]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.greenPower.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 0, disableDefaultResponse: true, frameType: 1, manufacturerSpecific: false, }, undefined, 0, 4, ); const payload = { options: 0, srcID: 4650238, frameCounter: 249, commandID: 224, payloadSize: 27, commandFrame: { deviceID: 2, options: 129, extendedOptions: 242, gpdClientClusters: Buffer.alloc(0), gpdServerClusters: Buffer.alloc(0), manufacturerID: 0, modelID: 0, numClientClusters: 0, numServerClusters: 0, securityKey: Buffer.from([0xf1, 0xec, 0x92, 0xab, 0xff, 0x8f, 0x13, 0x63, 0xe1, 0x46, 0xbe, 0xb5, 0x18, 0xc9, 0x0c, 0xab]), keyMic: 3587458724, outgoingCounter: 505, applicationInfo: 0, numGpdCommands: 0, gpdCommandIdList: Buffer.alloc(0), genericSwitchConfig: 0, currentContactStatus: 0, }, }; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer GPD scene 0", () => { const buffer = Buffer.from([0x11, 0x00, 0x00, 0xa0, 0x14, 0xfe, 0xf4, 0x46, 0x00, 0xe5, 0x04, 0x00, 0x00, 0x10, 0xff]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.greenPower.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 0, disableDefaultResponse: true, frameType: 1, manufacturerSpecific: false, }, undefined, 0, 0, ); const payload = { srcID: 4650238, commandFrame: {}, commandID: 16, frameCounter: 1253, options: 5280, payloadSize: 255, }; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer GPD with extra data", () => { const buffer = Buffer.from([0x11, 0x00, 0x00, 0xa0, 0x14, 0xfe, 0xf4, 0x46, 0x00, 0xe5, 0x04, 0x00, 0x00, 0x10, 0xff, 0x01]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.greenPower.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 0, disableDefaultResponse: true, frameType: 1, manufacturerSpecific: false, }, undefined, 0, 0, ); const payload = { srcID: 4650238, commandFrame: {raw: Buffer.from([1])}, commandID: 16, frameCounter: 1253, options: 5280, payloadSize: 255, }; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer GPD pairing", () => { const buffer = Buffer.from([ 0x19, 0x17, 0x01, 0x68, 0xe5, 0x00, 0xf8, 0x71, 0x71, 0x01, 0x47, 0x65, 0xa1, 0x1c, 0x00, 0x4b, 0x12, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x12, 0x00, 0x00, 0x09, 0x3c, 0xed, 0x1d, 0xbf, 0x25, 0x63, 0xf9, 0x29, 0x5c, 0x0d, 0x3d, 0x9f, 0xc5, 0x76, 0xe1, 0, 0, 0, 0, 0, 0, ]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.greenPower.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: true, frameType: 1, manufacturerSpecific: false, }, undefined, 23, 1, ); const payload = { options: 0x00e568, srcID: 0x017171f8, sinkIEEEAddr: "0x00124b001ca16547", sinkNwkAddr: 0, deviceID: 2, frameCounter: 4636, gpdKey: Buffer.from([0x09, 0x3c, 0xed, 0x1d, 0xbf, 0x25, 0x63, 0xf9, 0x29, 0x5c, 0x0d, 0x3d, 0x9f, 0xc5, 0x76, 0xe1]), }; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer readRsp alias type", () => { const buffer = Buffer.from([8, 1, 1, 1, 0, 0, 8, 3]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genBasic.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: false, frameType: 0, manufacturerSpecific: false, }, undefined, 1, 1, ); const payload = [{status: Zcl.Status.SUCCESS, attrId: 1, dataType: Zcl.DataType.DATA8, attrData: 3}]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer configReportRsp server to client", () => { const buffer = Buffer.from([8, 1, 6, 1, 1, 0, 10, 10]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genBasic.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: false, frameType: 0, manufacturerSpecific: false, }, undefined, 1, 6, ); const payload = [{attrId: 1, direction: 1, timeout: 2570}]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer configReportRsp client to server analog", () => { const buffer = Buffer.from([8, 1, 6, 0, 0, 1, 32, 1, 0, 10, 0, 20]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genBasic.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: false, frameType: 0, manufacturerSpecific: false, }, undefined, 1, 6, ); const payload = [{attrId: 256, dataType: 32, direction: 0, maxRepIntval: 10, minRepIntval: 1, repChange: 20}]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer configReportRsp client to server analog", () => { const buffer = Buffer.from([8, 1, 6, 0, 0, 1, 8, 1, 0, 10, 0]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genBasic.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: false, frameType: 0, manufacturerSpecific: false, }, undefined, 1, 6, ); const payload = [{attrId: 256, dataType: 8, direction: 0, maxRepIntval: 10, minRepIntval: 1}]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer readRsp", () => { const buffer = Buffer.from([ 24, 7, 1, 5, 0, 0, 66, 30, 84, 82, 65, 68, 70, 82, 73, 32, 98, 117, 108, 98, 32, 69, 50, 55, 32, 87, 83, 32, 111, 112, 97, 108, 32, 57, 56, 48, 108, 109, 6, 0, 0, 66, 8, 50, 48, 49, 55, 48, 51, 51, 49, 7, 0, 0, 48, 1, 10, 0, 0, 65, 15, 76, 69, 68, 49, 53, 52, 53, 71, 49, 50, 69, 50, 55, 69, 85, ]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genBasic.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: 1, disableDefaultResponse: true, frameType: 0, manufacturerSpecific: false, }, undefined, 7, 1, ); const payload = [ {attrId: 5, status: 0, dataType: 66, attrData: "TRADFRI bulb E27 WS opal 980lm"}, {attrId: 6, status: 0, dataType: 66, attrData: "20170331"}, {attrId: 7, status: 0, dataType: 48, attrData: 1}, {attrId: 10, status: 0, dataType: 65, attrData: Buffer.from([76, 69, 68, 49, 53, 52, 53, 71, 49, 50, 69, 50, 55, 69, 85])}, ]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame with Assa (manufacturer specific) cluster create", () => { const payload = [{attrId: 0x0012, status: 0, attrData: 1, dataType: 32}]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.CLIENT_TO_SERVER, false, 0x101d, 8, "readRsp", 0xfc00, payload, {}); expect(frame.cluster.name).toBe("manuSpecificAssaDoorLock"); }); it("ZclFrame with Assa (manufacturer specific) cluster create with non Assamanufcode", () => { const payload = [{attrId: 0x0012, status: 0, attrData: 1, dataType: 32}]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.CLIENT_TO_SERVER, false, 0x10f3, 8, "readRsp", 0xfc00, payload, {}); expect(frame.cluster.name).toBe("manuSpecificAssaDoorLock"); }); it("ZclFrame with Assa (manufacturer specific) cluster fromBuffer", () => { const buffer = Buffer.from([0x04, 0xf2, 0x10, 0x08, 0x01, 0x00, 0x00, 0x00, 0x20, 0x01]); const frame = Zcl.Frame.fromBuffer(0xfc00, Zcl.Header.fromBuffer(buffer)!, buffer, {}); expect(frame.cluster.name).toBe("manuSpecificAssaDoorLock"); }); it("ZclFrame to buffer with reservered bits", () => { const expected = Buffer.from([224, 8, 12, 0, 0, 240]); const payload = {startAttrId: 0, maxAttrIds: 240}; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.CLIENT_TO_SERVER, false, undefined, 8, "discover", 0, payload, {}, 7); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame from buffer with reservered bits", () => { const buffer = Buffer.from([224, 8, 12, 0, 0, 240]); const frame = Zcl.Frame.fromBuffer(0, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 7, direction: 0, disableDefaultResponse: false, frameType: 0, manufacturerSpecific: false, }, undefined, 8, 12, ); const payload = {startAttrId: 0, maxAttrIds: 240}; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame to buffer discover", () => { const expected = Buffer.from([0, 8, 12, 0, 0, 240]); const payload = {startAttrId: 0, maxAttrIds: 240}; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.CLIENT_TO_SERVER, false, undefined, 8, "discover", 0, payload, {}); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer queryNextImageResponse with non zero status", () => { const expected = Buffer.from([9, 8, 2, 1]); const payload = {status: 1}; const frame = Zcl.Frame.create( FrameType.SPECIFIC, Direction.SERVER_TO_CLIENT, false, undefined, 8, "queryNextImageResponse", 25, payload, {}, ); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer queryNextImageResponse with zero status", () => { const expected = Buffer.from([9, 8, 2, 0, 1, 0, 3, 0, 5, 0, 0, 0, 6, 0, 0, 0]); const payload = {status: 0, manufacturerCode: 1, imageType: 3, fileVersion: 5, imageSize: 6}; const frame = Zcl.Frame.create( FrameType.SPECIFIC, Direction.SERVER_TO_CLIENT, false, undefined, 8, "queryNextImageResponse", 25, payload, {}, ); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer queryNextImageResponse with zero status and missing parameters", () => { const payload = {status: 0}; const frame = Zcl.Frame.create( FrameType.SPECIFIC, Direction.SERVER_TO_CLIENT, false, undefined, 8, "queryNextImageResponse", 25, payload, {}, ); let error; try { frame.toBuffer(); } catch (e) { error = e; } expect(error).toStrictEqual(new Error(`Parameter 'manufacturerCode' is missing`)); }); it("ZclFrame to buffer readRsp UTC", () => { const expected = Buffer.from([24, 74, 1, 0, 0, 0, 226, 234, 83, 218, 36]); const payload = [{attrId: 0, status: 0, attrData: 618288106, dataType: 226}]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.SERVER_TO_CLIENT, true, undefined, 74, "readRsp", 0, payload, {}); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer write Livolo malformed", () => { // Created as example for https://github.com/Koenkk/zigbee-herdsman/issues/127 const expectedOn = Buffer.from([0x1c, 0xd2, 0x1a, 0xe9, 0x02, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); const payloadOn = [{attrId: 1, attrData: Buffer.from([1, 0, 0, 0, 0, 0, 0, 0]), dataType: 1}]; const frameOn = Zcl.Frame.create(FrameType.GLOBAL, Direction.SERVER_TO_CLIENT, true, 0x1ad2, 233, "write", 0, payloadOn, {}); expect(frameOn.toBuffer()).toStrictEqual(expectedOn); const expectedOff = Buffer.from([0x1c, 0xd2, 0x1a, 0xe9, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); const payloadOff = [{attrId: 1, attrData: Buffer.from([0, 0, 0, 0, 0, 0, 0, 0]), dataType: 1}]; const frameOff = Zcl.Frame.create(FrameType.GLOBAL, Direction.SERVER_TO_CLIENT, true, 0x1ad2, 233, "write", 0, payloadOff, {}); expect(frameOff.toBuffer()).toStrictEqual(expectedOff); }); it("ZclFrame write request with string as bytes array", () => { const payload = [{attrId: 0x0401, attrData: [0x07, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x14], dataType: 0x42}]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.CLIENT_TO_SERVER, true, 0x115f, 15, "write", 0, payload, {}); const expected = [0x14, 0x5f, 0x11, 0x0f, 0x02, 0x01, 0x04, 0x42, 0x07, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x14]; expect(Buffer.from(expected)).toStrictEqual(frame.toBuffer()); }); it("ZclFrame write rsp", () => { const payload = [{status: 0x11, attrId: 0x22}]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.CLIENT_TO_SERVER, true, 0x115f, 15, "writeRsp", 0, payload, {}); const buffer = frame.toBuffer(); const expected = [0x14, 0x5f, 0x11, 0x0f, 0x04, 0x11, 0x22, 0x00]; expect(Buffer.from(expected)).toStrictEqual(buffer); }); //{ frameType: 0, manufSpec: 0, direction: 0, disDefaultRsp: 0 } 0 8 'discover' { startAttrId: 0, maxAttrIds: 240 } it("ZclFrame to buffer readRsp success", () => { const expected = Buffer.from([8, 1, 1, 1, 0, 0, 32, 3]); const payload = [{status: Zcl.Status.SUCCESS, attrId: 1, dataType: Zcl.DataType.UINT8, attrData: 3}]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.SERVER_TO_CLIENT, false, undefined, 1, 1, 0, payload, {}); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer defaultRsp success", () => { const expected = Buffer.from([0x18, 0x04, 0x0b, 0x0c, 0x82]); const payload = {cmdId: 12, statusCode: 130}; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.SERVER_TO_CLIENT, true, undefined, 4, 11, 0, payload, {}); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer readStructured single element", () => { const expected = Buffer.from([0x18, 0x02, 0x0e, 0x01, 0x00, 0x01, 0x02, 0x00]); const payload = [{attrId: 0x0001, selector: {indexes: [2]}}]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.SERVER_TO_CLIENT, true, undefined, 2, 0x0e, Zcl.Clusters.genBasic.ID, payload, {}); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer readStructured multiple elements", () => { const expected = Buffer.from([ 0x18, 0x02, 0x0e, 0x02, 0x00, 0x02, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, ]); const payload = [ {attrId: 0x0002, selector: {indexes: [3, 4]}}, {attrId: 0x0005, selector: {indexes: [6, 7, 8]}}, ]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.SERVER_TO_CLIENT, true, undefined, 2, 0x0e, Zcl.Clusters.genBasic.ID, payload, {}); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer readStructured whole attribute", () => { const expected = Buffer.from([0x18, 0x02, 0x0e, 0x09, 0x00, 0x00]); const payload = [{attrId: 0x0009, selector: {}}]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.SERVER_TO_CLIENT, true, undefined, 2, 0x0e, Zcl.Clusters.genBasic.ID, payload, {}); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame from buffer readStructured single elements", () => { const buffer = Buffer.from([0x18, 0x02, 0x0e, 0x01, 0x00, 0x01, 0x02, 0x00]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genBasic.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: Direction.SERVER_TO_CLIENT, disableDefaultResponse: true, frameType: FrameType.GLOBAL, manufacturerSpecific: false, }, undefined, 2, 0x0e, ); const payload = [{attrId: 0x0001, selector: {indexes: [2]}}]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer readStructured multiple elements", () => { const buffer = Buffer.from([ 0x18, 0x02, 0x0e, 0x02, 0x00, 0x02, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x03, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, ]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genBasic.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: Direction.SERVER_TO_CLIENT, disableDefaultResponse: true, frameType: FrameType.GLOBAL, manufacturerSpecific: false, }, undefined, 2, 0x0e, ); const payload = [ {attrId: 0x0002, selector: {indexes: [3, 4]}}, {attrId: 0x0005, selector: {indexes: [6, 7, 8]}}, ]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame from buffer readStructured whole attribute", () => { const buffer = Buffer.from([0x18, 0x02, 0x0e, 0x09, 0x00, 0x00]); const frame = Zcl.Frame.fromBuffer(Zcl.Clusters.genBasic.ID, Zcl.Header.fromBuffer(buffer)!, buffer, {}); const header = new Zcl.Header( { reservedBits: 0, direction: Direction.SERVER_TO_CLIENT, disableDefaultResponse: true, frameType: FrameType.GLOBAL, manufacturerSpecific: false, }, undefined, 2, 0x0e, ); const payload = [{attrId: 0x0009, selector: {indicatorType: StructuredIndicatorType.Whole}}]; expect(frame.header).toStrictEqual(header); expect(frame.payload).toStrictEqual(payload); }); it("ZclFrame to buffer writeStructured single element", () => { const expected = Buffer.from([0x10, 0x02, 0x0f, 0x01, 0x00, 0x01, 0x02, 0x00, 0x20, 0x03]); const payload = [{attrId: 0x0001, selector: {indexes: [2]}, dataType: Zcl.DataType.UINT8, elementData: 3}]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.CLIENT_TO_SERVER, true, undefined, 2, 0x0f, Zcl.Clusters.genBasic.ID, payload, {}); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer writeStructured multiple elements", () => { const expected = Buffer.from([ 0x10, 0x02, 0x0f, 0x02, 0x00, 0x02, 0x03, 0x00, 0x04, 0x00, 0x42, 0x03, 0x66, 0x6f, 0x6f, 0x05, 0x00, 0x03, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x42, 0x03, 0x62, 0x61, 0x72, ]); const payload = [ {attrId: 0x0002, selector: {indexes: [3, 4]}, dataType: Zcl.DataType.CHAR_STR, elementData: "foo"}, {attrId: 0x0005, selector: {indexes: [6, 7, 8]}, dataType: Zcl.DataType.CHAR_STR, elementData: "bar"}, ]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.CLIENT_TO_SERVER, true, undefined, 2, 0x0f, Zcl.Clusters.genBasic.ID, payload, {}); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer writeStructured whole attribute", () => { const expected = Buffer.from([0x10, 0x02, 0x0f, 0x09, 0x00, 0x00, 0x48, 0x20, 0x03, 0x00, 0x0a, 0x0b, 0x0c]); const payload = [ {attrId: 0x0009, selector: {}, dataType: Zcl.DataType.ARRAY, elementData: {elementType: Zcl.DataType.UINT8, elements: [10, 11, 12]}}, ]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.CLIENT_TO_SERVER, true, undefined, 2, 0x0f, Zcl.Clusters.genBasic.ID, payload, {}); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer writeStructured add element into set/bag", () => { const expected = Buffer.from([0x10, 0x02, 0x0f, 0x0d, 0x00, 0x10, 0x42, 0x03, 0x66, 0x6f, 0x6f]); const payload = [ {attrId: 0x000d, selector: {indicatorType: StructuredIndicatorType.WriteAdd}, dataType: Zcl.DataType.CHAR_STR, elementData: "foo"}, ]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.CLIENT_TO_SERVER, true, undefined, 2, 0x0f, Zcl.Clusters.genBasic.ID, payload, {}); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer writeStructured remove element from set/bag", () => { const expected = Buffer.from([0x10, 0x02, 0x0f, 0x0e, 0x00, 0x20, 0x42, 0x03, 0x62, 0x61, 0x72]); const payload = [ {attrId: 0x000e, selector: {indicatorType: StructuredIndicatorType.WriteRemove}, dataType: Zcl.DataType.CHAR_STR, elementData: "bar"}, ]; const frame = Zcl.Frame.create(FrameType.GLOBAL, Direction.CLIENT_TO_SERVER, true, undefined, 2, 0x0f, Zcl.Clusters.genBasic.ID, payload, {}); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer writeStructured Livolo malformed", () => { const expected = Buffer.from([0x7c, 0xd2, 0x1a, 0xe9, 0x0f, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); const payload = [{attrId: 0x0000, selector: null, elementData: [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]}]; const frame = Zcl.Frame.create( FrameType.GLOBAL, Direction.SERVER_TO_CLIENT, true, 0x1ad2, 0xe9, 0x0f, Zcl.Clusters.genBasic.ID, payload, {}, 3, ); expect(frame.toBuffer()).toStrictEqual(expected); }); it("ZclFrame to buffer writeStructuredRsp success", () => { co