zigbee2mqtt/test/stub/zigbeeHerdsman.js
Ivan F. Martinez 17ac9cf8e7
feat: Add throttle option for devices (#24122)
* basic spam control

* used npm run pretty:write

* add test for SPAMMER description to comply with 100% coverage test

* define friendly name to spammer test devices

* Update README.md

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>

* trying now with throttleit library

* lint corrections

* last lint request

* correct await / async definiction

* remove description support

* change first command to be executed

---------

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
2024-10-02 21:15:15 +02:00

924 lines
27 KiB
JavaScript

const events = {};
const assert = require('assert');
function getKeyByValue(object, value, fallback) {
const key = Object.keys(object).find((k) => object[k] === value);
return key != null ? key : fallback;
}
class Group {
constructor(groupID, members) {
this.groupID = groupID;
this.command = jest.fn();
this.meta = {};
this.members = members;
this.removeFromDatabase = jest.fn();
this.removeFromNetwork = jest.fn();
this.hasMember = (endpoint) => this.members.includes(endpoint);
}
}
const clusters = {
genBasic: 0,
genOta: 25,
genScenes: 5,
genOnOff: 6,
genLevelCtrl: 8,
lightingColorCtrl: 768,
closuresWindowCovering: 258,
hvacThermostat: 513,
msIlluminanceMeasurement: 1024,
msTemperatureMeasurement: 1026,
msRelativeHumidity: 1029,
msSoilMoisture: 1032,
msCO2: 1037,
};
const custom_clusters = {
custom_1: {
ID: 64672,
manufacturerCode: 4617,
attributes: {
attribute_0: {ID: 0, type: 49},
},
commands: {
command_0: {ID: 0, response: 0, parameters: [{name: 'reset', type: 40}]},
},
commandsResponse: {},
},
};
const customClusterBTHRA = {
custom_1: {
ID: 513,
attributes: {
attribute_0: {ID: 16391, type: 48, manufacturerCode: 4617},
attribute_1: {ID: 16416, type: 48, manufacturerCode: 4617},
attribute_2: {ID: 16418, type: 48, manufacturerCode: 4617},
attribute_3: {ID: 16448, type: 41, manufacturerCode: 4617},
attribute_4: {ID: 16450, type: 48, manufacturerCode: 4617},
attribute_5: {ID: 16451, type: 48, manufacturerCode: 4617},
},
commands: {},
commandsResponse: {},
},
custom_2: {
ID: 516,
attributes: {
attribute_0: {ID: 16395, type: 32, manufacturerCode: 4617},
attribute_1: {ID: 16441, type: 48, manufacturerCode: 4617},
attribute_2: {ID: 16442, type: 48, manufacturerCode: 4617},
attribute_3: {ID: 16443, type: 48, manufacturerCode: 4617},
},
commands: {},
commandsResponse: {},
},
};
class Endpoint {
constructor(
ID,
inputClusters,
outputClusters,
deviceIeeeAddress,
binds = [],
clusterValues = {},
configuredReportings = [],
profileID = null,
deviceID = null,
meta = {},
) {
this.deviceIeeeAddress = deviceIeeeAddress;
this.clusterValues = clusterValues;
this.ID = ID;
this.inputClusters = inputClusters;
this.outputClusters = outputClusters;
this.command = jest.fn();
this.commandResponse = jest.fn();
this.read = jest.fn();
this.write = jest.fn();
this.bind = jest.fn();
this.unbind = jest.fn();
this.save = jest.fn();
this.configureReporting = jest.fn();
this.meta = meta;
this.binds = binds;
this.profileID = profileID;
this.deviceID = deviceID;
this.configuredReportings = configuredReportings;
this.getInputClusters = () =>
inputClusters
.map((c) => {
return {ID: c, name: getKeyByValue(clusters, c)};
})
.filter((c) => c.name);
this.getOutputClusters = () =>
outputClusters
.map((c) => {
return {ID: c, name: getKeyByValue(clusters, c)};
})
.filter((c) => c.name);
this.supportsInputCluster = (cluster) => {
assert(clusters[cluster] !== undefined, `Undefined '${cluster}'`);
return this.inputClusters.includes(clusters[cluster]);
};
this.supportsOutputCluster = (cluster) => {
assert(clusters[cluster], `Undefined '${cluster}'`);
return this.outputClusters.includes(clusters[cluster]);
};
this.addToGroup = jest.fn();
this.addToGroup.mockImplementation((group) => {
if (!group.members.includes(this)) group.members.push(this);
});
this.getDevice = () => {
return Object.values(devices).find((d) => d.ieeeAddr === deviceIeeeAddress);
};
this.removeFromGroup = jest.fn();
this.removeFromGroup.mockImplementation((group) => {
const index = group.members.indexOf(this);
if (index != -1) {
group.members.splice(index, 1);
}
});
this.removeFromAllGroups = () => {
Object.values(groups).forEach((g) => this.removeFromGroup(g));
};
this.getClusterAttributeValue = jest.fn();
this.getClusterAttributeValue.mockImplementation((cluster, value) => {
if (!(cluster in this.clusterValues)) return undefined;
return this.clusterValues[cluster][value];
});
}
}
class Device {
constructor(
type,
ieeeAddr,
networkAddress,
manufacturerID,
endpoints,
interviewCompleted,
powerSource = null,
modelID = null,
interviewing = false,
manufacturerName,
dateCode = null,
softwareBuildID = null,
customClusters = {},
) {
this.type = type;
this.ieeeAddr = ieeeAddr;
this.dateCode = dateCode;
this.networkAddress = networkAddress;
this.manufacturerID = manufacturerID;
this.endpoints = endpoints;
this.powerSource = powerSource;
this.softwareBuildID = softwareBuildID;
this.interviewCompleted = interviewCompleted;
this.modelID = modelID;
this.interview = jest.fn();
this.interviewing = interviewing;
this.meta = {};
this.ping = jest.fn();
this.removeFromNetwork = jest.fn();
this.removeFromDatabase = jest.fn();
this.customClusters = customClusters;
this.addCustomCluster = jest.fn();
this.save = jest.fn();
this.manufacturerName = manufacturerName;
this.lastSeen = 1000;
}
getEndpoint(ID) {
return this.endpoints.find((e) => e.ID === ID);
}
}
const returnDevices = [];
const bulb_color = new Device(
'Router',
'0x000b57fffec6a5b3',
40399,
4107,
[
new Endpoint(1, [0, 3, 4, 5, 6, 8, 768, 2821, 4096], [5, 25, 32, 4096], '0x000b57fffec6a5b3', [], {
lightingColorCtrl: {colorCapabilities: 254},
}),
],
true,
'Mains (single phase)',
'LLC020',
);
const bulb_color_2 = new Device(
'Router',
'0x000b57fffec6a5b4',
401292,
4107,
[
new Endpoint(
1,
[0, 3, 4, 5, 6, 8, 768, 2821, 4096],
[5, 25, 32, 4096],
'0x000b57fffec6a5b4',
[],
{lightingColorCtrl: {colorCapabilities: 254}},
[],
null,
null,
{scenes: {'1_0': {name: 'Chill scene', state: {state: 'ON'}}, '4_9': {state: {state: 'OFF'}}}},
),
],
true,
'Mains (single phase)',
'LLC020',
false,
'Philips',
'2019.09',
'5.127.1.26581',
);
const bulb_2 = new Device(
'Router',
'0x000b57fffec6a5b7',
40369,
4476,
[new Endpoint(1, [0, 3, 4, 5, 6, 8, 768, 2821, 4096], [5, 25, 32, 4096], '0x000b57fffec6a5b7', [], {lightingColorCtrl: {colorCapabilities: 17}})],
true,
'Mains (single phase)',
'TRADFRI bulb E27 WS opal 980lm',
);
const TS0601_thermostat = new Device(
'EndDevice',
'0x0017882104a44559',
6544,
4151,
[new Endpoint(1, [], [], '0x0017882104a44559')],
true,
'Mains (single phase)',
'kud7u2l',
);
const TS0601_switch = new Device(
'EndDevice',
'0x0017882104a44560',
6544,
4151,
[new Endpoint(1, [], [], '0x0017882104a44560')],
true,
'Mains (single phase)',
'kjintbl',
);
const TS0601_cover_switch = new Device(
'EndDevice',
'0x0017882104a44562',
6544,
4151,
[new Endpoint(1, [], [], '0x0017882104a44562')],
true,
'Mains (single phase)',
'TS0601',
false,
'_TZE200_5nldle7w',
);
const ZNCZ02LM = new Device(
'Router',
'0x0017880104e45524',
6540,
4151,
[new Endpoint(1, [0, 6], [], '0x0017880104e45524')],
true,
'Mains (single phase)',
'lumi.plug',
);
const GLEDOPTO_2ID = new Device(
'Router',
'0x0017880104e45724',
6540,
4151,
[
new Endpoint(11, [0, 3, 4, 5, 6, 8, 768], [], '0x0017880104e45724', [], {}, [], 49246, 528),
new Endpoint(12, [0, 3, 4, 5, 6, 8, 768], [], '0x0017880104e45724', [], {}, [], 260, 258),
new Endpoint(13, [4096], [4096], '0x0017880104e45724', [], {}, [], 49246, 57694),
new Endpoint(15, [0, 3, 4, 5, 6, 8, 768], [], '0x0017880104e45724', [], {}, [], 49246, 256),
],
true,
'Mains (single phase)',
'GL-C-007',
false,
'GLEDOPTO',
);
const QBKG03LM = new Device(
'Router',
'0x0017880104e45542',
6540,
4151,
[
new Endpoint(1, [0], [], '0x0017880104e45542'),
new Endpoint(2, [0, 6], [], '0x0017880104e45542'),
new Endpoint(3, [0, 6], [], '0x0017880104e45542'),
],
true,
'Mains (single phase)',
'lumi.ctrl_neutral2',
);
const zigfred_plus = new Device(
'Router',
'0xf4ce368a38be56a1',
6589,
0x129c,
[
new Endpoint(5, [0, 3, 4, 5, 6, 8, 0x0300, 0xfc42], [0xfc42], '0xf4ce368a38be56a1'),
new Endpoint(7, [0, 3, 4, 5, 6, 8], [], '0xf4ce368a38be56a1'),
new Endpoint(8, [0, 3, 4, 5, 6, 8], [], '0xf4ce368a38be56a1'),
new Endpoint(9, [0, 3, 4, 5, 6, 8], [], '0xf4ce368a38be56a1'),
new Endpoint(10, [0, 3, 4, 5, 6, 8], [], '0xf4ce368a38be56a1'),
new Endpoint(11, [0, 3, 4, 5, 0x0102], [], '0xf4ce368a38be56a1'),
new Endpoint(12, [0, 3, 4, 5, 0x0102], [], '0xf4ce368a38be56a1'),
],
true,
'Mains (single phase)',
'zigfred plus',
false,
'Siglis',
);
const groups = {
group_1: new Group(1, []),
group_tradfri_remote: new Group(15071, [bulb_color_2.endpoints[0], bulb_2.endpoints[0]]),
'group/with/slashes': new Group(99, []),
group_with_tradfri: new Group(11, [bulb_2.endpoints[0]]),
thermostat_group: new Group(12, [TS0601_thermostat.endpoints[0]]),
group_with_switch: new Group(14, [ZNCZ02LM.endpoints[0], bulb_2.endpoints[0]]),
gledopto_group: new Group(21, [GLEDOPTO_2ID.endpoints[3]]),
default_bind_group: new Group(901, []),
ha_discovery_group: new Group(9, [bulb_color_2.endpoints[0], bulb_2.endpoints[0], QBKG03LM.endpoints[1]]),
};
const devices = {
coordinator: new Device('Coordinator', '0x00124b00120144ae', 0, 0, [new Endpoint(1, [], [], '0x00124b00120144ae')], false),
bulb: new Device(
'Router',
'0x000b57fffec6a5b2',
40369,
4476,
[
new Endpoint(
1,
[0, 3, 4, 5, 6, 8, 768, 2821, 4096],
[5, 25, 32, 4096],
'0x000b57fffec6a5b2',
[],
{lightingColorCtrl: {colorCapabilities: 17}},
[
{
cluster: {name: 'genOnOff'},
attribute: {name: 'onOff'},
minimumReportInterval: 1,
maximumReportInterval: 10,
reportableChange: 20,
},
],
),
],
true,
'Mains (single phase)',
'TRADFRI bulb E27 WS opal 980lm',
),
'RBSH-TRV0-ZB-EU': new Device(
'EndDevice',
'0x18fc2600000d7ae2',
35902,
4617, // 0x1209,
[new Endpoint(1, [0, 1, 3, 4, 32, 513, 516, 2821], [10, 25], '0x18fc2600000d7ae2')],
true,
'Battery',
'RBSH-TRV0-ZB-EU',
false,
'BOSCH',
'20231122',
'3.05.09',
customClusterBTHRA,
),
bulb_color: bulb_color,
bulb_2: bulb_2,
bulb_color_2: bulb_color_2,
remote: new Device(
'EndDevice',
'0x0017880104e45517',
6535,
4107,
[
new Endpoint(1, [0], [0, 3, 4, 6, 8, 5], '0x0017880104e45517', [
{target: bulb_color.endpoints[0], cluster: {ID: 8, name: 'genLevelCtrl'}},
{target: bulb_color.endpoints[0], cluster: {ID: 6, name: 'genOnOff'}},
{target: bulb_color.endpoints[0], cluster: {ID: 768, name: 'lightingColorCtrl'}},
{target: groups.group_1, cluster: {ID: 6, name: 'genOnOff'}},
{target: groups.group_1, cluster: {ID: 6, name: 'genLevelCtrl'}},
]),
new Endpoint(2, [0, 1, 3, 15, 64512], [25, 6]),
],
true,
'Battery',
'RWL021',
),
unsupported: new Device(
'EndDevice',
'0x0017880104e45518',
6536,
0,
[new Endpoint(1, [0], [0, 3, 4, 6, 8, 5])],
true,
'Battery',
'notSupportedModelID',
false,
'notSupportedMfg',
),
unsupported2: new Device(
'EndDevice',
'0x0017880104e45529',
6536,
0,
[new Endpoint(1, [0], [0, 3, 4, 6, 8, 5])],
true,
'Battery',
'notSupportedModelID',
),
interviewing: new Device(
'EndDevice',
'0x0017880104e45530',
6536,
0,
[new Endpoint(1, [0], [0, 3, 4, 6, 8, 5])],
true,
'Battery',
undefined,
true,
),
notInSettings: new Device(
'EndDevice',
'0x0017880104e45519',
6537,
0,
[new Endpoint(1, [0], [0, 3, 4, 6, 8, 5])],
true,
'Battery',
'lumi.sensor_switch.aq2',
),
WXKG11LM: new Device(
'EndDevice',
'0x0017880104e45520',
6537,
4151,
[
new Endpoint(1, [0], [0, 3, 4, 6, 8, 5], '0x0017880104e45520', [], {}, [
{
cluster: {name: 'genOnOff'},
attribute: {name: undefined, ID: 1337},
minimumReportInterval: 1,
maximumReportInterval: 10,
reportableChange: 20,
},
]),
],
true,
'Battery',
'lumi.sensor_switch.aq2',
),
WXKG02LM_rev1: new Device(
'EndDevice',
'0x0017880104e45521',
6538,
4151,
[new Endpoint(1, [0], []), new Endpoint(2, [0], [])],
true,
'Battery',
'lumi.sensor_86sw2.es1',
),
WSDCGQ11LM: new Device('EndDevice', '0x0017880104e45522', 6539, 4151, [new Endpoint(1, [0], [])], true, 'Battery', 'lumi.weather'),
// This are not a real spammer device, just copy of previous to test the throttle filter
SPAMMER: new Device('EndDevice', '0x0017880104e455fe', 6539, 4151, [new Endpoint(1, [0], [])], true, 'Battery', 'lumi.weather'),
RTCGQ11LM: new Device('EndDevice', '0x0017880104e45523', 6540, 4151, [new Endpoint(1, [0], [])], true, 'Battery', 'lumi.sensor_motion.aq2'),
ZNCZ02LM: ZNCZ02LM,
E1743: new Device('Router', '0x0017880104e45540', 6540, 4476, [new Endpoint(1, [0], [])], true, 'Mains (single phase)', 'TRADFRI on/off switch'),
QBKG04LM: new Device(
'Router',
'0x0017880104e45541',
6549,
4151,
[new Endpoint(1, [0], [25]), new Endpoint(2, [0, 6], [])],
true,
'Mains (single phase)',
'lumi.ctrl_neutral1',
),
QBKG03LM: QBKG03LM,
GLEDOPTO1112: new Device(
'Router',
'0x0017880104e45543',
6540,
4151,
[new Endpoint(11, [0], [], '0x0017880104e45543'), new Endpoint(13, [0], [], '0x0017880104e45543')],
true,
'Mains (single phase)',
'GL-C-008',
),
GLEDOPTO111213: new Device(
'Router',
'0x0017880104e45544',
6540,
4151,
[new Endpoint(11, [0], []), new Endpoint(13, [0], []), new Endpoint(12, [0], [])],
true,
'Mains (single phase)',
'GL-C-008',
),
GLEDOPTO_2ID: GLEDOPTO_2ID,
HGZB04D: new Device(
'Router',
'0x0017880104e45545',
6540,
4151,
[new Endpoint(1, [0], [25], '0x0017880104e45545')],
true,
'Mains (single phase)',
'FB56+ZSC05HG1.0',
),
ZNCLDJ11LM: new Device(
'Router',
'0x0017880104e45547',
6540,
4151,
[new Endpoint(1, [0], []), new Endpoint(2, [0], [])],
true,
'Mains (single phase)',
'lumi.curtain',
),
HAMPTON99432: new Device(
'Router',
'0x0017880104e45548',
6540,
4151,
[new Endpoint(1, [0], []), new Endpoint(2, [0], [])],
true,
'Mains (single phase)',
'HDC52EastwindFan',
),
HS2WD: new Device('Router', '0x0017880104e45549', 6540, 4151, [new Endpoint(1, [0], [])], true, 'Mains (single phase)', 'WarningDevice'),
'1TST_EU': new Device('Router', '0x0017880104e45550', 6540, 4151, [new Endpoint(1, [0], [])], true, 'Mains (single phase)', 'Thermostat'),
SV01: new Device('Router', '0x0017880104e45551', 6540, 4151, [new Endpoint(1, [0], [])], true, 'Mains (single phase)', 'SV01-410-MP-1.0'),
J1: new Device('Router', '0x0017880104e45552', 6540, 4151, [new Endpoint(1, [0], [])], true, 'Mains (single phase)', 'J1 (5502)'),
E11_G13: new Device('EndDevice', '0x0017880104e45553', 6540, 4151, [new Endpoint(1, [0, 6], [])], true, 'Mains (single phase)', 'E11-G13'),
nomodel: new Device(
'Router',
'0x0017880104e45535',
6536,
0,
[new Endpoint(1, [0], [0, 3, 4, 6, 8, 5])],
true,
'Mains (single phase)',
undefined,
true,
),
unsupported_router: new Device(
'Router',
'0x0017880104e45525',
6536,
0,
[new Endpoint(1, [0], [0, 3, 4, 6, 8, 5])],
true,
'Mains (single phase)',
'notSupportedModelID',
false,
'Boef',
),
CC2530_ROUTER: new Device('Router', '0x0017880104e45559', 6540, 4151, [new Endpoint(1, [0, 6], [])], true, 'Mains (single phase)', 'lumi.router'),
LIVOLO: new Device('Router', '0x0017880104e45560', 6541, 4152, [new Endpoint(6, [0, 6], [])], true, 'Mains (single phase)', 'TI0001 '),
tradfri_remote: new Device(
'EndDevice',
'0x90fd9ffffe4b64ae',
33906,
4476,
[new Endpoint(1, [0], [0, 3, 4, 6, 8, 5], '0x90fd9ffffe4b64ae')],
true,
'Battery',
'TRADFRI remote control',
),
roller_shutter: new Device(
'EndDevice',
'0x90fd9ffffe4b64af',
33906,
4476,
[new Endpoint(1, [0], [0, 3, 4, 6, 8, 5], '0x90fd9ffffe4b64af')],
true,
'Battery',
'SCM-R_00.00.03.15TC',
),
ZNLDP12LM: new Device(
'Router',
'0x90fd9ffffe4b64ax',
33901,
4476,
[
new Endpoint(1, [0, 4, 3, 5, 10, 258, 13, 19, 6, 1, 1030, 8, 768, 1027, 1029, 1026], [0, 3, 4, 6, 8, 5], '0x90fd9ffffe4b64ax', [], {
lightingColorCtrl: {colorCapabilities: 254},
}),
],
true,
'Mains (single phase)',
'lumi.light.aqcn02',
),
SP600_OLD: new Device(
'Router',
'0x90fd9ffffe4b64aa',
33901,
4476,
[
new Endpoint(1, [0, 4, 3, 5, 10, 258, 13, 19, 6, 1, 1030, 8, 768, 1027, 1029, 1026], [0, 3, 4, 6, 8, 5], '0x90fd9ffffe4b64aa', [], {
seMetering: {multiplier: 1, divisor: 10000},
}),
],
true,
'Mains (single phase)',
'SP600',
false,
'Salus',
'20160120',
),
SP600_NEW: new Device(
'Router',
'0x90fd9ffffe4b64ab',
33901,
4476,
[
new Endpoint(1, [0, 4, 3, 5, 10, 258, 13, 19, 6, 1, 1030, 8, 768, 1027, 1029, 1026], [0, 3, 4, 6, 8, 5], '0x90fd9ffffe4b64aa', [], {
seMetering: {multiplier: 1, divisor: 10000},
}),
],
true,
'Mains (single phase)',
'SP600',
false,
'Salus',
'20170220',
),
'MKS-CM-W5': new Device(
'Router',
'0x90fd9ffffe4b64ac',
33901,
4476,
[new Endpoint(1, [0, 4, 3, 5, 10, 258, 13, 19, 6, 1, 1030, 8, 768, 1027, 1029, 1026], [0, 3, 4, 6, 8, 5], '0x90fd9ffffe4b64aa', [], {})],
true,
'Mains (single phase)',
'qnazj70',
false,
),
'GL-S-007ZS': new Device(
'Router',
'0x0017880104e45526',
6540,
4151,
[new Endpoint(1, [0], [], '0x0017880104e45526')],
true,
'Mains (single phase)',
'GL-S-007ZS',
),
U202DST600ZB: new Device(
'Router',
'0x0017880104e43559',
6540,
4151,
[new Endpoint(10, [0, 6], [], '0x0017880104e43559'), new Endpoint(11, [0, 6], [], '0x0017880104e43559')],
true,
'Mains (single phase)',
'U202DST600ZB',
),
zigfred_plus: zigfred_plus,
3157100: new Device(
'Router',
'0x0017880104e44559',
6542,
4151,
[new Endpoint(1, [], [], '0x0017880104e44559')],
true,
'Mains (single phase)',
'3157100',
false,
'Centralite',
),
J1: new Device(
'Router',
'0x0017880104a44559',
6543,
4151,
[new Endpoint(1, [], [], '0x0017880104a44559')],
true,
'Mains (single phase)',
'J1 (5502)',
),
TS0601_thermostat: TS0601_thermostat,
TS0601_switch: TS0601_switch,
TS0601_cover_switch: TS0601_cover_switch,
external_converter_device: new Device(
'EndDevice',
'0x0017880104e45511',
1114,
'external',
[new Endpoint(1, [], [], '0x0017880104e45511')],
false,
null,
'external_converter_device',
),
QS_Zigbee_D02_TRIAC_2C_LN: new Device(
'Router',
'0x0017882194e45543',
6549,
4151,
[new Endpoint(1, [0], [], '0x0017882194e45543'), new Endpoint(2, [0, 6], [], '0x0017882194e45543')],
true,
'Mains (single phase)',
'TS110F',
false,
'_TYZB01_v8gtiaed',
),
unknown: new Device('Router', '0x0017980134e45545', 6540, 4151, [], true, 'Mains (single phase)'),
temperature_sensor: new Device(
'EndDevice',
'0x0017880104e45561',
6544,
4151,
[new Endpoint(1, [0, 3, 4, 1026], [])],
true,
'Battery',
'temperature.sensor',
),
heating_actuator: new Device(
'Router',
'0x0017880104e45562',
6545,
4151,
[new Endpoint(1, [0, 3, 4, 513], [1026])],
true,
'Mains (single phase)',
'heating.actuator',
),
bj_scene_switch: new Device(
'EndDevice',
'0xd85def11a1002caa',
50117,
4398,
[
new Endpoint(10, [0, 4096], [3, 4, 5, 6, 8, 25, 768, 4096], '0xd85def11a1002caa', [
{target: bulb_color_2.endpoints[0], cluster: {ID: 8, name: 'genLevelCtrl'}},
{target: bulb_color_2.endpoints[0], cluster: {ID: 6, name: 'genOnOff'}},
{target: bulb_color_2.endpoints[0], cluster: {ID: 768, name: 'lightingColorCtrl'}},
]),
new Endpoint(11, [0, 4096], [3, 4, 5, 6, 8, 25, 768, 4096], '0xd85def11a1002caa'),
],
true,
'Battery',
'RB01',
false,
'Busch-Jaeger',
'20161222',
'1.2.0',
),
'GW003-AS-IN-TE-FC': new Device(
'Router',
'0x0017548104a44669',
6545,
4699,
[new Endpoint(1, [3], [0, 3, 513, 514], '0x0017548104a44669')],
true,
'Mains (single phase)',
'Adapter Zigbee FUJITSU',
),
'BMCT-SLZ': new Device(
'Router',
'0x18fc26000000cafe',
6546,
4617,
[new Endpoint(1, [0, 3, 4, 5, 258, 1794, 2820, 2821, 64672], [10, 25], '0x18fc26000000cafe')],
true,
'Mains (single phase)',
'RBSH-MMS-ZB-EU',
),
BMCT_SLZ: new Device(
'Router',
'0x0026decafe000473',
6546,
4617,
[new Endpoint(1, [0, 3, 4, 5, 258, 1794, 2820, 2821, 64672], [10, 25], '0x0026decafe000473')],
true,
'Mains (single phase)',
'RBSH-MMS-ZB-EU',
false,
null,
null,
null,
custom_clusters,
),
bulb_custom_cluster: new Device(
'Router',
'0x000b57fffec6a5c2',
40369,
4476,
[new Endpoint(1, [0, 3, 4, 5, 6, 8, 768, 2821, 4096], [5, 25, 32, 4096], '0x000b57fffec6a5c2')],
true,
'Mains (single phase)',
'TRADFRI bulb E27 WS opal 980lm',
false,
null,
null,
null,
custom_clusters,
),
};
const mock = {
setTransmitPower: jest.fn(),
touchlinkFactoryReset: jest.fn(),
touchlinkFactoryResetFirst: jest.fn(),
touchlinkScan: jest.fn(),
touchlinkIdentify: jest.fn(),
start: jest.fn(),
backup: jest.fn(),
coordinatorCheck: jest.fn(),
isStopping: jest.fn(),
permitJoin: jest.fn(),
addInstallCode: jest.fn(),
getCoordinatorVersion: jest.fn().mockReturnValue({type: 'z-Stack', meta: {version: 1, revision: 20190425}}),
getNetworkParameters: jest.fn().mockReturnValue({panID: 0x162a, extendedPanID: [0, 11, 22], channel: 15}),
on: (type, handler) => {
events[type] = handler;
},
stop: jest.fn(),
getDevicesIterator: jest.fn().mockImplementation(function* (predicate) {
for (const key in devices) {
const device = devices[key];
if ((returnDevices.length === 0 || returnDevices.includes(device.ieeeAddr)) && !device.isDeleted && (!predicate || predicate(device))) {
yield device;
}
}
}),
getDevicesByType: jest.fn().mockImplementation((type) => {
return Object.values(devices)
.filter((d) => returnDevices.length === 0 || returnDevices.includes(d.ieeeAddr))
.filter((d) => d.type === type);
}),
getDeviceByIeeeAddr: jest.fn().mockImplementation((ieeeAddr) => {
return Object.values(devices)
.filter((d) => returnDevices.length === 0 || returnDevices.includes(d.ieeeAddr))
.find((d) => d.ieeeAddr === ieeeAddr);
}),
getDeviceByNetworkAddress: jest.fn().mockImplementation((networkAddress) => {
return Object.values(devices)
.filter((d) => returnDevices.length === 0 || returnDevices.includes(d.ieeeAddr))
.find((d) => d.networkAddress === networkAddress);
}),
getGroupsIterator: jest.fn().mockImplementation(function* (predicate) {
for (const key in groups) {
const group = groups[key];
if (!predicate || predicate(group)) {
yield group;
}
}
}),
getGroupByID: jest.fn().mockImplementation((groupID) => {
return Object.values(groups).find((d) => d.groupID === groupID);
}),
getPermitJoin: jest.fn().mockReturnValue(false),
getPermitJoinTimeout: jest.fn().mockReturnValue(undefined),
reset: jest.fn(),
createGroup: jest.fn().mockImplementation((groupID) => {
const group = new Group(groupID, []);
groups[`group_${groupID}`] = group;
return group;
}),
};
const mockConstructor = jest.fn().mockImplementation(() => mock);
jest.mock('zigbee-herdsman', () => ({
...jest.requireActual('zigbee-herdsman'),
Controller: mockConstructor,
}));
module.exports = {
events,
...mock,
constructor: mockConstructor,
devices,
groups,
returnDevices,
custom_clusters,
};