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/backup.js
CHANGED
|
@@ -49,7 +49,7 @@ class Backup {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
async configure(zigbeeOptions) {
|
|
52
|
+
async configure (zigbeeOptions) {
|
|
53
53
|
this.zigbeeOptions = zigbeeOptions;
|
|
54
54
|
this.backup(zigbeeOptions);
|
|
55
55
|
const allBackupFiles = this.listBackupsFiles(zigbeeOptions);
|
|
@@ -121,7 +121,7 @@ class Backup {
|
|
|
121
121
|
delBackupsFiles(options, files) {
|
|
122
122
|
const arr = files.length;
|
|
123
123
|
if (arr > 10) {
|
|
124
|
-
this.info('delete old Backup files. keep only last 10')
|
|
124
|
+
this.info('delete old Backup files. keep only last 10')
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
for (let i = 10; i < files.length; i++) {
|
package/lib/binding.js
CHANGED
|
@@ -34,7 +34,7 @@ class Binding {
|
|
|
34
34
|
debug(msg) {
|
|
35
35
|
this.adapter.log.debug(msg);
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
warn(msg) {
|
|
39
39
|
this.adapter.log.warn(msg);
|
|
40
40
|
}
|
|
@@ -86,23 +86,21 @@ class Binding {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
extractDeviceId(stateId) {
|
|
89
|
-
if (stateId)
|
|
89
|
+
if (stateId)
|
|
90
90
|
return stateId.replace(`${this.adapter.namespace}.`, '');
|
|
91
|
-
}
|
|
92
91
|
return '';
|
|
93
92
|
}
|
|
94
93
|
|
|
95
94
|
getBindEp(ep) {
|
|
96
|
-
if (ep)
|
|
95
|
+
if (ep)
|
|
97
96
|
return parseInt(ep.split('_')[0]);
|
|
98
|
-
}
|
|
99
97
|
|
|
100
98
|
this.warn(`getBindEp called with illegal ep: ${safeJsonStringify(ep)}`);
|
|
101
99
|
return 0;
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
getBindCl(ep) {
|
|
105
|
-
return ep.indexOf('_') > 0 ? ep.split('_')[1] : null;
|
|
103
|
+
return (ep.indexOf('_') > 0) ? ep.split('_')[1] : null;
|
|
106
104
|
}
|
|
107
105
|
|
|
108
106
|
async doBindUnbind(type, bind_source, bind_source_ep, bind_target, bind_target_ep, callback) {
|
|
@@ -125,7 +123,8 @@ class Binding {
|
|
|
125
123
|
|
|
126
124
|
if (!source || !target) {
|
|
127
125
|
this.error('Devices not found');
|
|
128
|
-
|
|
126
|
+
if (callback) callback('Devices not found');
|
|
127
|
+
return;
|
|
129
128
|
}
|
|
130
129
|
const sourceName = source.name;
|
|
131
130
|
const targetName = target.name;
|
|
@@ -145,7 +144,8 @@ class Binding {
|
|
|
145
144
|
}
|
|
146
145
|
if (!found) {
|
|
147
146
|
this.debug(`No bind clusters`);
|
|
148
|
-
|
|
147
|
+
if (callback) callback(`No bind clusters`);
|
|
148
|
+
return;
|
|
149
149
|
} else {
|
|
150
150
|
let ok = true;
|
|
151
151
|
for (const clID of clusters) {
|
|
@@ -171,23 +171,23 @@ class Binding {
|
|
|
171
171
|
`Failed to ${type} cluster '${cluster}' from '${sourceName}' to ` +
|
|
172
172
|
`'${targetName}' (${error})`,
|
|
173
173
|
);
|
|
174
|
-
callback
|
|
174
|
+
if (callback) callback(`Failed to ${type} cluster '${cluster}' from '${sourceName}' to '${targetName}' (${error})`);
|
|
175
175
|
ok = false;
|
|
176
176
|
break;
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
|
-
ok && callback
|
|
180
|
+
if (ok && callback) callback(undefined, id);
|
|
181
181
|
}
|
|
182
182
|
} catch (error) {
|
|
183
183
|
this.error(`Failed to doBindUnbind ${error.stack}`);
|
|
184
|
-
callback
|
|
184
|
+
if (callback) callback(`Failed to doBindUnbind ${error.stack}`);
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
async addBinding(from, command, params, callback) {
|
|
189
189
|
try {
|
|
190
|
-
this.debug(
|
|
190
|
+
this.debug('addBinding message: ' + JSON.stringify(params));
|
|
191
191
|
const bind_source = params.bind_source,
|
|
192
192
|
bind_source_ep = params.bind_source_ep,
|
|
193
193
|
bind_target = params.bind_target,
|
|
@@ -207,8 +207,9 @@ class Binding {
|
|
|
207
207
|
type: 'state',
|
|
208
208
|
common: {name: id},
|
|
209
209
|
}, () => {
|
|
210
|
-
this.adapter.setState(stateId, JSON.stringify(params), true, () =>
|
|
211
|
-
callback()
|
|
210
|
+
this.adapter.setState(stateId, JSON.stringify(params), true, () => {
|
|
211
|
+
callback();
|
|
212
|
+
});
|
|
212
213
|
});
|
|
213
214
|
}
|
|
214
215
|
});
|
|
@@ -220,7 +221,7 @@ class Binding {
|
|
|
220
221
|
|
|
221
222
|
async editBinding(from, command, params, callback) {
|
|
222
223
|
try {
|
|
223
|
-
this.debug(
|
|
224
|
+
this.debug('editBinding message: ' + JSON.stringify(params));
|
|
224
225
|
const old_id = params.id,
|
|
225
226
|
bind_source = params.bind_source,
|
|
226
227
|
bind_source_ep = params.bind_source_ep,
|
|
@@ -228,7 +229,7 @@ class Binding {
|
|
|
228
229
|
bind_target_ep = params.bind_target_ep,
|
|
229
230
|
id = this.getBindingId(bind_source, bind_source_ep, bind_target, bind_target_ep);
|
|
230
231
|
if (old_id !== id) {
|
|
231
|
-
await this.delBinding(from, command, old_id, async err
|
|
232
|
+
await this.delBinding(from, command, old_id, async (err)=>{
|
|
232
233
|
if (err) {
|
|
233
234
|
callback(err);
|
|
234
235
|
} else {
|
|
@@ -241,7 +242,7 @@ class Binding {
|
|
|
241
242
|
await this.doBindUnbind(type , bind_source, bind_source_ep, 'coordinator', '1');
|
|
242
243
|
this.debug('Successfully ' + (type === 'bind' ? 'bound' : 'unbound') + ' Coordinator from ' + bind_source);
|
|
243
244
|
} catch (e) {
|
|
244
|
-
this.error(
|
|
245
|
+
this.error('Could not ' + type + ' Coordinator from ' + bind_source + ': ' + JSON.stringify(e));
|
|
245
246
|
}
|
|
246
247
|
}
|
|
247
248
|
} catch (error) {
|
|
@@ -251,17 +252,17 @@ class Binding {
|
|
|
251
252
|
|
|
252
253
|
async delBinding(from, command, bind_id, callback) {
|
|
253
254
|
try {
|
|
254
|
-
this.debug(
|
|
255
|
+
this.debug('delBinding message: ' + JSON.stringify(bind_id));
|
|
255
256
|
const stateId = `info.${bind_id}`;
|
|
256
257
|
this.adapter.getStateAsync(stateId)
|
|
257
|
-
.then(async stateV => {
|
|
258
|
-
this.debug(
|
|
258
|
+
.then(async (stateV) => {
|
|
259
|
+
this.debug('found state: ' + JSON.stringify(stateV));
|
|
259
260
|
const params = JSON.parse(stateV.val);
|
|
260
261
|
const bind_source = params.bind_source,
|
|
261
262
|
bind_source_ep = params.bind_source_ep,
|
|
262
263
|
bind_target = params.bind_target,
|
|
263
264
|
bind_target_ep = params.bind_target_ep;
|
|
264
|
-
await this.doBindUnbind('unbind', bind_source, bind_source_ep, bind_target, bind_target_ep, async err => {
|
|
265
|
+
await this.doBindUnbind('unbind', bind_source, bind_source_ep, bind_target, bind_target_ep, async (err) => {
|
|
265
266
|
if (err) {
|
|
266
267
|
callback({error: err});
|
|
267
268
|
} else {
|
|
@@ -307,11 +308,11 @@ class Binding {
|
|
|
307
308
|
}
|
|
308
309
|
});
|
|
309
310
|
return Promise.all(chain).then(() => {
|
|
310
|
-
this.debug(
|
|
311
|
+
this.debug('getBinding result: ' + JSON.stringify(binding));
|
|
311
312
|
callback(binding);
|
|
312
313
|
});
|
|
313
314
|
} else {
|
|
314
|
-
this.debug(
|
|
315
|
+
this.debug('getBinding result: ' + JSON.stringify(binding));
|
|
315
316
|
callback(binding);
|
|
316
317
|
}
|
|
317
318
|
});
|
package/lib/colors.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
|
|
3
4
|
const namedColors = {
|
|
4
5
|
mediumvioletred: {
|
|
5
6
|
rgb: '#c71585',
|
|
@@ -423,15 +424,15 @@ const namedColors = {
|
|
|
423
424
|
},
|
|
424
425
|
};
|
|
425
426
|
|
|
426
|
-
function
|
|
427
|
+
function NamedColorToRGBstring(name)
|
|
428
|
+
{
|
|
427
429
|
const lowerName = name.toLowerCase();
|
|
428
|
-
if (namedColors.hasOwnProperty(lowerName))
|
|
429
|
-
return namedColors[lowerName].rgb;
|
|
430
|
-
}
|
|
430
|
+
if (namedColors.hasOwnProperty(lowerName)) return namedColors[lowerName].rgb;
|
|
431
431
|
return '#0088FF';
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
-
function
|
|
434
|
+
function ParseColor(rgbstring)
|
|
435
|
+
{
|
|
435
436
|
if (typeof(rgbstring) === 'string') {
|
|
436
437
|
const lowerName = rgbstring.toLowerCase();
|
|
437
438
|
if (namedColors.hasOwnProperty(lowerName))
|
|
@@ -445,18 +446,15 @@ function parseColor(rgbstring) {
|
|
|
445
446
|
oneColor.b = val % 256;
|
|
446
447
|
return oneColor;
|
|
447
448
|
}
|
|
448
|
-
|
|
449
|
-
return {r: 0,g: 128,b: 255};
|
|
449
|
+
return {r:0,g:128,b:255};
|
|
450
450
|
}
|
|
451
451
|
|
|
452
|
-
function
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
return {r: 0, g: 128, b: 255};
|
|
452
|
+
function NamedColorToRGB(name)
|
|
453
|
+
{
|
|
454
|
+
if (namedColors.hasOwnProperty(name)) return ParseColor(namedColors[name].rgb);
|
|
455
|
+
return {r:0,g:128,b:255};
|
|
458
456
|
}
|
|
459
457
|
|
|
460
|
-
exports.NamedColorToRGB =
|
|
461
|
-
exports.NamedCOlorToRGBString =
|
|
462
|
-
exports.ParseColor =
|
|
458
|
+
exports.NamedColorToRGB = NamedColorToRGB;
|
|
459
|
+
exports.NamedCOlorToRGBString = NamedColorToRGBstring;
|
|
460
|
+
exports.ParseColor = ParseColor;
|
package/lib/commands.js
CHANGED
|
@@ -112,6 +112,7 @@ class Commands {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
|
|
115
116
|
letsPairing(from, command, message, callback) {
|
|
116
117
|
if (this.zbController) {
|
|
117
118
|
let devId = '';
|
|
@@ -122,11 +123,11 @@ class Commands {
|
|
|
122
123
|
this.adapter.logToPairing('Pairing started ' + devId, true);
|
|
123
124
|
|
|
124
125
|
let cTimer = Number(this.adapter.config.countDown);
|
|
125
|
-
if (!this.adapter.config.countDown ||
|
|
126
|
+
if (!this.adapter.config.countDown || cTimer == 0) {
|
|
126
127
|
cTimer = 60;
|
|
127
128
|
}
|
|
128
129
|
|
|
129
|
-
this.zbController.permitJoin(cTimer, devId, err => {
|
|
130
|
+
this.zbController.permitJoin(cTimer, devId, (err) => {
|
|
130
131
|
if (!err) {
|
|
131
132
|
// set pairing mode on
|
|
132
133
|
this.adapter.setState('info.pairingMode', true);
|
|
@@ -148,7 +149,7 @@ class Commands {
|
|
|
148
149
|
this.adapter.logToPairing('Touchlink reset started ', true);
|
|
149
150
|
|
|
150
151
|
let cTimer = Number(this.adapter.config.countDown);
|
|
151
|
-
if (!this.adapter.config.countDown ||
|
|
152
|
+
if (!this.adapter.config.countDown || cTimer == 0) {
|
|
152
153
|
cTimer = 60;
|
|
153
154
|
}
|
|
154
155
|
|
|
@@ -169,18 +170,20 @@ class Commands {
|
|
|
169
170
|
const groups = {};
|
|
170
171
|
let rooms;
|
|
171
172
|
this.adapter.getEnumsAsync('enum.rooms')
|
|
172
|
-
.then(enums => {
|
|
173
|
+
.then((enums) => {
|
|
173
174
|
// rooms
|
|
174
175
|
rooms = enums['enum.rooms'];
|
|
175
176
|
})
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
177
|
+
.then(() => {
|
|
178
|
+
// get all adapter devices
|
|
179
|
+
return this.adapter.getDevicesAsync();
|
|
180
|
+
})
|
|
181
|
+
.then(async (result) => {
|
|
182
|
+
const alls = (id) ? await this.adapter.getStatesAsync(id+'.*') : await this.adapter.getStatesAsync('*');
|
|
183
|
+
const allst = (id) ? await this.adapter.getStatesOfAsync(id) : await this.adapter.getStatesOfAsync();
|
|
184
|
+
result = result.filter((item)=>!id || id == item._id);
|
|
182
185
|
// get device states and groups
|
|
183
|
-
result.forEach(async devInfo => {
|
|
186
|
+
result.forEach(async (devInfo) => {
|
|
184
187
|
if (devInfo._id) {
|
|
185
188
|
// groups
|
|
186
189
|
// const grState = alls[`${devInfo._id}.groups`];
|
|
@@ -189,31 +192,31 @@ class Commands {
|
|
|
189
192
|
// }
|
|
190
193
|
// battery and link_quality
|
|
191
194
|
const lqState = alls[`${devInfo._id}.link_quality`];
|
|
192
|
-
devInfo.link_quality = lqState ? lqState.val: undefined;
|
|
193
|
-
devInfo.link_quality_lc = lqState ? lqState.lc: undefined;
|
|
195
|
+
devInfo.link_quality = (lqState) ? lqState.val: undefined;
|
|
196
|
+
devInfo.link_quality_lc = (lqState) ? lqState.lc: undefined;
|
|
194
197
|
const batState = alls[`${devInfo._id}.battery`];
|
|
195
|
-
devInfo.battery = batState ? batState.val: undefined;
|
|
198
|
+
devInfo.battery = (batState) ? batState.val: undefined;
|
|
196
199
|
// devInfo.states = states || {};
|
|
197
200
|
|
|
198
|
-
const states = allst.filter(item
|
|
201
|
+
const states = allst.filter((item)=>item._id.startsWith(devInfo._id));
|
|
199
202
|
|
|
200
203
|
// put only allowed states
|
|
201
|
-
devInfo.statesDef = (states || []).filter(stateDef
|
|
204
|
+
devInfo.statesDef = (states || []).filter((stateDef)=>{
|
|
202
205
|
const sid = stateDef._id;
|
|
203
206
|
const name = sid.split('.').pop();
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}).map(stateDef
|
|
207
|
+
if (disallowedDashStates.includes(name)) return false;
|
|
208
|
+
return true;
|
|
209
|
+
}).map((stateDef)=>{
|
|
207
210
|
const name = stateDef.common.name;
|
|
208
211
|
const devname = devInfo.common.name;
|
|
209
212
|
// replace state
|
|
210
213
|
return {
|
|
211
214
|
id: stateDef._id,
|
|
212
|
-
name: typeof name === 'string' ? name.replace(devname, '') : name,
|
|
215
|
+
name: (typeof name === 'string') ? name.replace(devname, '') : name,
|
|
213
216
|
type: stateDef.common.type,
|
|
214
217
|
read: stateDef.common.read,
|
|
215
218
|
write: stateDef.common.write,
|
|
216
|
-
val: alls[stateDef._id] ? alls[stateDef._id].val : undefined,
|
|
219
|
+
val: (alls[stateDef._id]) ? alls[stateDef._id].val : undefined,
|
|
217
220
|
role: stateDef.common.role,
|
|
218
221
|
unit: stateDef.common.unit,
|
|
219
222
|
states: stateDef.common.states,
|
|
@@ -223,7 +226,7 @@ class Commands {
|
|
|
223
226
|
});
|
|
224
227
|
return result;
|
|
225
228
|
})
|
|
226
|
-
.then(async result => {
|
|
229
|
+
.then(async (result) => {
|
|
227
230
|
// combine info
|
|
228
231
|
const devices = [];
|
|
229
232
|
for (const devInfo of result) {
|
|
@@ -234,37 +237,40 @@ class Commands {
|
|
|
234
237
|
const match = /zigbee.\d.group_([0-9]+)/.exec(devInfo._id);
|
|
235
238
|
if (match && match.length > 1) {
|
|
236
239
|
const groupmembers = await this.zbController.getGroupMembersFromController(match[1]);
|
|
237
|
-
this.debug(
|
|
240
|
+
this.debug('group members: ' + JSON.stringify(groupmembers));
|
|
238
241
|
if (groupmembers && groupmembers.length > 0) {
|
|
239
242
|
const memberinfo = [];
|
|
240
243
|
for (const member of groupmembers) {
|
|
241
244
|
if (groups) {
|
|
242
245
|
const grouparray = groups[member.ieee];
|
|
243
|
-
if (grouparray)
|
|
246
|
+
if (grouparray)
|
|
247
|
+
{
|
|
244
248
|
if (!grouparray.includes(match[1])) {
|
|
245
|
-
groups[member.ieee].push(match[1])
|
|
249
|
+
groups[member.ieee].push(match[1])
|
|
246
250
|
}
|
|
247
251
|
}
|
|
248
252
|
else groups[member.ieee] = [match[1]];
|
|
249
253
|
}
|
|
250
|
-
const device = await this.adapter.getObjectAsync(
|
|
254
|
+
const device = await this.adapter.getObjectAsync(this.adapter.namespace + '.' + member.ieee.substr(2));
|
|
251
255
|
if (device) {
|
|
252
256
|
member.device = device.common.name;
|
|
253
|
-
}
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
254
259
|
member.device = 'unknown';
|
|
255
260
|
}
|
|
256
261
|
memberinfo.push(member);
|
|
257
262
|
}
|
|
258
263
|
devInfo.memberinfo = memberinfo;
|
|
259
|
-
this.debug(
|
|
264
|
+
this.debug('memberinfo: ' + JSON.stringify(devInfo.memberinfo));
|
|
260
265
|
}
|
|
261
266
|
}
|
|
262
|
-
}
|
|
267
|
+
}
|
|
268
|
+
else
|
|
269
|
+
{
|
|
263
270
|
const modelDesc = statesMapping.findModel(devInfo.common.type);
|
|
264
271
|
devInfo.icon = (modelDesc && modelDesc.icon) ? modelDesc.icon : 'img/unknown.png';
|
|
265
|
-
devInfo.vendor = modelDesc ? modelDesc.vendor : '';
|
|
272
|
+
devInfo.vendor = (modelDesc) ? modelDesc.vendor : '';
|
|
266
273
|
}
|
|
267
|
-
|
|
268
274
|
const id = getZbId(devInfo._id);
|
|
269
275
|
devInfo.info = await this.zbController.resolveEntity(id);
|
|
270
276
|
|
|
@@ -273,11 +279,10 @@ class Commands {
|
|
|
273
279
|
if (!rooms.hasOwnProperty(room) ||
|
|
274
280
|
!rooms[room] ||
|
|
275
281
|
!rooms[room].common ||
|
|
276
|
-
!rooms[room].common.members
|
|
277
|
-
) {
|
|
282
|
+
!rooms[room].common.members) {
|
|
278
283
|
continue;
|
|
279
284
|
}
|
|
280
|
-
if (rooms[room].common.members.
|
|
285
|
+
if (rooms[room].common.members.indexOf(devInfo._id) !== -1) {
|
|
281
286
|
devInfo.rooms.push(rooms[room].common.name);
|
|
282
287
|
}
|
|
283
288
|
}
|
|
@@ -290,20 +295,18 @@ class Commands {
|
|
|
290
295
|
.then(async (devices) => {
|
|
291
296
|
// fill group info
|
|
292
297
|
for (const groupdev in groups) {
|
|
293
|
-
|
|
294
|
-
const device = devices.find((dev) =>( groupdev === getZbId(dev._id) ))
|
|
298
|
+
this.debug('GetDevices scanning group ' + groupdev + ' ' + JSON.stringify(groups[groupdev]))
|
|
299
|
+
const device = devices.find((dev) =>( groupdev === getZbId(dev._id) ))
|
|
295
300
|
if (device) {
|
|
296
|
-
device.groups = groups[groupdev]
|
|
297
|
-
this.debug(
|
|
301
|
+
device.groups = groups[groupdev]
|
|
302
|
+
this.debug('adding group info to device ' + groupdev);
|
|
298
303
|
}
|
|
299
304
|
}
|
|
300
305
|
// append devices that paired but not created
|
|
301
306
|
if (!id) {
|
|
302
307
|
for (const d of pairedDevices) {
|
|
303
308
|
const device = await this.zbController.resolveEntity(d.ieeeAddr);
|
|
304
|
-
if (!device)
|
|
305
|
-
continue;
|
|
306
|
-
}
|
|
309
|
+
if (!device) continue;
|
|
307
310
|
const exists = devices.find((dev) => (dev._id && device.device.ieeeAddr === getZbId(dev._id)));
|
|
308
311
|
if (!exists) {
|
|
309
312
|
devices.push({
|
|
@@ -322,11 +325,13 @@ class Commands {
|
|
|
322
325
|
}
|
|
323
326
|
return devices;
|
|
324
327
|
})
|
|
325
|
-
.then(devices => {
|
|
326
|
-
this.debug(
|
|
328
|
+
.then((devices) => {
|
|
329
|
+
this.debug('getDevices result: ' + JSON.stringify(devices));
|
|
327
330
|
this.adapter.sendTo(from, command, devices, callback);
|
|
328
331
|
})
|
|
329
|
-
.catch(err =>
|
|
332
|
+
.catch((err) => {
|
|
333
|
+
this.error('getDevices error: ' + err.stack);
|
|
334
|
+
});
|
|
330
335
|
} else {
|
|
331
336
|
this.adapter.sendTo(from, command, {error: 'You need save and run adapter before pairing!'}, callback);
|
|
332
337
|
}
|
|
@@ -347,16 +352,17 @@ class Commands {
|
|
|
347
352
|
|
|
348
353
|
const coordinatorVersion = await this.adapter.zbController.herdsman.getCoordinatorVersion();
|
|
349
354
|
|
|
350
|
-
await this.adapter.getForeignObject(
|
|
355
|
+
await this.adapter.getForeignObject('system.adapter.' + this.adapter.namespace, (err, obj) => {
|
|
351
356
|
if (!err && obj) {
|
|
352
357
|
if (obj.common.installedFrom && obj.common.installedFrom.includes('://')) {
|
|
353
358
|
const instFrom = obj.common.installedFrom;
|
|
354
|
-
coordinatorinfo.installSource = instFrom.replace('tarball',
|
|
359
|
+
coordinatorinfo.installSource = instFrom.replace('tarball','commit');
|
|
355
360
|
} else {
|
|
356
361
|
coordinatorinfo.installSource = obj.common.installedFrom;
|
|
357
362
|
}
|
|
358
363
|
}
|
|
359
|
-
try
|
|
364
|
+
try
|
|
365
|
+
{
|
|
360
366
|
coordinatorinfo.port = obj.native.port;
|
|
361
367
|
coordinatorinfo.channel = obj.native.channel;
|
|
362
368
|
coordinatorinfo.installedVersion = obj.native.version;
|
|
@@ -364,40 +370,24 @@ class Commands {
|
|
|
364
370
|
coordinatorinfo.type = coordinatorVersion.type;
|
|
365
371
|
const meta = coordinatorVersion.meta;
|
|
366
372
|
if (meta) {
|
|
367
|
-
if (meta.hasOwnProperty('revision'))
|
|
368
|
-
coordinatorinfo.revision = meta.revision;
|
|
369
|
-
}
|
|
373
|
+
if (meta.hasOwnProperty('revision')) coordinatorinfo.revision = meta.revision;
|
|
370
374
|
let vt = 'x-';
|
|
371
|
-
if (meta.hasOwnProperty('transportrev'))
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
if (meta.hasOwnProperty('
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
vt = vt + meta.majorrel + '.';
|
|
381
|
-
} else {
|
|
382
|
-
vt = vt + 'x.';
|
|
383
|
-
}
|
|
384
|
-
if (meta.hasOwnProperty('minorrel')) {
|
|
385
|
-
vt = vt + meta.minorrel + '.';
|
|
386
|
-
} else {
|
|
387
|
-
vt = vt + 'x.';
|
|
388
|
-
}
|
|
389
|
-
if (meta.hasOwnProperty('maintrel')) {
|
|
390
|
-
vt = vt + meta.maintrel + '.';
|
|
391
|
-
} else {
|
|
392
|
-
vt = vt + 'x.';
|
|
393
|
-
}
|
|
375
|
+
if (meta.hasOwnProperty('transportrev')) vt = meta.transportrev + '-';
|
|
376
|
+
if (meta.hasOwnProperty('product')) vt = vt + meta.product + '.';
|
|
377
|
+
else vt = vt + 'x.';
|
|
378
|
+
if (meta.hasOwnProperty('majorrel')) vt = vt + meta.majorrel + '.';
|
|
379
|
+
else vt = vt + 'x.';
|
|
380
|
+
if (meta.hasOwnProperty('minorrel')) vt = vt + meta.minorrel + '.';
|
|
381
|
+
else vt = vt + 'x.';
|
|
382
|
+
if (meta.hasOwnProperty('maintrel')) vt = vt + meta.maintrel + '.';
|
|
383
|
+
else vt = vt + 'x.';
|
|
394
384
|
coordinatorinfo.version = vt;
|
|
395
385
|
}
|
|
396
386
|
}
|
|
397
387
|
}
|
|
398
388
|
catch { this.warn('exception raised in getCoordinatorInfo');}
|
|
399
389
|
|
|
400
|
-
this.debug(
|
|
390
|
+
this.debug('getCoorinatorInfo result: ' + JSON.stringify(coordinatorinfo));
|
|
401
391
|
this.adapter.sendTo(from, command, coordinatorinfo, callback);
|
|
402
392
|
});
|
|
403
393
|
} else {
|
|
@@ -417,26 +407,28 @@ class Commands {
|
|
|
417
407
|
|
|
418
408
|
deleteDevice(from, command, msg, callback) {
|
|
419
409
|
if (this.zbController && this.stController) {
|
|
420
|
-
this.debug(
|
|
410
|
+
this.debug('deleteDevice message: ' + JSON.stringify(msg));
|
|
421
411
|
const id = msg.id;
|
|
422
412
|
const force = msg.force;
|
|
423
413
|
const sysid = id.replace(this.adapter.namespace + '.', '0x');
|
|
424
414
|
const devId = id.replace(this.adapter.namespace + '.', '');
|
|
425
|
-
this.debug(
|
|
415
|
+
this.debug('deleteDevice sysid: ' + sysid);
|
|
426
416
|
const dev = this.zbController.getDevice(sysid);
|
|
427
417
|
if (!dev) {
|
|
428
418
|
this.debug('Not found!');
|
|
429
|
-
this.debug(
|
|
430
|
-
this.stController.deleteDeviceStates(devId, () =>
|
|
431
|
-
this.adapter.sendTo(from, command, {}, callback)
|
|
419
|
+
this.debug('Try delete dev ' + devId + ' from iobroker.');
|
|
420
|
+
this.stController.deleteDeviceStates(devId, () => {
|
|
421
|
+
this.adapter.sendTo(from, command, {}, callback);
|
|
422
|
+
});
|
|
432
423
|
return;
|
|
433
424
|
}
|
|
434
|
-
this.zbController.remove(sysid, force, err => {
|
|
425
|
+
this.zbController.remove(sysid, force, (err) => {
|
|
435
426
|
if (!err) {
|
|
436
|
-
this.stController.deleteDeviceStates(devId, () =>
|
|
437
|
-
this.adapter.sendTo(from, command, {}, callback)
|
|
427
|
+
this.stController.deleteDeviceStates(devId, () => {
|
|
428
|
+
this.adapter.sendTo(from, command, {}, callback);
|
|
429
|
+
});
|
|
438
430
|
} else {
|
|
439
|
-
this.debug(
|
|
431
|
+
this.debug('Error on remove! ' + err);
|
|
440
432
|
this.adapter.sendTo(from, command, {error: err}, callback);
|
|
441
433
|
}
|
|
442
434
|
});
|
|
@@ -461,7 +453,7 @@ class Commands {
|
|
|
461
453
|
async getChannels(from, command, message, callback) {
|
|
462
454
|
if (this.zbController) {
|
|
463
455
|
const result = await this.zbController.getChannelsEnergy();
|
|
464
|
-
this.debug(
|
|
456
|
+
this.debug('getChannels result: ' + JSON.stringify(result));
|
|
465
457
|
this.adapter.sendTo(from, command, result, callback);
|
|
466
458
|
} else {
|
|
467
459
|
this.adapter.sendTo(
|
|
@@ -474,10 +466,10 @@ class Commands {
|
|
|
474
466
|
|
|
475
467
|
async setDeviceActivated(from, command, msg, callback) {
|
|
476
468
|
if (this.stController) {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
469
|
+
const id = msg.id;
|
|
470
|
+
const targetstate = msg.deactivated;
|
|
471
|
+
this.stController.setDeviceActivated(id, targetstate);
|
|
472
|
+
this.adapter.sendTo(from, command, {}, callback);
|
|
481
473
|
}
|
|
482
474
|
}
|
|
483
475
|
|
|
@@ -494,7 +486,8 @@ class Commands {
|
|
|
494
486
|
);
|
|
495
487
|
this.adapter.sendTo(from, command, {}, callback);
|
|
496
488
|
} catch (error) {
|
|
497
|
-
const errmsg = `Reconfigure failed ${entity.device.ieeeAddr} ${entity.device.modelID},
|
|
489
|
+
const errmsg = `Reconfigure failed ${entity.device.ieeeAddr} ${entity.device.modelID}, ` +
|
|
490
|
+
`(${error.stack})`;
|
|
498
491
|
this.error(errmsg);
|
|
499
492
|
this.adapter.sendTo(from, command, {error: errmsg}, callback);
|
|
500
493
|
}
|
package/lib/developer.js
CHANGED
|
@@ -38,8 +38,9 @@ class Developer {
|
|
|
38
38
|
if (typeof obj === 'object' && obj.command) {
|
|
39
39
|
switch (obj.command) {
|
|
40
40
|
case 'reset':
|
|
41
|
-
this.zbController.reset(obj.message.mode, err
|
|
42
|
-
this.adapter.sendTo(obj.from, obj.command, err, obj.callback)
|
|
41
|
+
this.zbController.reset(obj.message.mode, function (err) {
|
|
42
|
+
this.adapter.sendTo(obj.from, obj.command, err, obj.callback);
|
|
43
|
+
}.bind(this));
|
|
43
44
|
break;
|
|
44
45
|
case 'sendToZigbee':
|
|
45
46
|
this.sendToZigbee(obj);
|
|
@@ -93,7 +94,7 @@ class Developer {
|
|
|
93
94
|
cmd = zcl.Utils.getCluster(cid).getCommand(obj.message.cmd);
|
|
94
95
|
}
|
|
95
96
|
else if (cmdType === 'functionalResp') {
|
|
96
|
-
cmd = zcl.Utils.getCluster(cid).getCommandResponse(obj.message.cmd);
|
|
97
|
+
cmd = zcl.Utils.getCluster(cid).getCommandResponse(obj.message.cmd);
|
|
97
98
|
}
|
|
98
99
|
else if (cmdType === 'foundation') {
|
|
99
100
|
cmd = zcl.Utils.getGlobalCommand((obj.message.cmd));
|
|
@@ -105,7 +106,7 @@ class Developer {
|
|
|
105
106
|
|
|
106
107
|
const publishTarget = this.zbController.getDevice(devId) ? devId : this.zbController.getGroup(parseInt(devId));
|
|
107
108
|
if (!publishTarget) {
|
|
108
|
-
this.adapter.sendTo(obj.from, obj.command, {localErr:
|
|
109
|
+
this.adapter.sendTo(obj.from, obj.command, {localErr: 'Device or group ' + devId + ' not found!'}, obj.callback);
|
|
109
110
|
return;
|
|
110
111
|
}
|
|
111
112
|
if (!cid || !cmd) {
|
|
@@ -136,8 +137,8 @@ class Developer {
|
|
|
136
137
|
result.statusCode = exception.code;
|
|
137
138
|
this.adapter.sendTo(obj.from, obj.command, result, obj.callback);
|
|
138
139
|
} else {
|
|
139
|
-
this.error(
|
|
140
|
-
// exception (Error class) cannot be
|
|
140
|
+
this.error('SendToZigbee failed! (' + exception + ')');
|
|
141
|
+
// exception (Error class) cannot be send to adapter, send string message instead!
|
|
141
142
|
this.adapter.sendTo(obj.from, obj.command, {msg: exception.message}, obj.callback);
|
|
142
143
|
}
|
|
143
144
|
}
|