iobroker.zigbee 2.0.1 → 2.0.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/README.md +77 -36
- package/admin/admin.js +211 -19
- package/admin/img/philips_hue_lom001.png +0 -0
- package/admin/tab_m.html +13 -8
- package/docs/de/readme.md +21 -28
- package/docs/tutorial/groups-1.png +0 -0
- package/docs/tutorial/groups-2.png +0 -0
- package/docs/tutorial/tab-dev-1.png +0 -0
- package/io-package.json +30 -51
- package/lib/DeviceDebug.js +80 -0
- package/lib/commands.js +24 -3
- package/lib/developer.js +0 -0
- package/lib/devices.js +14 -4
- package/lib/exposes.js +46 -46
- package/lib/groups.js +6 -8
- package/lib/localConfig.js +11 -6
- package/lib/ota.js +11 -10
- package/lib/statescontroller.js +314 -101
- package/lib/utils.js +4 -2
- package/lib/zbDeviceAvailability.js +3 -9
- package/lib/zbDeviceConfigure.js +68 -34
- package/lib/zigbeecontroller.js +50 -14
- package/main.js +168 -203
- package/package.json +5 -5
package/lib/groups.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const json = require('iobroker.zigbee/lib/json');
|
|
4
4
|
const statesMapping = require('./devices');
|
|
5
|
-
const { numberWithinRange } = require('zigbee-herdsman-converters/lib/utils');
|
|
6
5
|
const idRegExp = new RegExp(/group_(\d+)/);
|
|
7
6
|
|
|
8
7
|
|
|
@@ -168,7 +167,7 @@ class Groups {
|
|
|
168
167
|
for (const gpid of groups[epid]) {
|
|
169
168
|
const gpidn = parseInt(gpid);
|
|
170
169
|
if (gpidn < 0) {
|
|
171
|
-
this.
|
|
170
|
+
this.debug(`calling removeDevFromGroup with ${sysid}, ${-gpidn}, ${epid}` );
|
|
172
171
|
const response = await this.zbController.removeDevFromGroup(sysid, (-gpidn), epid);
|
|
173
172
|
if (response && response.error) {
|
|
174
173
|
errors.push(response.error);
|
|
@@ -176,7 +175,7 @@ class Groups {
|
|
|
176
175
|
}
|
|
177
176
|
const icon = this.stController.getDefaultGroupIcon(-gpidn)
|
|
178
177
|
} else if (gpidn > 0) {
|
|
179
|
-
this.
|
|
178
|
+
this.debug(`calling addDevToGroup with ${sysid}, ${gpidn}, ${epid}` );
|
|
180
179
|
const response = await this.zbController.addDevToGroup(sysid, (gpidn), epid);
|
|
181
180
|
if (response && response.error) {
|
|
182
181
|
errors.push(response.error);
|
|
@@ -233,7 +232,7 @@ class Groups {
|
|
|
233
232
|
throw error;
|
|
234
233
|
}
|
|
235
234
|
if (result.unread.length > 0) {
|
|
236
|
-
this.
|
|
235
|
+
this.debug(`unread ${stateDesc.id} change for group members ${JSON.stringify(result.unread)}`);
|
|
237
236
|
}
|
|
238
237
|
}
|
|
239
238
|
|
|
@@ -254,11 +253,10 @@ class Groups {
|
|
|
254
253
|
if (message.remove) {
|
|
255
254
|
for (const member of message.remove) {
|
|
256
255
|
const response = await this.zbController.removeDevFromGroup(member.id, id, member.ep);
|
|
257
|
-
this.
|
|
256
|
+
this.debug('trying to remove ' + member.id + (member.ep ? '.'+member.ep : '') + ' ' + ' from group ' + message.id + ' response is '+JSON.stringify(response));
|
|
258
257
|
}
|
|
259
258
|
}
|
|
260
259
|
if (icon.match(/img\/group_\d+\.png/g)) {
|
|
261
|
-
this.warn('.');
|
|
262
260
|
icon = await this.zbController.rebuildGroupIcon(group);
|
|
263
261
|
}
|
|
264
262
|
} catch (e) {
|
|
@@ -270,7 +268,7 @@ class Groups {
|
|
|
270
268
|
this.warn(`rename group name ${name}, id ${id}, icon ${icon} remove ${JSON.stringify(message.removeMembers)}`);
|
|
271
269
|
const group = await this.adapter.getObjectAsync(id);
|
|
272
270
|
if (!group) {
|
|
273
|
-
this.
|
|
271
|
+
this.debug('group object doesnt exist ')
|
|
274
272
|
// assume we have to create the group
|
|
275
273
|
this.adapter.setObjectNotExists(id, {
|
|
276
274
|
type: 'device',
|
|
@@ -301,7 +299,7 @@ class Groups {
|
|
|
301
299
|
});
|
|
302
300
|
}
|
|
303
301
|
else {
|
|
304
|
-
this.
|
|
302
|
+
this.debug('group object exists');
|
|
305
303
|
this.adapter.extendObject(id, {common: {name, type: 'group', icon: icon}});
|
|
306
304
|
}
|
|
307
305
|
}
|
package/lib/localConfig.js
CHANGED
|
@@ -179,13 +179,13 @@ class localConfig extends EventEmitter {
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
getOverrideData(target, isGlobal) {
|
|
182
|
-
const base = (isGlobal ? this.localData.by_model : this.localData.
|
|
183
|
-
if (base.hasOwnProperty(target)) return base
|
|
182
|
+
const base = (isGlobal ? this.localData.by_model : this.localData.by_id);
|
|
183
|
+
if (base.hasOwnProperty(target)) return base[target];
|
|
184
184
|
return {};
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
setOverrideData(target, isGlobal, data) {
|
|
188
|
-
const base = (isGlobal ? this.localData.by_model : this.localData.
|
|
188
|
+
const base = (isGlobal ? this.localData.by_model : this.localData.by_id);
|
|
189
189
|
if (typeof target != 'string') {
|
|
190
190
|
this.error('illegal target for override data: '+JSON.stringify(target));
|
|
191
191
|
return;
|
|
@@ -203,7 +203,7 @@ class localConfig extends EventEmitter {
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
getOverridesWithKey(key, isGlobal) {
|
|
206
|
-
const base = (isGlobal ? this.localData.by_model : this.localData.
|
|
206
|
+
const base = (isGlobal ? this.localData.by_model : this.localData.by_id);
|
|
207
207
|
const rv = [];
|
|
208
208
|
for(const prop in base) {
|
|
209
209
|
if (base[prop].hasOwnProperty(key)) {
|
|
@@ -213,8 +213,13 @@ class localConfig extends EventEmitter {
|
|
|
213
213
|
return rv;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
getOverrideWithKey(target, key, isGlobal) {
|
|
217
|
+
const targetdata = this.getOverrideData(target, isGlobal);
|
|
218
|
+
if (targetdata && targetdata.hasOwnProperty(key)) return targetdata[key];
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
|
|
216
222
|
async updateFromDeviceNames() {
|
|
217
|
-
this.warn('updateFromDeviceNames');
|
|
218
223
|
const fn = this.adapter.expandFileName('dev_names').replace('.', '_').concat('.json');
|
|
219
224
|
fs.readFile(fn, (err, content) => {
|
|
220
225
|
if (!err) {
|
|
@@ -280,7 +285,7 @@ class localConfig extends EventEmitter {
|
|
|
280
285
|
const files= fs.readdirSync(_path, {withFileTypes: true, recursive: true}).filter(item => (!item.isDirectory() && item.name.endsWith('.png')));
|
|
281
286
|
files.forEach((item) => {
|
|
282
287
|
const fn = path.join(item.parentPath, item.name);
|
|
283
|
-
rv.push({file: fn, name: item.name, data: fs.readFileSync(path.join(item.parentPath, item.name), 'base64')})
|
|
288
|
+
rv.push({file: fn, name: item.name, data: fs.readFileSync(path.join(item.parentPath, item.name), 'base64'), isBase64:true});
|
|
284
289
|
});
|
|
285
290
|
//this.warn('enumerateImages for ' + _path + ' is ' + JSON.stringify(rv));
|
|
286
291
|
}
|
package/lib/ota.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const getZbId = require('./utils').getZbId;
|
|
4
|
+
const zhc_ota = require('zigbee-herdsman-converters').ota;
|
|
4
5
|
|
|
5
6
|
class Ota {
|
|
6
7
|
constructor(adapter) {
|
|
@@ -24,7 +25,7 @@ class Ota {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
warn(msg) {
|
|
27
|
-
this.adapter.log.
|
|
28
|
+
this.adapter.log.warn(msg);
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
error(msg) {
|
|
@@ -54,7 +55,7 @@ class Ota {
|
|
|
54
55
|
async checkOtaAvail(obj) {
|
|
55
56
|
const device = await this.getDeviceForMessage(obj);
|
|
56
57
|
if (!device) {
|
|
57
|
-
this.
|
|
58
|
+
this.info(`Device ${obj.message.devId} is unavailable`);
|
|
58
59
|
this.adapter.sendTo(obj.from, obj.command, {
|
|
59
60
|
status: 'fail',
|
|
60
61
|
device: getZbId(obj.message.devId),
|
|
@@ -63,13 +64,13 @@ class Ota {
|
|
|
63
64
|
return;
|
|
64
65
|
}
|
|
65
66
|
if (this.inProgress.has(device.device.ieeeAddr)) {
|
|
66
|
-
this.
|
|
67
|
+
this.info(`Update or check already in progress for '${device.name}', skipping...`);
|
|
67
68
|
return;
|
|
68
69
|
}
|
|
69
70
|
// do not attempt update for a device which has been deactivated or is unavailable
|
|
70
71
|
const stateObj = await this.adapter.getObjectAsync(obj.message.devId);
|
|
71
72
|
if (stateObj && stateObj.common && stateObj.common.deactivated) {
|
|
72
|
-
this.
|
|
73
|
+
this.info(`Device ${obj.message.devId} is deactivated, skipping...`);
|
|
73
74
|
this.adapter.sendTo(obj.from, obj.command, {
|
|
74
75
|
status: 'fail',
|
|
75
76
|
device: getZbId(obj.message.devId),
|
|
@@ -80,7 +81,7 @@ class Ota {
|
|
|
80
81
|
const availablestate = await this.adapter.getStateAsync(`${obj.message.devId.replace(this.namespace + '.', '')}.available`);
|
|
81
82
|
const lqi = await this.adapter.getStateAsync(`${obj.message.devId.replace(this.namespace + '.', '')}.link_quality`);
|
|
82
83
|
if ((availablestate && (!availablestate.val)) || (lqi && lqi.val < 1)) {
|
|
83
|
-
this.
|
|
84
|
+
this.info(`Device ${obj.message.devId} is marked unavailable, skipping...`);
|
|
84
85
|
this.adapter.sendTo(obj.from, obj.command, {
|
|
85
86
|
status: 'fail',
|
|
86
87
|
device: getZbId(obj.message.devId),
|
|
@@ -94,10 +95,10 @@ class Ota {
|
|
|
94
95
|
this.debug(`Checking if firmware update is available for ${device.name}`);
|
|
95
96
|
|
|
96
97
|
if (device && device.mapped.ota) {
|
|
97
|
-
const available = await
|
|
98
|
+
const available = await zhc_ota.isUpdateAvailable(device.device, device.mapped.ota, undefined, false);
|
|
98
99
|
result.status = available.available ? 'available' : 'not_available';
|
|
99
100
|
if (available.currentFileVersion !== available.otaFileVersion) {
|
|
100
|
-
this.
|
|
101
|
+
this.debug(`current Firmware for ${device.name} is ${available.currentFileVersion} new is ${available.otaFileVersion}`);
|
|
101
102
|
}
|
|
102
103
|
} else {
|
|
103
104
|
result.status = 'not_supported';
|
|
@@ -132,13 +133,13 @@ class Ota {
|
|
|
132
133
|
// do not attempt update for a device which has been deactivated or is unavailable
|
|
133
134
|
const stateObj = await this.adapter.getObjectAsync(obj.message.devId);
|
|
134
135
|
if (stateObj && stateObj.common && stateObj.common.deactivated) {
|
|
135
|
-
this.
|
|
136
|
+
this.info(`Device ${obj.message.devId} is deactivated, skipping...`);
|
|
136
137
|
return;
|
|
137
138
|
}
|
|
138
139
|
const availablestate = await this.adapter.getStateAsync(`${obj.message.devId.replace(this.namespace + '.', '')}.available`);
|
|
139
140
|
const lqi = await this.adapter.getStateAsync(`${obj.message.devId.replace(this.namespace + '.', '')}.link_quality`);
|
|
140
141
|
if ((availablestate && (!availablestate.val)) || (lqi && lqi.val < 1)) {
|
|
141
|
-
this.
|
|
142
|
+
this.info(`Device ${obj.message.devId} is marked unavailable, skipping...`);
|
|
142
143
|
return;
|
|
143
144
|
}
|
|
144
145
|
this.inProgress.add(device.device.ieeeAddr);
|
|
@@ -155,7 +156,7 @@ class Ota {
|
|
|
155
156
|
};
|
|
156
157
|
|
|
157
158
|
const from_ = await this.readSoftwareBuildIDAndDateCode(device.device, false);
|
|
158
|
-
const fileVersion = await
|
|
159
|
+
const fileVersion = await zhc_ota.update(device.device, device.mapped.ota, false, onProgress)
|
|
159
160
|
const to = await this.readSoftwareBuildIDAndDateCode(device.device, true);
|
|
160
161
|
const [fromS, toS] = [JSON.stringify(from_), JSON.stringify(to)];
|
|
161
162
|
result.status = 'success';
|