zigbee-herdsman
Version:
An open source ZigBee gateway solution with node.js.
1,277 lines (1,130 loc) • 108 kB
text/typescript
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