mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-07-11 06:11:46 +00:00
Poll device when device does not support reporting. (#2122)
* Support emulation of attReport
Some device do not support attReport for some keys, this will emulate
it.
You can configure which keys that should be read when another device
send a message and the configured device a bind target or in a group the
message was send to.
```yaml
devices:
'0x0017880104259333':
friendly_name: bedroom/desk_lamp
retain: true
debounce: 0.5
report_emulate:
- brightness
- color
```
Will have the brightness and color queried for example when a hue dimmer
sends commands to the bulb.
* Refactor polling.
* Finish poll tests.
* Update herdsman.
* Improve test stability.
This commit is contained in:
committed by
Koen Kanters
parent
ec5064bc4d
commit
a813663de5
@@ -3,6 +3,8 @@ const logger = require('../util/logger');
|
||||
const CC2530Router = zigbeeHerdsmanConverters.devices.find((d) => d.model === 'CC2530.ROUTER');
|
||||
const utils = require('../util/utils');
|
||||
const BaseExtension = require('./baseExtension');
|
||||
const debounce = require('debounce');
|
||||
const ZigbeeHerdsman = require('zigbee-herdsman');
|
||||
|
||||
const defaultConfiguration = {
|
||||
minimumReportInterval: 3, maximumReportInterval: 300, reportableChange: 0,
|
||||
@@ -28,11 +30,31 @@ const clusters = {
|
||||
],
|
||||
};
|
||||
|
||||
const pollOnMessage = [
|
||||
{
|
||||
// Key is used this.pollDebouncers uniqueness
|
||||
key: 1,
|
||||
// On messages that have the cluster and type of below
|
||||
cluster: {
|
||||
manuSpecificPhilips: ['commandHueNotification'],
|
||||
genLevelCtrl: [
|
||||
'commandStep', 'commandStepWithOnOff', 'commandStop', 'commandMoveWithOnOff', 'commandStopWithOnOff',
|
||||
'commandMove',
|
||||
],
|
||||
},
|
||||
// Read the following attributes
|
||||
read: {cluster: 'genLevelCtrl', attributes: ['currentLevel']},
|
||||
// When the bound devices/members of group have the following manufacturerID
|
||||
manufacturerID: ZigbeeHerdsman.Zcl.ManufacturerCode.Philips,
|
||||
},
|
||||
];
|
||||
|
||||
class DeviceReport extends BaseExtension {
|
||||
constructor(zigbee, mqtt, state, publishEntityState) {
|
||||
super(zigbee, mqtt, state, publishEntityState);
|
||||
this.configuring = new Set();
|
||||
this.failed = new Set();
|
||||
this.pollDebouncers = {};
|
||||
}
|
||||
|
||||
async setupReporting(device) {
|
||||
@@ -99,6 +121,60 @@ class DeviceReport extends BaseExtension {
|
||||
if (this.shouldSetupReporting(mappedDevice, data.device, type)) {
|
||||
this.setupReporting(data.device);
|
||||
}
|
||||
|
||||
if (type === 'message') {
|
||||
this.poll(data);
|
||||
}
|
||||
}
|
||||
|
||||
poll(message) {
|
||||
/**
|
||||
* This method poll bound endpoints and group members for state changes.
|
||||
*
|
||||
* A use case is e.g. a Hue Dimmer switch bound to a Hue bulb.
|
||||
* Hue bulbs only report their on/off state.
|
||||
* When dimming the bulb via the dimmer switch the state is therefore not reported.
|
||||
* When we receive a message from a Hue dimmer we read the brightness from the bulb (if bound).
|
||||
*/
|
||||
|
||||
const polls = pollOnMessage.filter((p) =>
|
||||
p.cluster[message.cluster] && p.cluster[message.cluster].includes(message.type)
|
||||
);
|
||||
|
||||
if (polls.length) {
|
||||
let toPoll = [];
|
||||
|
||||
// Add bound devices
|
||||
toPoll = toPoll.concat([].concat(...message.device.endpoints.map((e) => e.binds.map((e) => e))));
|
||||
toPoll = toPoll.filter((e) => e.target.constructor.name === 'Endpoint');
|
||||
toPoll = toPoll.filter((e) => e.target.getDevice().type !== 'Coordinator');
|
||||
toPoll = toPoll.map((e) => e.target);
|
||||
|
||||
// If message is published to a group, add members of the group
|
||||
const group = message.groupID !== 0 ? this.zigbee.getGroupByID(message.groupID) : null;
|
||||
if (group) {
|
||||
toPoll = toPoll.concat(group.members);
|
||||
}
|
||||
|
||||
toPoll = new Set(toPoll);
|
||||
|
||||
for (const endpoint of toPoll) {
|
||||
for (const poll of polls) {
|
||||
if (poll.manufacturerID !== endpoint.getDevice().manufacturerID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const key = `${endpoint.deviceIeeeAddress}_${endpoint.ID}_${poll.key}`;
|
||||
if (!this.pollDebouncers[key]) {
|
||||
this.pollDebouncers[key] = debounce(async () => {
|
||||
await endpoint.read(poll.read.cluster, poll.read.attributes);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
this.pollDebouncers[key]();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
+18
-18
@@ -880,9 +880,9 @@
|
||||
}
|
||||
},
|
||||
"bser": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz",
|
||||
"integrity": "sha512-8zsjWrQkkBoLK6uxASk1nJ2SKv97ltiGDo6A3wA0/yRPz+CwmEyDo0hUrhIuukG2JHpAl3bvFIixw2/3Hi0DOg==",
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
|
||||
"integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"node-int64": "^0.4.0"
|
||||
@@ -1628,9 +1628,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"eslint-plugin-jest": {
|
||||
"version": "22.19.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-22.19.0.tgz",
|
||||
"integrity": "sha512-4zUc3rh36ds0SXdl2LywT4YWA3zRe8sfLhz8bPp8qQPIKvynTTkNGwmSCMpl5d9QiZE2JxSinGF+WD8yU+O0Lg==",
|
||||
"version": "22.20.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-22.20.0.tgz",
|
||||
"integrity": "sha512-UwHGXaYprxwd84Wer8H7jZS+5C3LeEaU8VD7NqORY6NmPJrs+9Ugbq3wyjqO3vWtSsDaLar2sqEB8COmOZA4zw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/experimental-utils": "^1.13.0"
|
||||
@@ -2717,9 +2717,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz",
|
||||
"integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==",
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
|
||||
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
|
||||
"dev": true
|
||||
},
|
||||
"growly": {
|
||||
@@ -4644,9 +4644,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.10.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.2.tgz",
|
||||
"integrity": "sha512-INBT1QEgtcCCgvccr5/86CfD71fw9EPmDxgiJX4I2Ddr6ZsV6iFXsuby+qWJPtmNuMY0zByTsG4468P7nHuNWA==",
|
||||
"version": "16.11.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.11.0.tgz",
|
||||
"integrity": "sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw==",
|
||||
"dev": true
|
||||
},
|
||||
"read-pkg": {
|
||||
@@ -5665,9 +5665,9 @@
|
||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.6.3",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.3.tgz",
|
||||
"integrity": "sha512-KfQUgOqTkLp2aZxrMbCuKCDGW9slFYu2A23A36Gs7sGzTLcRBDORdOi5E21KWHFIfkY8kzgi/Pr1cXCh0yIp5g==",
|
||||
"version": "3.6.4",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.4.tgz",
|
||||
"integrity": "sha512-9Yc2i881pF4BPGhjteCXQNaXx1DCwm3dtOyBaG2hitHjLWOczw/ki8vD1bqyT3u6K0Ms/FpCShkmfg+FtlOfYA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -6053,9 +6053,9 @@
|
||||
}
|
||||
},
|
||||
"zigbee-herdsman": {
|
||||
"version": "0.10.9",
|
||||
"resolved": "https://registry.npmjs.org/zigbee-herdsman/-/zigbee-herdsman-0.10.9.tgz",
|
||||
"integrity": "sha512-QcV/v1hqGYdlawvvgoZsClOI6aeXGvJVSCZkMm4xQS1SbevTXzXFP4VtcR5WlnK0a+Kl7ibXcVfnR4XCl2r5IA==",
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/zigbee-herdsman/-/zigbee-herdsman-0.11.1.tgz",
|
||||
"integrity": "sha512-eBIEZN8cF9hlPMRDUQ8J0LBEa7obYX74pmMwvK3dBmeMfc4m3kzNYZ0Lgc+XV93VSEEe9Hj9flOuHa93KUZKIQ==",
|
||||
"requires": {
|
||||
"debug": "^4.1.1",
|
||||
"fast-deep-equal": "^2.0.1",
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@
|
||||
"rimraf": "*",
|
||||
"semver": "*",
|
||||
"winston": "*",
|
||||
"zigbee-herdsman": "0.10.9",
|
||||
"zigbee-herdsman": "0.11.1",
|
||||
"zigbee-herdsman-converters": "11.1.28"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -170,7 +170,7 @@ describe('Bridge config', () => {
|
||||
await flushPromises();
|
||||
expect(MQTT.publish.mock.calls[0][0]).toStrictEqual('zigbee2mqtt/bridge/log');
|
||||
const payload = JSON.parse(MQTT.publish.mock.calls[0][1]);
|
||||
expect(payload).toStrictEqual({"message": [{"ID": 1, "friendly_name": "group_1", "retain": false, 'devices': [], optimistic: true}, {"ID": 2, "friendly_name": "group_2", "retain": false, "devices": [], optimistic: true}], "type": "groups"});
|
||||
expect(payload).toStrictEqual({"message": [{"ID": 1, "friendly_name": "group_1", "retain": false, 'devices': [], optimistic: true}, {"ID": 2, "friendly_name": "group_2", "retain": false, "devices": [], optimistic: true}, {"ID": 15071, "friendly_name": "group_tradfri_remote", "retain": false, "devices": ['bulb_color_2', 'bulb_2'], optimistic: true}], "type": "groups"});
|
||||
});
|
||||
|
||||
it('Should allow rename devices', async () => {
|
||||
@@ -237,7 +237,6 @@ describe('Bridge config', () => {
|
||||
expect(device.removeFromNetwork).toHaveBeenCalledTimes(1);
|
||||
expect(controller.state[device.ieeeAddr]).toBeUndefined();
|
||||
expect(settings.getDevice('bulb_color')).toBeNull();
|
||||
expect(MQTT.publish).toHaveBeenCalledTimes(1);
|
||||
expect(MQTT.publish).toHaveBeenCalledWith(
|
||||
'zigbee2mqtt/bridge/log',
|
||||
JSON.stringify({type: 'device_removed', message: 'bulb_color'}),
|
||||
|
||||
@@ -6,13 +6,17 @@ zigbeeHerdsman.returnDevices.push('0x00124b00120144ae');
|
||||
zigbeeHerdsman.returnDevices.push('0x000b57fffec6a5b2');
|
||||
zigbeeHerdsman.returnDevices.push('0x0017880104e45553');
|
||||
zigbeeHerdsman.returnDevices.push('0x0017880104e45559');
|
||||
zigbeeHerdsman.returnDevices.push('0x000b57fffec6a5b4');
|
||||
zigbeeHerdsman.returnDevices.push('0x000b57fffec6a5b7');
|
||||
const MQTT = require('./stub/mqtt');
|
||||
const settings = require('../lib/util/settings');
|
||||
const Controller = require('../lib/controller');
|
||||
const flushPromises = () => new Promise(setImmediate);
|
||||
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
jest.mock('debounce', () => jest.fn(fn => fn));
|
||||
const debounce = require('debounce');
|
||||
|
||||
const mocksClear = [MQTT.publish, logger.warn, logger.debug];
|
||||
const mocksClear = [MQTT.publish, logger.warn, logger.debug, debounce];
|
||||
|
||||
describe('Device report', () => {
|
||||
let controller;
|
||||
@@ -163,4 +167,34 @@ describe('Device report', () => {
|
||||
await flushPromises();
|
||||
expect(endpoint.bind).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('Should poll bounded Hue bulb when receiving message from Hue dimmer', async () => {
|
||||
const remote = zigbeeHerdsman.devices.remote;
|
||||
const data = {"button":3,"unknown1":3145728,"type":2,"unknown2":0,"time":1};
|
||||
const payload = {data, cluster: 'manuSpecificPhilips', device: remote, endpoint: remote.getEndpoint(2), type: 'commandHueNotification', linkquality: 10, groupID: 0};
|
||||
await zigbeeHerdsman.events.message(payload);
|
||||
await flushPromises();
|
||||
expect(debounce).toHaveBeenCalledTimes(1);
|
||||
expect(zigbeeHerdsman.devices.bulb_color.getEndpoint(1).read).toHaveBeenCalledWith("genLevelCtrl", ["currentLevel"]);
|
||||
});
|
||||
|
||||
it('Should poll grouped Hue bulb when receiving message from TRADFRI remote and should', async () => {
|
||||
const remote = zigbeeHerdsman.devices.tradfri_remote;
|
||||
const data = {"stepmode":0,"stepsize":43,"transtime":5};
|
||||
const payload = {data, cluster: 'genLevelCtrl', device: remote, endpoint: remote.getEndpoint(1), type: 'commandStepWithOnOff', linkquality: 10, groupID: 15071};
|
||||
await zigbeeHerdsman.events.message(payload);
|
||||
await flushPromises();
|
||||
expect(debounce).toHaveBeenCalledTimes(1);
|
||||
expect(zigbeeHerdsman.devices.bulb_color_2.getEndpoint(1).read).toHaveBeenCalledTimes(1);
|
||||
expect(zigbeeHerdsman.devices.bulb_color_2.getEndpoint(1).read).toHaveBeenCalledWith("genLevelCtrl", ["currentLevel"]);
|
||||
|
||||
// Should also only debounce once
|
||||
await zigbeeHerdsman.events.message(payload);
|
||||
await flushPromises();
|
||||
expect(debounce).toHaveBeenCalledTimes(1);
|
||||
expect(zigbeeHerdsman.devices.bulb_color_2.getEndpoint(1).read).toHaveBeenCalledTimes(2);
|
||||
|
||||
// Should only call Hue bulb, not e.g. tradfri
|
||||
expect(zigbeeHerdsman.devices.bulb.getEndpoint(1).read).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -353,10 +353,10 @@ describe('Entity publish', () => {
|
||||
|
||||
it('Should create and publish to group which is in configuration.yaml but not in zigbee-herdsman', async () => {
|
||||
delete zigbeeHerdsman.groups.group_2;
|
||||
expect(Object.values(zigbeeHerdsman.groups).length).toBe(1);
|
||||
expect(Object.values(zigbeeHerdsman.groups).length).toBe(2);
|
||||
await MQTT.events.message('zigbee2mqtt/group_2/set', JSON.stringify({state: 'ON'}));
|
||||
await flushPromises();
|
||||
expect(Object.values(zigbeeHerdsman.groups).length).toBe(2);
|
||||
expect(Object.values(zigbeeHerdsman.groups).length).toBe(3);
|
||||
expect(zigbeeHerdsman.groups.group_2.command).toHaveBeenCalledTimes(1);
|
||||
expect(zigbeeHerdsman.groups.group_2.command).toHaveBeenCalledWith("genOnOff", "on", {}, {});
|
||||
});
|
||||
|
||||
@@ -55,10 +55,18 @@ function writeDefaultConfiguration() {
|
||||
retain: false,
|
||||
friendly_name: "ikea_onoff"
|
||||
},
|
||||
'0x000b57fffec6a5b7': {
|
||||
retain: false,
|
||||
friendly_name: "bulb_2"
|
||||
},
|
||||
"0x000b57fffec6a5b3": {
|
||||
retain: false,
|
||||
friendly_name: "bulb_color"
|
||||
},
|
||||
'0x000b57fffec6a5b4': {
|
||||
retain: false,
|
||||
friendly_name: "bulb_color_2"
|
||||
},
|
||||
"0x0017880104e45541": {
|
||||
retain: false,
|
||||
friendly_name: "wall_switch"
|
||||
@@ -118,6 +126,10 @@ function writeDefaultConfiguration() {
|
||||
'0x0017880104e45560': {
|
||||
retain: false,
|
||||
friendly_name: 'livolo'
|
||||
},
|
||||
'0x90fd9ffffe4b64ae': {
|
||||
retain: false,
|
||||
friendly_name: 'tradfri_remote',
|
||||
}
|
||||
},
|
||||
groups: {
|
||||
@@ -128,6 +140,11 @@ function writeDefaultConfiguration() {
|
||||
'2': {
|
||||
friendly_name: 'group_2',
|
||||
retain: false,
|
||||
},
|
||||
'15071': {
|
||||
friendly_name: 'group_tradfri_remote',
|
||||
retain: false,
|
||||
devices: ['bulb_color_2', 'bulb_2']
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,11 +2,11 @@ const events = {};
|
||||
const assert = require('assert');
|
||||
|
||||
class Group {
|
||||
constructor(groupID) {
|
||||
constructor(groupID, members) {
|
||||
this.groupID = groupID;
|
||||
this.command = jest.fn();
|
||||
this.meta = {};
|
||||
this.members = [];
|
||||
this.members = members;
|
||||
this.hasMember = (endpoint) => this.members.includes(endpoint);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ const clusters = {
|
||||
}
|
||||
|
||||
class Endpoint {
|
||||
constructor(ID, inputClusters, outputClusters, deviceIeeeAddress) {
|
||||
constructor(ID, inputClusters, outputClusters, deviceIeeeAddress, binds=[]) {
|
||||
this.deviceIeeeAddress = deviceIeeeAddress;
|
||||
this.ID = ID;
|
||||
this.inputClusters = inputClusters;
|
||||
@@ -31,6 +31,7 @@ class Endpoint {
|
||||
this.bind = jest.fn();
|
||||
this.unbind = jest.fn();
|
||||
this.configureReporting = jest.fn();
|
||||
this.binds = binds;
|
||||
this.supportsInputCluster = (cluster) => {
|
||||
assert(clusters[cluster], `Undefined '${cluster}'`);
|
||||
return this.inputClusters.includes(clusters[cluster]);
|
||||
@@ -88,11 +89,17 @@ class Device {
|
||||
|
||||
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')], 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')], true, "Mains (single phase)", "LLC020");
|
||||
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')], true, "Mains (single phase)", "TRADFRI bulb E27 WS opal 980lm");
|
||||
|
||||
const devices = {
|
||||
'coordinator': new Device('Coordinator', '0x00124b00120144ae', 0, 0, [new Endpoint(1, [], [])], 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')], true, "Mains (single phase)", "TRADFRI bulb E27 WS opal 980lm"),
|
||||
'bulb_color': new Device('Router', '0x000b57fffec6a5b3', 40399, 6535, [new Endpoint(1, [0,3,4,5,6,8,768,2821,4096], [5,25,32,4096], '0x000b57fffec6a5b3')], true, "Mains (single phase)", "LLC020"),
|
||||
'remote': new Device('EndDevice', '0x0017880104e45517', 6535, 4107, [new Endpoint(1, [0], [0,3,4,6,8,5]), new Endpoint(2, [0,1,3,15,64512], [25, 6])], true, "Battery", "RWL021"),
|
||||
'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]}]), 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"),
|
||||
'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),
|
||||
@@ -119,10 +126,12 @@ const devices = {
|
||||
'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"),
|
||||
}
|
||||
|
||||
const groups = {
|
||||
'group_1': new Group(1),
|
||||
'group_1': new Group(1, []),
|
||||
'group_tradfri_remote': new Group(15071, [bulb_color_2.endpoints[0], bulb_2.endpoints[0]]),
|
||||
}
|
||||
|
||||
const mock = {
|
||||
@@ -153,7 +162,7 @@ const mock = {
|
||||
getPermitJoin: jest.fn().mockReturnValue(false),
|
||||
reset: jest.fn(),
|
||||
createGroup: jest.fn().mockImplementation((groupID) => {
|
||||
const group = new Group(groupID);
|
||||
const group = new Group(groupID, []);
|
||||
groups[`group_${groupID}`] = group
|
||||
return group;
|
||||
})
|
||||
@@ -163,6 +172,7 @@ const mockConstructor = jest.fn().mockImplementation(() => mock);
|
||||
|
||||
jest.mock('zigbee-herdsman', () => ({
|
||||
Controller: mockConstructor,
|
||||
Zcl: {ManufacturerCode: {Philips: 4107}},
|
||||
}));
|
||||
|
||||
module.exports = {
|
||||
|
||||
Reference in New Issue
Block a user