iobroker.zigbee 1.8.0 → 1.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +2 -0
- package/.eslintrc.json +37 -0
- package/.github/FUNDING.yml +3 -0
- package/.github/auto-merge.yml +17 -0
- package/.github/dependabot.yml +24 -0
- package/.github/stale.yml +13 -0
- package/.github/workflows/codeql.yml +41 -0
- package/.github/workflows/dependabot-automerge.yml +22 -0
- package/.github/workflows/test-and-release.yml +149 -0
- package/.releaseconfig.json +3 -0
- package/.travis/wiki.sh +28 -0
- package/.travis.yml +41 -0
- package/README.md +32 -9
- package/admin/admin.js +466 -482
- package/admin/i18n/de/translations.json +2 -2
- package/admin/index_m.html +1 -1
- package/admin/tab_m.html +3 -44
- package/admin/words.js +2 -2
- package/gulpfile.js +464 -0
- package/io-package.json +19 -26
- package/lib/backup.js +2 -2
- package/lib/binding.js +24 -23
- package/lib/colors.js +14 -16
- package/lib/commands.js +82 -89
- package/lib/developer.js +7 -6
- package/lib/devices.js +153 -144
- package/lib/exclude.js +36 -30
- package/lib/exposes.js +111 -106
- package/lib/groups.js +54 -53
- package/lib/json.js +4 -3
- package/lib/networkmap.js +2 -2
- package/lib/ota.js +15 -23
- package/lib/rgb.js +44 -47
- package/lib/seriallist.js +16 -21
- package/lib/states.js +496 -482
- package/lib/statescontroller.js +164 -170
- package/lib/utils.js +21 -22
- package/lib/zbBaseExtension.js +4 -4
- package/lib/zbDelayedAction.js +13 -5
- package/lib/zbDeviceAvailability.js +44 -47
- package/lib/zbDeviceConfigure.js +19 -7
- package/lib/zbDeviceEvent.js +4 -3
- package/lib/zigbeecontroller.js +96 -88
- package/main.js +133 -149
- package/package.json +15 -29
- package/test/integration.js +5 -0
- package/test/mocha.custom.opts +2 -0
- package/test/mocha.setup.js +14 -0
- package/test/package.js +5 -0
- package/test/unit.js +5 -0
- package/docs/de/img/CC2531.png +0 -0
- package/docs/de/img/CC2538_CC2592_PA.PNG +0 -0
- package/docs/de/img/CC2591.png +0 -0
- package/docs/de/img/boards.jpg +0 -0
- package/docs/de/img/cc26x2r.PNG +0 -0
- package/docs/de/img/results.jpg +0 -0
- package/docs/de/img/sku_429478_2.png +0 -0
- package/docs/de/img/sku_429601_2.png +0 -0
- package/docs/de/readme.md +0 -27
- package/docs/en/img/CC2531.png +0 -0
- package/docs/en/img/CC2591.png +0 -0
- package/docs/en/img/deconz.png +0 -0
- package/docs/en/img/sku_429478_2.png +0 -0
- package/docs/en/img/sku_429601_2.png +0 -0
- package/docs/en/readme.md +0 -30
- package/docs/flashing_via_arduino_(en).md +0 -110
- package/docs/ru/img/CC2531.png +0 -0
- package/docs/ru/img/CC2591.png +0 -0
- package/docs/ru/img/sku_429478_2.png +0 -0
- package/docs/ru/img/sku_429601_2.png +0 -0
- package/docs/ru/readme.md +0 -28
- package/docs/tutorial/CC2530_20190425.zip +0 -0
- package/docs/tutorial/CC2530_CC2591_20190515.zip +0 -0
- package/docs/tutorial/CC2530_CC2592_20190515.zip +0 -0
- package/docs/tutorial/CC2531_20190425.zip +0 -0
- package/docs/tutorial/adm5_1.PNG +0 -0
- package/docs/tutorial/adm5_2.PNG +0 -0
- package/docs/tutorial/cat.PNG +0 -0
- package/docs/tutorial/groups-1.png +0 -0
- package/docs/tutorial/groups-2.png +0 -0
- package/docs/tutorial/inst.PNG +0 -0
- package/docs/tutorial/reflash-finish.PNG +0 -0
- package/docs/tutorial/reflash-step0.png +0 -0
- package/docs/tutorial/reflash-step1.PNG +0 -0
- package/docs/tutorial/reflash-step2.PNG +0 -0
- package/docs/tutorial/settings.png +0 -0
- package/docs/tutorial/tab-dev-1.png +0 -0
- package/docs/tutorial/zigbee.png +0 -0
- package/docs/tutorial/zigbee15.png +0 -0
package/lib/utils.js
CHANGED
|
@@ -24,7 +24,7 @@ function bulbLevelToAdapterLevel(bulbLevel) {
|
|
|
24
24
|
// - Bulb level range [2...254] is linearly mapped to adapter level range [1...100].
|
|
25
25
|
if (bulbLevel >= 2) {
|
|
26
26
|
// Perform linear mapping of range [2...254] to [1...100]
|
|
27
|
-
return Math.round((bulbLevel - 2) * 99 / 252) + 1;
|
|
27
|
+
return (Math.round((bulbLevel - 2) * 99 / 252) + 1);
|
|
28
28
|
} else {
|
|
29
29
|
// The bulb is considered off. Even a bulb level of "1" is considered as off.
|
|
30
30
|
return 0;
|
|
@@ -42,7 +42,7 @@ function adapterLevelToBulbLevel(adapterLevel) {
|
|
|
42
42
|
// Please read the comments there regarding the rules applied here for mapping the values.
|
|
43
43
|
if (adapterLevel) {
|
|
44
44
|
// Perform linear mapping of range [1...100] to [2...254]
|
|
45
|
-
return Math.round((adapterLevel - 1) * 252 / 99) + 2;
|
|
45
|
+
return (Math.round((adapterLevel - 1) * 252 / 99) + 2);
|
|
46
46
|
} else {
|
|
47
47
|
// Switch the bulb off. Some bulbs need "0" (IKEA), others "1" (HUE), and according to the
|
|
48
48
|
// ZigBee docs "1" is the "minimum possible level"... we choose "0" here which seems to work.
|
|
@@ -53,7 +53,7 @@ function adapterLevelToBulbLevel(adapterLevel) {
|
|
|
53
53
|
function bytesArrayToWordArray(ba) {
|
|
54
54
|
const wa = [];
|
|
55
55
|
for (let i = 0; i < ba.length; i++) {
|
|
56
|
-
wa[(i / 2) | 0] |= ba[i] << (8
|
|
56
|
+
wa[(i / 2) | 0] |= ba[i] << (8*(i % 2));
|
|
57
57
|
}
|
|
58
58
|
return wa;
|
|
59
59
|
}
|
|
@@ -91,25 +91,24 @@ function decimalToHex(decimal, padding) {
|
|
|
91
91
|
|
|
92
92
|
function getZbId(adapterDevId) {
|
|
93
93
|
const idx = adapterDevId.indexOf('group');
|
|
94
|
-
if (idx > 0)
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
return `0x${adapterDevId.split('.')[2]}`;
|
|
94
|
+
if (idx > 0) return adapterDevId.substr(idx+6);
|
|
95
|
+
return '0x' + adapterDevId.split('.')[2];
|
|
98
96
|
}
|
|
99
97
|
|
|
100
98
|
function getAdId(adapter, id) {
|
|
101
|
-
return
|
|
99
|
+
return adapter.namespace + '.' + id.split('.')[2]; // iobroker device id
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
function flatten(arr) {
|
|
105
|
-
return arr.reduce((flat, toFlatten) =>
|
|
106
|
-
flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten)
|
|
103
|
+
return arr.reduce((flat, toFlatten) => {
|
|
104
|
+
return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
|
|
105
|
+
}, []);
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
const forceEndDevice = flatten(
|
|
110
109
|
['QBKG03LM', 'QBKG04LM', 'ZNMS13LM', 'ZNMS12LM']
|
|
111
|
-
.map(model => zigbeeHerdsmanConverters.devices.find((d) => d.model === model))
|
|
112
|
-
.map(mappedModel => mappedModel.zigbeeModel));
|
|
110
|
+
.map((model) => zigbeeHerdsmanConverters.devices.find((d) => d.model === model))
|
|
111
|
+
.map((mappedModel) => mappedModel.zigbeeModel));
|
|
113
112
|
|
|
114
113
|
// Xiaomi uses 4151 and 4447 (lumi.plug) as manufacturer ID.
|
|
115
114
|
const xiaomiManufacturerID = [4151, 4447];
|
|
@@ -118,7 +117,7 @@ const ikeaTradfriManufacturerID = [4476];
|
|
|
118
117
|
function sanitizeImageParameter(parameter) {
|
|
119
118
|
const replaceByDash = [/\?/g, /&/g, /[^a-z\d\-_./:]/gi, /[/]/gi];
|
|
120
119
|
let sanitized = parameter;
|
|
121
|
-
replaceByDash.forEach(r => sanitized = sanitized.replace(r, '-'));
|
|
120
|
+
replaceByDash.forEach((r) => sanitized = sanitized.replace(r, '-'));
|
|
122
121
|
return sanitized;
|
|
123
122
|
}
|
|
124
123
|
|
|
@@ -133,7 +132,7 @@ function getDeviceIcon(definition) {
|
|
|
133
132
|
return icon;
|
|
134
133
|
}
|
|
135
134
|
|
|
136
|
-
exports.secondsToMilliseconds = seconds => seconds * 1000;
|
|
135
|
+
exports.secondsToMilliseconds = (seconds) => seconds * 1000;
|
|
137
136
|
exports.bulbLevelToAdapterLevel = bulbLevelToAdapterLevel;
|
|
138
137
|
exports.adapterLevelToBulbLevel = adapterLevelToBulbLevel;
|
|
139
138
|
exports.bytesArrayToWordArray = bytesArrayToWordArray;
|
|
@@ -142,11 +141,11 @@ exports.miredKelvinConversion = miredKelvinConversion;
|
|
|
142
141
|
exports.decimalToHex = decimalToHex;
|
|
143
142
|
exports.getZbId = getZbId;
|
|
144
143
|
exports.getAdId = getAdId;
|
|
145
|
-
exports.isRouter = device => device.type === 'Router' && !forceEndDevice.includes(device.modelID);
|
|
146
|
-
exports.isBatteryPowered = device => device.powerSource && device.powerSource === 'Battery';
|
|
147
|
-
exports.isXiaomiDevice = device =>
|
|
148
|
-
device.modelID !== 'lumi.router' &&
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
exports.isIkeaTradfriDevice = device => ikeaTradfriManufacturerID.includes(device.manufacturerID);
|
|
152
|
-
exports.getDeviceIcon
|
|
144
|
+
exports.isRouter = (device) => device.type === 'Router' && !forceEndDevice.includes(device.modelID);
|
|
145
|
+
exports.isBatteryPowered = (device) => device.powerSource && device.powerSource === 'Battery';
|
|
146
|
+
exports.isXiaomiDevice = (device) => {
|
|
147
|
+
return device.modelID !== 'lumi.router' && xiaomiManufacturerID.includes(device.manufacturerID) &&
|
|
148
|
+
(!device.manufacturerName || !device.manufacturerName.startsWith('Trust'));
|
|
149
|
+
};
|
|
150
|
+
exports.isIkeaTradfriDevice = (device) => ikeaTradfriManufacturerID.includes(device.manufacturerID);
|
|
151
|
+
exports.getDeviceIcon = getDeviceIcon;
|
package/lib/zbBaseExtension.js
CHANGED
|
@@ -14,18 +14,18 @@ class BaseExtension {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
error(message, data) {
|
|
17
|
-
this.zigbee.error(
|
|
17
|
+
this.zigbee.error(this.name + ':' + message, data);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
warn(message, data) {
|
|
21
|
-
this.zigbee.warn(
|
|
21
|
+
this.zigbee.warn(this.name + ':' + message, data);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
debug(message, data) {
|
|
25
25
|
if (this.elevate_debug)
|
|
26
|
-
this.zigbee.warn(
|
|
26
|
+
this.zigbee.warn('DE ' + this.name + ':' + message, data);
|
|
27
27
|
else
|
|
28
|
-
this.zigbee.debug(
|
|
28
|
+
this.zigbee.debug(this.name + ':' + message, data);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
sendError(error, message) {
|
package/lib/zbDelayedAction.js
CHANGED
|
@@ -8,11 +8,12 @@ class DelayedAction extends BaseExtension {
|
|
|
8
8
|
|
|
9
9
|
this.actions = {};
|
|
10
10
|
this.zigbee.delayAction = this.delayAction.bind(this);
|
|
11
|
-
this.name =
|
|
11
|
+
this.name = "DelayedAction";
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
setOptions(options) {
|
|
15
|
-
|
|
15
|
+
if (typeof(options) != 'object') return false;
|
|
16
|
+
return true;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
|
|
@@ -29,7 +30,11 @@ class DelayedAction extends BaseExtension {
|
|
|
29
30
|
// return false;
|
|
30
31
|
// }
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
if (device.interviewing === true) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return true;
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
async onZigbeeStarted() {
|
|
@@ -92,7 +97,10 @@ class DelayedAction extends BaseExtension {
|
|
|
92
97
|
}
|
|
93
98
|
const foundDev = await this.zigbee.getDevice(device.ieeeAddr);
|
|
94
99
|
if (!foundDev) {
|
|
95
|
-
this.debug(
|
|
100
|
+
this.debug(
|
|
101
|
+
`No found device ${device.ieeeAddr} ${device.modelID}, ` +
|
|
102
|
+
`for doAction`
|
|
103
|
+
);
|
|
96
104
|
delete this.actions[device.ieeeAddr];
|
|
97
105
|
return;
|
|
98
106
|
}
|
|
@@ -112,7 +120,7 @@ class DelayedAction extends BaseExtension {
|
|
|
112
120
|
try {
|
|
113
121
|
// do action
|
|
114
122
|
await actionDef.action(device);
|
|
115
|
-
this.info(`Do action
|
|
123
|
+
this.info(`Do action succesfully ${device.ieeeAddr} ${device.modelID}`);
|
|
116
124
|
toDelete.push(actionDef);
|
|
117
125
|
} catch (error) {
|
|
118
126
|
this.sendError(error);
|
|
@@ -44,77 +44,65 @@ class DeviceAvailability extends BaseExtension {
|
|
|
44
44
|
// force publish availability for new devices
|
|
45
45
|
this.zigbee.on('new', (entity) => {
|
|
46
46
|
// wait for 1s for creating device states
|
|
47
|
-
setTimeout(() =>
|
|
48
|
-
this.publishAvailability(entity.device, true, true)
|
|
47
|
+
setTimeout(() => {
|
|
48
|
+
this.publishAvailability(entity.device, true, true);
|
|
49
|
+
}, 1000);
|
|
49
50
|
});
|
|
50
51
|
this.startDevicePingQueue = []; // simple fifo array for starting device pings
|
|
51
52
|
this.startDevicePingTimeout = null; // handle for the timeout which empties the queue
|
|
52
53
|
this.startDevicePingDelay = 200; // 200 ms delay between starting the ping timeout
|
|
53
|
-
this.name =
|
|
54
|
+
this.name = "DeviceAvailability";
|
|
54
55
|
this.elevate_debug = false;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
setOptions(options) {
|
|
58
|
-
if (typeof
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (options.
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
if (options.disableForcedPing) {
|
|
65
|
-
this.forced_ping = false;
|
|
66
|
-
}
|
|
67
|
-
if (typeof options.pingTimeout === 'number') {
|
|
68
|
-
this.availability_timeout = Math.min(60,options.pingTimeout);
|
|
69
|
-
}
|
|
70
|
-
if (typeof options.pingCount === 'number') {
|
|
71
|
-
this.max_ping = Math.min(2, options.pingCount);
|
|
72
|
-
}
|
|
59
|
+
if (typeof(options) != 'object') return false;
|
|
60
|
+
if (options.disableActivePing) this.active_ping = false;
|
|
61
|
+
if (options.disableForcedPing) this.forced_ping = false;
|
|
62
|
+
if (typeof(options.pingTimeout)=='number') this.availability_timeout = Math.min(60,options.pingTimeout);
|
|
63
|
+
if (typeof(options.pingCount)=='number') this.max_ping = Math.min(2, options.pingCount);
|
|
73
64
|
return true;
|
|
74
65
|
}
|
|
75
66
|
|
|
76
67
|
isPingable(device) {
|
|
77
68
|
if (this.active_ping)
|
|
78
69
|
{
|
|
79
|
-
if (this.forced_ping && forcedPingable.find(d => d && d.hasOwnProperty('zigbeeModel') && d.zigbeeModel.includes(device.modelID))) {
|
|
70
|
+
if (this.forced_ping && forcedPingable.find((d) => d && d.hasOwnProperty('zigbeeModel') && d.zigbeeModel.includes(device.modelID))) {
|
|
80
71
|
return true;
|
|
81
72
|
}
|
|
82
73
|
|
|
83
|
-
|
|
74
|
+
const result = utils.isRouter(device) && !utils.isBatteryPowered(device);
|
|
75
|
+
return result;
|
|
84
76
|
}
|
|
85
77
|
return false;
|
|
86
78
|
}
|
|
87
79
|
|
|
88
80
|
async getAllPingableDevices() {
|
|
89
81
|
const clients = await this.zigbee.getClients();
|
|
90
|
-
return clients.filter(d => this.isPingable(d));
|
|
82
|
+
return clients.filter((d) => this.isPingable(d));
|
|
91
83
|
}
|
|
92
84
|
|
|
93
85
|
async registerDevicePing(device, entity) {
|
|
94
|
-
this.debug(
|
|
86
|
+
this.debug('register device Ping for ' + JSON.stringify(device.ieeeAddr));
|
|
95
87
|
this.forcedNonPingable[device.ieeeAddr] = false;
|
|
96
88
|
// this.warn(`Called registerDevicePing for '${device}' of '${entity}'`);
|
|
97
|
-
if (!this.isPingable(device))
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
89
|
+
if (!this.isPingable(device)) return;
|
|
100
90
|
// ensure we do not already have this device in the queue
|
|
101
|
-
// TODO: Following does not work, may be `if (this.startDevicePingQueue.find(item => item && item.device === device)) { return; }`
|
|
102
91
|
this.startDevicePingQueue.forEach(item => {
|
|
103
|
-
if (item && item.device == device)
|
|
92
|
+
if (item && item.device == device)
|
|
104
93
|
return;
|
|
105
|
-
}
|
|
106
94
|
});
|
|
107
95
|
this.number_of_registered_devices++;
|
|
108
96
|
this.availability_timeout = Math.max(Math.min(this.number_of_registered_devices * AverageTimeBetweenPings,MaxAvailabilityTimeout ),MinAvailabilityTimeout);
|
|
109
|
-
this.startDevicePingQueue.push({device, entity});
|
|
110
|
-
if (this.startDevicePingTimeout == null)
|
|
111
|
-
this.startDevicePingTimeout = setTimeout(async() =>
|
|
112
|
-
await this.startDevicePing()
|
|
113
|
-
|
|
97
|
+
this.startDevicePingQueue.push({device:device, entity:entity});
|
|
98
|
+
if (this.startDevicePingTimeout == null)
|
|
99
|
+
this.startDevicePingTimeout = setTimeout(async() => {
|
|
100
|
+
await this.startDevicePing();
|
|
101
|
+
}, this.startDevicePingDelay);
|
|
114
102
|
}
|
|
115
103
|
|
|
116
104
|
async deregisterDevicePing(device) {
|
|
117
|
-
this.info(
|
|
105
|
+
this.info('deregister device Ping for deactivated device ' + JSON.stringify(device.ieeeAddr));
|
|
118
106
|
this.forcedNonPingable[device.ieeeAddr] = true;
|
|
119
107
|
if (this.timers[device.ieeeAddr]) {
|
|
120
108
|
clearTimeout(this.timers[device.ieeeAddr]);
|
|
@@ -126,8 +114,9 @@ class DeviceAvailability extends BaseExtension {
|
|
|
126
114
|
this.startDevicePingTimeout = null;
|
|
127
115
|
const item = this.startDevicePingQueue.shift();
|
|
128
116
|
if (this.startDevicePingQueue.length >0) {
|
|
129
|
-
this.startDevicePingTimeout = setTimeout(async() =>
|
|
130
|
-
await this.startDevicePing()
|
|
117
|
+
this.startDevicePingTimeout = setTimeout(async() => {
|
|
118
|
+
await this.startDevicePing();
|
|
119
|
+
}, this.startDevicePingDelay);
|
|
131
120
|
}
|
|
132
121
|
if (item && item.hasOwnProperty('device')) {
|
|
133
122
|
this.handleIntervalPingable(item.device, item.entity);
|
|
@@ -142,13 +131,15 @@ class DeviceAvailability extends BaseExtension {
|
|
|
142
131
|
const clients = await this.zigbee.getClients();
|
|
143
132
|
// this.warn('onZigbeeStarted called');
|
|
144
133
|
for (const device of clients) {
|
|
134
|
+
|
|
145
135
|
if (this.isPingable(device)) {
|
|
146
136
|
// this.setTimerPingable(device);
|
|
147
137
|
} else {
|
|
148
138
|
// this.warn(`Setting '${device.ieeeAddr}' as available - battery driven`);
|
|
149
139
|
this.publishAvailability(device, true);
|
|
150
|
-
this.timers[device.ieeeAddr] = setInterval(() =>
|
|
151
|
-
this.handleIntervalNotPingable(device)
|
|
140
|
+
this.timers[device.ieeeAddr] = setInterval(() => {
|
|
141
|
+
this.handleIntervalNotPingable(device);
|
|
142
|
+
},utils.secondsToMilliseconds(this.availability_timeout));
|
|
152
143
|
}
|
|
153
144
|
}
|
|
154
145
|
}
|
|
@@ -163,8 +154,8 @@ class DeviceAvailability extends BaseExtension {
|
|
|
163
154
|
if (this.isPingable(device)) {
|
|
164
155
|
let pingCount = this.ping_counters[device.ieeeAddr];
|
|
165
156
|
if (pingCount === undefined) {
|
|
166
|
-
this.ping_counters[device.ieeeAddr] = {failed: 0, reported: 0};
|
|
167
|
-
pingCount = {failed: 0, reported: 0};
|
|
157
|
+
this.ping_counters[device.ieeeAddr] = { failed: 0, reported: 0};
|
|
158
|
+
pingCount = { failed: 0, reported: 0};
|
|
168
159
|
}
|
|
169
160
|
|
|
170
161
|
// first see if we can "ping" the device by reading a Status
|
|
@@ -194,22 +185,26 @@ class DeviceAvailability extends BaseExtension {
|
|
|
194
185
|
this.ping_counters[device.ieeeAddr].failed = 0;
|
|
195
186
|
} catch (error) {
|
|
196
187
|
this.publishAvailability(device, false);
|
|
197
|
-
if (pingCount.failed++ <= this.max_ping)
|
|
188
|
+
if (pingCount.failed++ <= this.max_ping)
|
|
189
|
+
{
|
|
198
190
|
if (pingCount.failed < 2 && pingCount.reported < this.max_ping) {
|
|
199
191
|
this.warn(`Failed to ping ${ieeeAddr} ${device.modelID}`);
|
|
200
192
|
pingCount.reported++;
|
|
201
|
-
}
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
202
195
|
this.debug(`Failed to ping ${ieeeAddr} ${device.modelID} on ${pingCount} consecutive attempts`);
|
|
203
196
|
}
|
|
204
197
|
this.setTimerPingable(device, pingCount.failed);
|
|
205
198
|
this.ping_counters[device.ieeeAddr]= pingCount;
|
|
206
|
-
}
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
207
201
|
this.warn(`Stopping to ping ${ieeeAddr} ${device.modelID} after ${pingCount.failed} ping attempts`);
|
|
208
202
|
}
|
|
209
203
|
}
|
|
210
204
|
}
|
|
211
205
|
}
|
|
212
206
|
|
|
207
|
+
|
|
213
208
|
async handleIntervalNotPingable(device) {
|
|
214
209
|
const entity = await this.zigbee.resolveEntity(device.ieeeAddr);
|
|
215
210
|
if (!entity || !device.lastSeen) {
|
|
@@ -229,8 +224,9 @@ class DeviceAvailability extends BaseExtension {
|
|
|
229
224
|
if (this.timers[device.ieeeAddr]) {
|
|
230
225
|
clearTimeout(this.timers[device.ieeeAddr]);
|
|
231
226
|
}
|
|
232
|
-
this.timers[device.ieeeAddr] = setTimeout(async() =>
|
|
233
|
-
await this.handleIntervalPingable(device)
|
|
227
|
+
this.timers[device.ieeeAddr] = setTimeout(async() => {
|
|
228
|
+
await this.handleIntervalPingable(device);
|
|
229
|
+
}, utils.secondsToMilliseconds(this.availability_timeout * factor));
|
|
234
230
|
}
|
|
235
231
|
|
|
236
232
|
async stop() {
|
|
@@ -238,7 +234,7 @@ class DeviceAvailability extends BaseExtension {
|
|
|
238
234
|
clearTimeout(timer);
|
|
239
235
|
}
|
|
240
236
|
const clients = await this.zigbee.getClients();
|
|
241
|
-
clients.forEach(device => this.publishAvailability(device, false));
|
|
237
|
+
clients.forEach((device) => this.publishAvailability(device, false));
|
|
242
238
|
}
|
|
243
239
|
|
|
244
240
|
async onReconnect(device) {
|
|
@@ -294,7 +290,8 @@ class DeviceAvailability extends BaseExtension {
|
|
|
294
290
|
const pc = this.ping_counters[device.ieeeAddr];
|
|
295
291
|
if (pc == undefined) {
|
|
296
292
|
this.ping_counters[device.ieeeAddr] = { failed:0, reported:0 };
|
|
297
|
-
}
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
298
295
|
this.ping_counters[device.ieeeAddr].failed++;
|
|
299
296
|
}
|
|
300
297
|
|
package/lib/zbDeviceConfigure.js
CHANGED
|
@@ -10,17 +10,20 @@ const forcedConfigureOnEachStart = [
|
|
|
10
10
|
zigbeeHerdsmanConverters.devices.find((d) => d.model === 'ZK03840')
|
|
11
11
|
];
|
|
12
12
|
|
|
13
|
+
|
|
14
|
+
|
|
13
15
|
class DeviceConfigure extends BaseExtension {
|
|
14
16
|
constructor(zigbee, options) {
|
|
15
17
|
super(zigbee, options);
|
|
16
18
|
|
|
17
19
|
this.configuring = new Set();
|
|
18
20
|
this.attempts = {};
|
|
19
|
-
this.name =
|
|
21
|
+
this.name = "DeviceConfigure";
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
setOptions(options) {
|
|
23
|
-
|
|
25
|
+
if (typeof(options) != 'object') return false;
|
|
26
|
+
return true;
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
shouldConfigure(device, mappedDevice) {
|
|
@@ -34,8 +37,11 @@ class DeviceConfigure extends BaseExtension {
|
|
|
34
37
|
zigbeeHerdsmanConverters.getConfigureKey(mappedDevice)) {
|
|
35
38
|
return false;
|
|
36
39
|
}
|
|
40
|
+
if (device.interviewing === true) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
37
43
|
|
|
38
|
-
return
|
|
44
|
+
return true;
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
async onZigbeeStarted() {
|
|
@@ -47,7 +53,7 @@ class DeviceConfigure extends BaseExtension {
|
|
|
47
53
|
|
|
48
54
|
if (forcedConfigureOnEachStart.find((d) => d && d.hasOwnProperty('zigbeeModel') && d.zigbeeModel.includes(device.modelID))) {
|
|
49
55
|
this.debug(`DeviceConfigure ${device.ieeeAddr} ${device.modelID} forced by adapter config`);
|
|
50
|
-
device.meta.configured = -1; // Force a
|
|
56
|
+
device.meta.configured = -1; // Force a reconfigure for this device
|
|
51
57
|
}
|
|
52
58
|
if (this.shouldConfigure(device, mappedDevice)) {
|
|
53
59
|
this.debug(`DeviceConfigure ${device.ieeeAddr} ${device.modelID} needed`);
|
|
@@ -58,7 +64,9 @@ class DeviceConfigure extends BaseExtension {
|
|
|
58
64
|
}
|
|
59
65
|
} catch (error) {
|
|
60
66
|
this.sendError(error);
|
|
61
|
-
this.error(
|
|
67
|
+
this.error(
|
|
68
|
+
`Failed to DeviceConfigure.onZigbeeStarted (${error.stack})`,
|
|
69
|
+
);
|
|
62
70
|
}
|
|
63
71
|
}
|
|
64
72
|
|
|
@@ -70,7 +78,9 @@ class DeviceConfigure extends BaseExtension {
|
|
|
70
78
|
}
|
|
71
79
|
} catch (error) {
|
|
72
80
|
this.sendError(error);
|
|
73
|
-
this.error(
|
|
81
|
+
this.error(
|
|
82
|
+
`Failed to DeviceConfigure.onZigbeeEvent (${error.stack})`,
|
|
83
|
+
);
|
|
74
84
|
}
|
|
75
85
|
}
|
|
76
86
|
|
|
@@ -85,7 +95,9 @@ class DeviceConfigure extends BaseExtension {
|
|
|
85
95
|
}
|
|
86
96
|
} catch (error) {
|
|
87
97
|
this.sendError(error);
|
|
88
|
-
this.error(
|
|
98
|
+
this.error(
|
|
99
|
+
`Failed to DeviceConfigure.onDeviceRemove (${error.stack})`,
|
|
100
|
+
);
|
|
89
101
|
}
|
|
90
102
|
}
|
|
91
103
|
|
package/lib/zbDeviceEvent.js
CHANGED
|
@@ -6,9 +6,10 @@ const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
|
|
|
6
6
|
class DeviceEvent extends BaseExtension {
|
|
7
7
|
constructor(zigbee, options) {
|
|
8
8
|
super(zigbee, options);
|
|
9
|
-
this.name =
|
|
9
|
+
this.name = "DeviceEvent";
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
|
|
12
13
|
async onZigbeeStarted() {
|
|
13
14
|
for (const device of await this.zigbee.getClients()) {
|
|
14
15
|
this.callOnEvent(device, 'start', {});
|
|
@@ -16,8 +17,8 @@ class DeviceEvent extends BaseExtension {
|
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
setOptions(options) {
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
if (typeof(options) != 'object') return false;
|
|
21
|
+
return true;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
onZigbeeEvent(data, mappedDevice) {
|