iobroker.zigbee 1.8.3 → 1.8.5
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 +3 -0
- package/admin/admin.js +512 -493
- package/admin/index_m.html +1171 -1001
- package/admin/tab_m.html +44 -3
- 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 +27 -0
- 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 +30 -0
- package/docs/flashing_via_arduino_(en).md +110 -0
- 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 +28 -0
- 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/io-package.json +17 -25
- package/lib/backup.js +2 -2
- package/lib/binding.js +32 -37
- package/lib/colors.js +163 -158
- package/lib/commands.js +100 -91
- package/lib/developer.js +9 -12
- package/lib/devices.js +168 -178
- package/lib/exclude.js +30 -36
- package/lib/exposes.js +163 -139
- package/lib/groups.js +81 -83
- package/lib/json.js +5 -6
- package/lib/networkmap.js +2 -3
- package/lib/ota.js +34 -18
- package/lib/rgb.js +114 -72
- package/lib/seriallist.js +25 -20
- package/lib/states.js +511 -526
- package/lib/statescontroller.js +206 -183
- package/lib/utils.js +24 -23
- package/lib/zbBaseExtension.js +4 -4
- package/lib/zbDelayedAction.js +5 -13
- package/lib/zbDeviceAvailability.js +69 -65
- package/lib/zbDeviceConfigure.js +9 -21
- package/lib/zbDeviceEvent.js +3 -4
- package/lib/zigbeecontroller.js +133 -128
- package/main.js +169 -154
- package/package.json +27 -13
- package/.eslintignore +0 -2
- package/.eslintrc.json +0 -37
- package/.github/FUNDING.yml +0 -3
- package/.github/auto-merge.yml +0 -17
- package/.github/dependabot.yml +0 -24
- package/.github/stale.yml +0 -13
- package/.github/workflows/codeql.yml +0 -41
- package/.github/workflows/dependabot-automerge.yml +0 -22
- package/.github/workflows/test-and-release.yml +0 -149
- package/.releaseconfig.json +0 -3
- package/.travis/wiki.sh +0 -28
- package/.travis.yml +0 -41
- package/gulpfile.js +0 -464
- package/test/integration.js +0 -5
- package/test/mocha.custom.opts +0 -2
- package/test/mocha.setup.js +0 -14
- package/test/package.js +0 -5
- package/test/unit.js +0 -5
package/admin/admin.js
CHANGED
|
@@ -38,7 +38,7 @@ function getDeviceByID(ID) {
|
|
|
38
38
|
return devices.find((devInfo) => {
|
|
39
39
|
try {
|
|
40
40
|
return devInfo._id == ID;
|
|
41
|
-
}
|
|
41
|
+
} catch (e) {
|
|
42
42
|
//console.log("No dev with ieee " + ieeeAddr);
|
|
43
43
|
}
|
|
44
44
|
});
|
|
@@ -48,17 +48,18 @@ function getDevice(ieeeAddr) {
|
|
|
48
48
|
return devices.find((devInfo) => {
|
|
49
49
|
try {
|
|
50
50
|
return devInfo.info.device._ieeeAddr == ieeeAddr;
|
|
51
|
-
}
|
|
51
|
+
} catch (e) {
|
|
52
52
|
//console.log("No dev with ieee " + ieeeAddr);
|
|
53
53
|
}
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
|
+
|
|
56
57
|
// eslint-disable-next-line no-unused-vars
|
|
57
58
|
function getDeviceByNetwork(nwk) {
|
|
58
59
|
return devices.find((devInfo) => {
|
|
59
60
|
try {
|
|
60
61
|
return devInfo.info.device._networkAddress == nwk;
|
|
61
|
-
}
|
|
62
|
+
} catch (e) {
|
|
62
63
|
//console.log("No dev with nwkAddr " + nwk);
|
|
63
64
|
}
|
|
64
65
|
});
|
|
@@ -125,12 +126,12 @@ function getCoordinatorCard(dev) {
|
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
function getGroupCard(dev) {
|
|
128
|
-
const id = (dev._id ? dev._id: ''),
|
|
129
|
+
const id = (dev._id ? dev._id : ''),
|
|
129
130
|
title = dev.common.name,
|
|
130
131
|
lq = '<div class="col tool"><i class="material-icons icon-green">check_circle</i></div>',
|
|
131
132
|
rooms = [],
|
|
132
|
-
numid = parseInt(id.replace(namespace+'.group_', '')),
|
|
133
|
-
lang = systemLang
|
|
133
|
+
numid = parseInt(id.replace(namespace + '.group_', '')),
|
|
134
|
+
lang = systemLang || 'en';
|
|
134
135
|
for (const r in dev.rooms) {
|
|
135
136
|
if (dev.rooms[r].hasOwnProperty(lang)) {
|
|
136
137
|
rooms.push(dev.rooms[r][lang]);
|
|
@@ -143,19 +144,20 @@ function getGroupCard(dev) {
|
|
|
143
144
|
let memberCount = 0;
|
|
144
145
|
let info = `<div style="min-height:88px; font-size: 0.8em; height: 98px; overflow-y: auto" class="truncate">
|
|
145
146
|
<ul>`;
|
|
146
|
-
|
|
147
|
+
info = info.concat(`<li><span class="labelinfo">Group ${numid}</span></li>`);
|
|
147
148
|
if (dev.memberinfo === undefined) {
|
|
148
149
|
info = info.concat(`<li><span class="labelinfo">No devices in group</span></li>`);
|
|
149
150
|
} else {
|
|
150
|
-
for (let m=0;m < dev.memberinfo.length; m++) {
|
|
151
|
+
for (let m = 0; m < dev.memberinfo.length; m++) {
|
|
151
152
|
info = info.concat(`<li><span align:"left">${dev.memberinfo[m].device}.${dev.memberinfo[m].epid}</span><span align:"right"> ...${dev.memberinfo[m].ieee.slice(-4)}</span></li>`);
|
|
152
153
|
}
|
|
153
|
-
memberCount = (dev.memberinfo.length<8?dev.memberinfo.length:7);
|
|
154
|
-
}
|
|
154
|
+
memberCount = (dev.memberinfo.length < 8 ? dev.memberinfo.length : 7);
|
|
155
|
+
}
|
|
156
|
+
;
|
|
155
157
|
info = info.concat(` </ul>
|
|
156
158
|
</div>`);
|
|
157
159
|
const image = `<img src="img/group_${memberCount}.png" width="80px" onerror="this.onerror=null;this.src='img/unavailable.png';">`;
|
|
158
|
-
const dashCard = getDashCard(dev
|
|
160
|
+
const dashCard = getDashCard(dev, `img/group_${memberCount}.png`);
|
|
159
161
|
const card = `<div id="${id}" class="device group">
|
|
160
162
|
<div class="card hoverable flipable">
|
|
161
163
|
<div class="front face">${dashCard}</div>
|
|
@@ -202,7 +204,7 @@ function getCard(dev) {
|
|
|
202
204
|
img_src = dev.icon || dev.common.icon,
|
|
203
205
|
rooms = [],
|
|
204
206
|
isActive = (dev.common.deactivated ? false : true),
|
|
205
|
-
lang = systemLang
|
|
207
|
+
lang = systemLang || 'en';
|
|
206
208
|
for (const r in dev.rooms) {
|
|
207
209
|
if (dev.rooms[r].hasOwnProperty(lang)) {
|
|
208
210
|
rooms.push(dev.rooms[r][lang]);
|
|
@@ -216,25 +218,25 @@ function getCard(dev) {
|
|
|
216
218
|
const modelUrl = (!type) ? '' : `<a href="https://www.zigbee2mqtt.io/devices/${type_url}.html" target="_blank" rel="noopener noreferrer">${type}</a>`;
|
|
217
219
|
const image = `<img src="${img_src}" width="80px" onerror="this.onerror=null;this.src='img/unavailable.png';">`,
|
|
218
220
|
nwk = (dev.info && dev.info.device) ? dev.info.device._networkAddress : undefined,
|
|
219
|
-
battery_cls = (isActive ? getBatteryCls(dev.battery):''),
|
|
221
|
+
battery_cls = (isActive ? getBatteryCls(dev.battery) : ''),
|
|
220
222
|
lqi_cls = getLQICls(dev.link_quality),
|
|
221
223
|
battery = (dev.battery && isActive) ? `<div class="col tool"><i id="${rid}_battery_icon" class="material-icons ${battery_cls}">battery_std</i><div id="${rid}_battery" class="center" style="font-size:0.7em">${dev.battery}</div></div>` : '',
|
|
222
224
|
lq = (dev.link_quality > 0 && isActive) ? `<div class="col tool"><i id="${rid}_link_quality_icon" class="material-icons ${lqi_cls}">network_check</i><div id="${rid}_link_quality" class="center" style="font-size:0.7em">${dev.link_quality}</div></div>` : '',
|
|
223
|
-
status = (dev.link_quality > 0 && isActive) ? `<div class="col tool"><i class="material-icons icon-green">check_circle</i></div>` : (isActive ? `<div class="col tool"><i class="material-icons icon-black">leak_remove</i></div
|
|
225
|
+
status = (dev.link_quality > 0 && isActive) ? `<div class="col tool"><i class="material-icons icon-green">check_circle</i></div>` : (isActive ? `<div class="col tool"><i class="material-icons icon-black">leak_remove</i></div>` : ''),
|
|
224
226
|
info = `<div style="min-height:88px; font-size: 0.8em" class="truncate">
|
|
225
227
|
<ul>
|
|
226
|
-
<li><span class="labelinfo">ieee:</span><span>0x${id.replace(namespace+'.', '')}</span></li>
|
|
227
|
-
<li><span class="labelinfo">nwk:</span><span>${(nwk) ? nwk.toString()+' (0x'+nwk.toString(16)+')' : ''}</span></li>
|
|
228
|
+
<li><span class="labelinfo">ieee:</span><span>0x${id.replace(namespace + '.', '')}</span></li>
|
|
229
|
+
<li><span class="labelinfo">nwk:</span><span>${(nwk) ? nwk.toString() + ' (0x' + nwk.toString(16) + ')' : ''}</span></li>
|
|
228
230
|
<li><span class="labelinfo">model:</span><span>${modelUrl}</span></li>
|
|
229
231
|
<li><span class="labelinfo">groups:</span><span>${dev.groupNames || ''}</span></li>
|
|
230
232
|
</ul>
|
|
231
233
|
</div>`,
|
|
232
234
|
permitJoinBtn = (dev.info && dev.info.device._type == 'Router') ? '<button name="join" class="btn-floating btn-small waves-effect waves-light right hoverable green"><i class="material-icons tiny">leak_add</i></button>' : '',
|
|
233
|
-
deactBtn = `<button name="swapactive" class="right btn-flat btn-small tooltipped" title="${(isActive?'Deactivate':'Activate')}"><i class="material-icons icon-${(isActive?'red':'green')}">power_settings_new</i></button>`,
|
|
235
|
+
deactBtn = `<button name="swapactive" class="right btn-flat btn-small tooltipped" title="${(isActive ? 'Deactivate' : 'Activate')}"><i class="material-icons icon-${(isActive ? 'red' : 'green')}">power_settings_new</i></button>`,
|
|
234
236
|
infoBtn = (nwk) ? `<button name="info" class="left btn-flat btn-small"><i class="material-icons icon-blue">info</i></button>` : '';
|
|
235
237
|
const dashCard = getDashCard(dev);
|
|
236
238
|
const card = `<div id="${id}" class="device">
|
|
237
|
-
<div class="card hoverable flipable ${isActive?'':'bg_red'}">
|
|
239
|
+
<div class="card hoverable flipable ${isActive ? '' : 'bg_red'}">
|
|
238
240
|
<div class="front face">${dashCard}</div>
|
|
239
241
|
<div class="back face">
|
|
240
242
|
<div class="card-content zcard">
|
|
@@ -274,6 +276,7 @@ function getCard(dev) {
|
|
|
274
276
|
</div>`;
|
|
275
277
|
return card;
|
|
276
278
|
}
|
|
279
|
+
|
|
277
280
|
/*
|
|
278
281
|
function openReval(e, id, name){
|
|
279
282
|
const $card = $(e.target).closest('.card');
|
|
@@ -301,7 +304,7 @@ function openReval(e, id, name){
|
|
|
301
304
|
});
|
|
302
305
|
}
|
|
303
306
|
*/
|
|
304
|
-
function closeReval(e, id){
|
|
307
|
+
function closeReval(e, id) {
|
|
305
308
|
const $cardReveal = $(e.target).closest('.card-reveal');
|
|
306
309
|
const $revealName = $cardReveal[0].getAttribute('name');
|
|
307
310
|
if ($revealName == 'edit' && id) {
|
|
@@ -320,21 +323,21 @@ function closeReval(e, id){
|
|
|
320
323
|
translateY: 0,
|
|
321
324
|
duration: 225,
|
|
322
325
|
easing: 'easeInOutQuad',
|
|
323
|
-
complete: function(anim) {
|
|
326
|
+
complete: function (anim) {
|
|
324
327
|
const el = anim.animatables[0].target;
|
|
325
|
-
$(el).css({
|
|
328
|
+
$(el).css({display: 'none'});
|
|
326
329
|
$card.css('overflow', $card.data('initialOverflow'));
|
|
327
330
|
}
|
|
328
331
|
});
|
|
329
332
|
}
|
|
330
333
|
|
|
331
334
|
function deleteConfirmation(id, name) {
|
|
332
|
-
const text = translateWord('Do you really want to delete device') + ' "'+name+'" ('+id+')?';
|
|
335
|
+
const text = translateWord('Do you really want to delete device') + ' "' + name + '" (' + id + ')?';
|
|
333
336
|
$('#modaldelete').find('p').text(text);
|
|
334
337
|
$('#force').prop('checked', false);
|
|
335
338
|
$('#forcediv').removeClass('hide');
|
|
336
|
-
$(
|
|
337
|
-
$(
|
|
339
|
+
$('#modaldelete a.btn[name=\'yes\']').unbind('click');
|
|
340
|
+
$('#modaldelete a.btn[name=\'yes\']').click(() => {
|
|
338
341
|
const force = $('#force').prop('checked');
|
|
339
342
|
deleteDevice(id, force);
|
|
340
343
|
});
|
|
@@ -347,8 +350,8 @@ function cleanConfirmation() {
|
|
|
347
350
|
$('#modalclean').find('p').text(text);
|
|
348
351
|
$('#cforce').prop('checked', false);
|
|
349
352
|
$('#cforcediv').removeClass('hide');
|
|
350
|
-
$(
|
|
351
|
-
$(
|
|
353
|
+
$('#modalclean a.btn[name=\'yes\']').unbind('click');
|
|
354
|
+
$('#modalclean a.btn[name=\'yes\']').click(() => {
|
|
352
355
|
const force = $('#cforce').prop('checked');
|
|
353
356
|
cleanDeviceStates(force);
|
|
354
357
|
});
|
|
@@ -356,78 +359,75 @@ function cleanConfirmation() {
|
|
|
356
359
|
Materialize.updateTextFields();
|
|
357
360
|
}
|
|
358
361
|
|
|
359
|
-
function EndPointIDfromEndPoint(ep)
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
return
|
|
363
|
-
return 'unidentified';
|
|
362
|
+
function EndPointIDfromEndPoint(ep) {
|
|
363
|
+
if (ep && ep.deviceIeeeAddress && ep.ID)
|
|
364
|
+
return `${ep.deviceIeeeAddress}:${ep.ID}`;
|
|
365
|
+
return 'unidentified';
|
|
364
366
|
}
|
|
365
367
|
|
|
366
368
|
function editName(id, name) {
|
|
367
|
-
|
|
369
|
+
console.log('editName called with ' + name);
|
|
368
370
|
const dev = devices.find((d) => d._id == id);
|
|
369
|
-
$('#modaledit').find(
|
|
371
|
+
$('#modaledit').find('input[id=\'d_name\']').val(name);
|
|
370
372
|
// if (dev.info && dev.info.device._type == 'Router') {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
+
const groupables = [];
|
|
374
|
+
if (dev && dev.info && dev.info.endpoints) {
|
|
373
375
|
for (const ep of dev.info.endpoints) {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
376
|
+
if (ep.inputClusters.includes(4)) {
|
|
377
|
+
groupables.push({epid: EndPointIDfromEndPoint(ep), ep: ep, memberOf: []});
|
|
378
|
+
}
|
|
377
379
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
+
}
|
|
381
|
+
const numEP = groupables.length;
|
|
380
382
|
// console.log('groupables: '+JSON.stringify(groupables));
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
383
|
+
$('#modaledit').find('.row.epid0').addClass('hide');
|
|
384
|
+
$('#modaledit').find('.row.epid1').addClass('hide');
|
|
385
|
+
$('#modaledit').find('.row.epid2').addClass('hide');
|
|
386
|
+
$('#modaledit').find('.row.epid3').addClass('hide');
|
|
387
|
+
if (numEP > 0) {
|
|
386
388
|
// go through all the groups. Find the ones to list for each groupable
|
|
387
389
|
if (numEP == 1) {
|
|
388
|
-
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
$('#modaledit').find('.endpointid').removeClass('hide');
|
|
390
|
+
$('#modaledit').find('.endpointid').addClass('hide');
|
|
391
|
+
} else {
|
|
392
|
+
$('#modaledit').find('.endpointid').removeClass('hide');
|
|
392
393
|
}
|
|
393
394
|
for (const d of devices) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
395
|
+
if (d && d.common && d.common.type == 'group') {
|
|
396
|
+
if (d.hasOwnProperty('memberinfo')) {
|
|
397
|
+
for (const member of d.memberinfo) {
|
|
398
|
+
const epid = EndPointIDfromEndPoint(member.ep);
|
|
399
|
+
for (var i = 0; i < groupables.length; i++) {
|
|
400
|
+
if (groupables[i].epid == epid) {
|
|
401
|
+
groupables[i].memberOf.push(d.native.id.replace('group_', ''));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
402
405
|
}
|
|
403
|
-
}
|
|
404
406
|
}
|
|
405
|
-
}
|
|
406
407
|
}
|
|
407
|
-
console.log(
|
|
408
|
-
for (var i = 0;i<groupables.length;i++)
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
list2select('#d_groups_ep'+i, groups, groupables[i].memberOf || []);
|
|
408
|
+
console.log('groupables: ' + JSON.stringify(groupables));
|
|
409
|
+
for (var i = 0; i < groupables.length; i++) {
|
|
410
|
+
if (i > 1) {
|
|
411
|
+
$('#modaledit').find('translate.device_with_endpoint').innerHtml = name + ' ' + groupables[i].epid;
|
|
412
|
+
}
|
|
413
|
+
$('#modaledit').find('.row.epid' + i).removeClass('hide');
|
|
414
|
+
list2select('#d_groups_ep' + i, groups, groupables[i].memberOf || []);
|
|
415
415
|
}
|
|
416
|
-
|
|
416
|
+
}
|
|
417
417
|
// } else {
|
|
418
418
|
// $('#modaledit').find('.input-field.endpoints').addClass('hide');
|
|
419
419
|
// $('#modaledit').find('.input-field.groups').addClass('hide');
|
|
420
420
|
// }
|
|
421
|
-
$(
|
|
422
|
-
$(
|
|
423
|
-
const newName = $('#modaledit').find(
|
|
421
|
+
$('#modaledit a.btn[name=\'save\']').unbind('click');
|
|
422
|
+
$('#modaledit a.btn[name=\'save\']').click(() => {
|
|
423
|
+
const newName = $('#modaledit').find('input[id=\'d_name\']').val();
|
|
424
424
|
const groupsbyid = {};
|
|
425
|
-
if (groupables.length
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
425
|
+
if (groupables.length > 0) {
|
|
426
|
+
for (var i = 0; i < groupables.length; i++) {
|
|
427
|
+
const ng = $('#d_groups_ep' + i).val();
|
|
428
|
+
if (ng.toString() != groupables[i].memberOf.toString())
|
|
429
|
+
groupsbyid[groupables[i].ep.ID] = GenerateGroupChange(groupables[i].memberOf, ng);
|
|
430
|
+
}
|
|
431
431
|
}
|
|
432
432
|
console.log('grpid ' + JSON.stringify(groupsbyid));
|
|
433
433
|
updateDev(id, newName, groupsbyid);
|
|
@@ -436,14 +436,13 @@ function editName(id, name) {
|
|
|
436
436
|
Materialize.updateTextFields();
|
|
437
437
|
}
|
|
438
438
|
|
|
439
|
-
function GenerateGroupChange(oldmembers, newmembers)
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
return grpchng;
|
|
439
|
+
function GenerateGroupChange(oldmembers, newmembers) {
|
|
440
|
+
let grpchng = [];
|
|
441
|
+
for (const oldg of oldmembers)
|
|
442
|
+
if (!newmembers.includes(oldg)) grpchng.push('-' + oldg);
|
|
443
|
+
for (const newg of newmembers)
|
|
444
|
+
if (!oldmembers.includes(newg)) grpchng.push(newg);
|
|
445
|
+
return grpchng;
|
|
447
446
|
}
|
|
448
447
|
|
|
449
448
|
function deleteDevice(id, force) {
|
|
@@ -474,6 +473,7 @@ function cleanDeviceStates(force) {
|
|
|
474
473
|
});
|
|
475
474
|
showWaitingDialog('Device is being removed', 10);
|
|
476
475
|
}
|
|
476
|
+
|
|
477
477
|
function renameDevice(id, name) {
|
|
478
478
|
sendTo(namespace, 'renameDevice', {id: id, name: name}, function (msg) {
|
|
479
479
|
if (msg) {
|
|
@@ -490,7 +490,7 @@ function showDevices() {
|
|
|
490
490
|
let html = '';
|
|
491
491
|
const lang = systemLang || 'en';
|
|
492
492
|
// sort by rooms
|
|
493
|
-
devices.sort((a, b)=>{
|
|
493
|
+
devices.sort((a, b) => {
|
|
494
494
|
const roomsA = [], roomsB = [];
|
|
495
495
|
for (const r in a.rooms) {
|
|
496
496
|
if (a.rooms[r].hasOwnProperty(lang)) {
|
|
@@ -517,29 +517,28 @@ function showDevices() {
|
|
|
517
517
|
}
|
|
518
518
|
return 0;
|
|
519
519
|
});
|
|
520
|
-
for (let i=0;i < devices.length; i++) {
|
|
520
|
+
for (let i = 0; i < devices.length; i++) {
|
|
521
521
|
const d = devices[i];
|
|
522
522
|
if (!d.info) {
|
|
523
|
-
if (d.common && d.common.type == 'group')
|
|
524
|
-
{
|
|
523
|
+
if (d.common && d.common.type == 'group') {
|
|
525
524
|
const card = getGroupCard(d);
|
|
526
525
|
html += card;
|
|
527
526
|
continue;
|
|
528
527
|
}
|
|
529
|
-
}
|
|
528
|
+
}
|
|
529
|
+
;
|
|
530
530
|
if (d.info && d.info.device._type == 'Coordinator') {
|
|
531
531
|
const card = getCoordinatorCard(d);
|
|
532
532
|
html += card;
|
|
533
533
|
} else {
|
|
534
|
-
|
|
534
|
+
//if (d.groups && d.info && d.info.device._type == "Router") {
|
|
535
535
|
if (d.groups) {
|
|
536
536
|
// devGroups[d._id] = d.groups;
|
|
537
537
|
if (typeof d.groups.map == 'function') {
|
|
538
|
-
d.groupNames = d.groups.map(item=>{
|
|
538
|
+
d.groupNames = d.groups.map(item => {
|
|
539
539
|
return groups[item] || '';
|
|
540
540
|
}).join(', ');
|
|
541
|
-
}
|
|
542
|
-
else {
|
|
541
|
+
} else {
|
|
543
542
|
d.groupNames = '..';
|
|
544
543
|
}
|
|
545
544
|
}
|
|
@@ -551,13 +550,13 @@ function showDevices() {
|
|
|
551
550
|
hookControls();
|
|
552
551
|
|
|
553
552
|
// update rooms filter
|
|
554
|
-
const allRooms = new Set(devices.map((item)=>item.rooms).flat().map((room)=>{
|
|
553
|
+
const allRooms = new Set(devices.map((item) => item.rooms).flat().map((room) => {
|
|
555
554
|
if (room && room.hasOwnProperty(lang)) {
|
|
556
555
|
return room[lang];
|
|
557
556
|
} else {
|
|
558
557
|
return room;
|
|
559
558
|
}
|
|
560
|
-
}).filter((item)=>item != undefined));
|
|
559
|
+
}).filter((item) => item != undefined));
|
|
561
560
|
const roomSelector = $('#room-filter');
|
|
562
561
|
roomSelector.empty();
|
|
563
562
|
roomSelector.append(`<li class="device-order-item" data-type="All" tabindex="0"><a class="translate" data-lang="All">All</a></li>`);
|
|
@@ -568,69 +567,70 @@ function showDevices() {
|
|
|
568
567
|
$('#room-filter-btn').text($(this).text());
|
|
569
568
|
doFilter();
|
|
570
569
|
});
|
|
571
|
-
$(
|
|
572
|
-
const card = $(this).parents(
|
|
573
|
-
card.toggleClass(
|
|
570
|
+
$('.flip').click(function () {
|
|
571
|
+
const card = $(this).parents('.card');
|
|
572
|
+
card.toggleClass('flipped');
|
|
574
573
|
});
|
|
575
574
|
$('#rotate_btn').click(function () {
|
|
576
|
-
$('.card.flipable').toggleClass(
|
|
575
|
+
$('.card.flipable').toggleClass('flipped');
|
|
577
576
|
});
|
|
578
577
|
|
|
579
|
-
shuffleInstance = new Shuffle($(
|
|
578
|
+
shuffleInstance = new Shuffle($('#devices'), {
|
|
580
579
|
itemSelector: '.device',
|
|
581
580
|
sizer: '.js-shuffle-sizer',
|
|
582
581
|
});
|
|
583
582
|
doFilter();
|
|
584
583
|
|
|
585
|
-
const getDevName = function(dev_block) {
|
|
584
|
+
const getDevName = function (dev_block) {
|
|
586
585
|
return dev_block.find('#dName').text();
|
|
587
586
|
};
|
|
588
|
-
const getDevId = function(dev_block) {
|
|
587
|
+
const getDevId = function (dev_block) {
|
|
589
588
|
return dev_block.attr('id');
|
|
590
589
|
};
|
|
591
|
-
$(
|
|
590
|
+
$('.card-reveal-buttons button[name=\'delete\']').click(function () {
|
|
592
591
|
const dev_block = $(this).parents('div.device');
|
|
593
592
|
deleteConfirmation(getDevId(dev_block), getDevName(dev_block));
|
|
594
593
|
});
|
|
595
|
-
$(
|
|
594
|
+
$('.card-reveal-buttons button[name=\'deletegrp\']').click(function () {
|
|
596
595
|
const dev_block = $(this).parents('div.device');
|
|
597
|
-
const id = dev_block.attr('id').replace(namespace+'.group_', '');
|
|
596
|
+
const id = dev_block.attr('id').replace(namespace + '.group_', '');
|
|
598
597
|
deleteGroupConfirmation(id, getDevName(dev_block));
|
|
599
598
|
});
|
|
600
|
-
$(
|
|
601
|
-
const dev_block = $(this).parents('div.device')
|
|
602
|
-
|
|
603
|
-
|
|
599
|
+
$('.card-reveal-buttons button[name=\'edit\']').click(function () {
|
|
600
|
+
const dev_block = $(this).parents('div.device');
|
|
601
|
+
const id = getDevId(dev_block);
|
|
602
|
+
const name = getDevName(dev_block);
|
|
604
603
|
editName(id, name);
|
|
605
604
|
});
|
|
606
|
-
$(
|
|
607
|
-
const dev_block = $(this).parents('div.device')
|
|
608
|
-
|
|
609
|
-
|
|
605
|
+
$('.card-reveal-buttons button[name=\'editgrp\']').click(function () {
|
|
606
|
+
const dev_block = $(this).parents('div.device');
|
|
607
|
+
const id = dev_block.attr('id').replace(namespace + '.group_', '');
|
|
608
|
+
const name = getDevName(dev_block);
|
|
610
609
|
editGroupName(id, name, false);
|
|
611
610
|
});
|
|
612
|
-
$(
|
|
611
|
+
$('button.btn-floating[name=\'join\']').click(function () {
|
|
613
612
|
const dev_block = $(this).parents('div.device');
|
|
614
|
-
if (!$('#pairing').hasClass('pulse'))
|
|
613
|
+
if (!$('#pairing').hasClass('pulse')) {
|
|
615
614
|
joinProcess(getDevId(dev_block));
|
|
615
|
+
}
|
|
616
616
|
showPairingProcess();
|
|
617
617
|
});
|
|
618
|
-
$(
|
|
618
|
+
$('.card-reveal-buttons button[name=\'info\']').click(function () {
|
|
619
619
|
const dev_block = $(this).parents('div.device');
|
|
620
620
|
showDevInfo(getDevId(dev_block));
|
|
621
621
|
});
|
|
622
|
-
$(
|
|
622
|
+
$('a.btn[name=\'done\']').click((e) => {
|
|
623
623
|
const dev_block = $(this).parents('div.device');
|
|
624
624
|
closeReval(e, getDevId(dev_block), getDevName(dev_block));
|
|
625
625
|
});
|
|
626
|
-
$(
|
|
626
|
+
$('a.btn-flat[name=\'close\']').click((e) => {
|
|
627
627
|
closeReval(e);
|
|
628
628
|
});
|
|
629
|
-
$(
|
|
629
|
+
$('.card-reveal-buttons button[name=\'reconfigure\']').click(function () {
|
|
630
630
|
const dev_block = $(this).parents('div.device');
|
|
631
631
|
reconfigureDlg(getDevId(dev_block));
|
|
632
632
|
});
|
|
633
|
-
$(
|
|
633
|
+
$('.card-reveal-buttons button[name=\'swapactive\']').click(function () {
|
|
634
634
|
const dev_block = $(this).parents('div.device');
|
|
635
635
|
swapActive(getDevId(dev_block));
|
|
636
636
|
});
|
|
@@ -641,10 +641,10 @@ function showDevices() {
|
|
|
641
641
|
|
|
642
642
|
function checkFwUpdate() {
|
|
643
643
|
const deviceCards = getDeviceCards();
|
|
644
|
-
const getFwInfoNode = function(deviceCard) {
|
|
644
|
+
const getFwInfoNode = function (deviceCard) {
|
|
645
645
|
return deviceCard.find('.fw_info');
|
|
646
646
|
};
|
|
647
|
-
const createBtn = function(icon, hint, disabled, color) {
|
|
647
|
+
const createBtn = function (icon, hint, disabled, color) {
|
|
648
648
|
const disabledAttr = disabled ? '[disabled]="true"' : '';
|
|
649
649
|
if (!color) {
|
|
650
650
|
color = !disabled ? 'icon-green' : '';
|
|
@@ -652,14 +652,14 @@ function checkFwUpdate() {
|
|
|
652
652
|
return `<button name="fw_update" class="left btn-flat btn-small" title="${hint}" ${disabledAttr}>
|
|
653
653
|
<i class="material-icons ${color}">${icon}</i></button>`;
|
|
654
654
|
};
|
|
655
|
-
const callback = function(msg) {
|
|
655
|
+
const callback = function (msg) {
|
|
656
656
|
if (msg) {
|
|
657
657
|
const deviceCard = getDeviceCard(msg.device);
|
|
658
658
|
const devId = getDevId(deviceCard.attr('id'));
|
|
659
659
|
const fwInfoNode = getFwInfoNode(deviceCard);
|
|
660
660
|
if (msg.status == 'available') {
|
|
661
661
|
fwInfoNode.html(createBtn('system_update', 'Click to start firmware update', false));
|
|
662
|
-
$(fwInfoNode).find(
|
|
662
|
+
$(fwInfoNode).find('button[name=\'fw_update\']').click(() => {
|
|
663
663
|
fwInfoNode.html(createBtn('check_circle', 'Firmware update started, check progress in logs.', true, 'icon-blue'));
|
|
664
664
|
sendTo(namespace, 'startOta', {devId: devId}, (msg) => {
|
|
665
665
|
fwInfoNode.html(createBtn('check_circle', 'Finished, see logs.', true));
|
|
@@ -669,13 +669,13 @@ function checkFwUpdate() {
|
|
|
669
669
|
} else if (msg.status == 'not_available') {
|
|
670
670
|
fwInfoNode.html(createBtn('check_circle', 'Up-to-date', true));
|
|
671
671
|
} else if (msg.status == 'fail') {
|
|
672
|
-
fwInfoNode.html(createBtn('check_circle', 'Firmware check failed, '+msg.msg, true, 'icon-red'));
|
|
672
|
+
fwInfoNode.html(createBtn('check_circle', 'Firmware check failed, ' + msg.msg, true, 'icon-red'));
|
|
673
673
|
} else {
|
|
674
674
|
fwInfoNode.html(createBtn('not_interested', 'No firmware update available', true));
|
|
675
675
|
}
|
|
676
676
|
}
|
|
677
677
|
};
|
|
678
|
-
for (let i=0;i < deviceCards.length; i++) {
|
|
678
|
+
for (let i = 0; i < deviceCards.length; i++) {
|
|
679
679
|
const deviceCard = $(deviceCards[i]);
|
|
680
680
|
const devId = getDevId(deviceCard.attr('id'));
|
|
681
681
|
getFwInfoNode(deviceCard).html('<span class="left" style="padding-top:8px">checking...</span>');
|
|
@@ -686,10 +686,8 @@ function checkFwUpdate() {
|
|
|
686
686
|
function letsPairing() {
|
|
687
687
|
messages = [];
|
|
688
688
|
sendTo(namespace, 'letsPairing', {}, function (msg) {
|
|
689
|
-
if (msg) {
|
|
690
|
-
|
|
691
|
-
showMessage(msg.error, _('Error'));
|
|
692
|
-
}
|
|
689
|
+
if (msg && msg.error) {
|
|
690
|
+
showMessage(msg.error, _('Error'));
|
|
693
691
|
}
|
|
694
692
|
});
|
|
695
693
|
}
|
|
@@ -697,10 +695,8 @@ function letsPairing() {
|
|
|
697
695
|
function touchlinkReset() {
|
|
698
696
|
messages = [];
|
|
699
697
|
sendTo(namespace, 'touchlinkReset', {}, function (msg) {
|
|
700
|
-
if (msg) {
|
|
701
|
-
|
|
702
|
-
showMessage(msg.error, _('Error'));
|
|
703
|
-
}
|
|
698
|
+
if (msg && msg.error) {
|
|
699
|
+
showMessage(msg.error, _('Error'));
|
|
704
700
|
}
|
|
705
701
|
});
|
|
706
702
|
}
|
|
@@ -708,10 +704,8 @@ function touchlinkReset() {
|
|
|
708
704
|
function joinProcess(devId) {
|
|
709
705
|
messages = [];
|
|
710
706
|
sendTo(namespace, 'letsPairing', {id: devId}, function (msg) {
|
|
711
|
-
if (msg) {
|
|
712
|
-
|
|
713
|
-
showMessage(msg.error, _('Error'));
|
|
714
|
-
}
|
|
707
|
+
if (msg && msg.error) {
|
|
708
|
+
showMessage(msg.error, _('Error'));
|
|
715
709
|
}
|
|
716
710
|
});
|
|
717
711
|
}
|
|
@@ -728,7 +722,6 @@ function getCoordinatorInfo() {
|
|
|
728
722
|
});
|
|
729
723
|
}
|
|
730
724
|
|
|
731
|
-
|
|
732
725
|
function getDevices() {
|
|
733
726
|
getCoordinatorInfo();
|
|
734
727
|
sendTo(namespace, 'getDevices', {}, function (msg) {
|
|
@@ -746,7 +739,7 @@ function getDevices() {
|
|
|
746
739
|
}
|
|
747
740
|
|
|
748
741
|
function getDeviceCards() {
|
|
749
|
-
return $('#devices .device').not(
|
|
742
|
+
return $('#devices .device').not('.group');
|
|
750
743
|
}
|
|
751
744
|
|
|
752
745
|
function getDeviceCard(devId) {
|
|
@@ -774,17 +767,25 @@ function getMap() {
|
|
|
774
767
|
// the function loadSettings has to exist ...
|
|
775
768
|
// eslint-disable-next-line no-unused-vars
|
|
776
769
|
function load(settings, onChange) {
|
|
777
|
-
|
|
778
|
-
|
|
770
|
+
settings.panID = settings.panID || 6754;
|
|
771
|
+
settings.extPanID = settings.extPanID || 'DDDDDDDDDDDDDDDD';
|
|
779
772
|
// fix for previous wrong value
|
|
780
|
-
if (settings.extPanID === 'DDDDDDDDDDDDDDD')
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
773
|
+
if (settings.extPanID === 'DDDDDDDDDDDDDDD') {
|
|
774
|
+
settings.extPanID = 'DDDDDDDDDDDDDDDD';
|
|
775
|
+
}
|
|
776
|
+
settings.precfgkey = settings.precfgkey || '01030507090B0D0F00020406080A0C0D';
|
|
777
|
+
if (settings.channel === undefined){
|
|
778
|
+
settings.channel = 11;
|
|
779
|
+
}
|
|
780
|
+
if (settings.disablePing === undefined) {
|
|
781
|
+
settings.disablePing = false;
|
|
782
|
+
}
|
|
784
783
|
|
|
785
784
|
// example: select elements with id=key and class=value and insert value
|
|
786
785
|
for (const key in settings) {
|
|
787
|
-
if (savedSettings.indexOf(key) === -1)
|
|
786
|
+
if (savedSettings.indexOf(key) === -1) {
|
|
787
|
+
continue;
|
|
788
|
+
}
|
|
788
789
|
// example: select elements with id=key and class=value and insert value
|
|
789
790
|
const value = $('#' + key + '.value');
|
|
790
791
|
if (value.attr('type') === 'checkbox') {
|
|
@@ -810,35 +811,36 @@ function load(settings, onChange) {
|
|
|
810
811
|
// Signal to admin, that no changes yet
|
|
811
812
|
onChange(false);
|
|
812
813
|
|
|
813
|
-
$('#state_cleanup_btn').click(function() {
|
|
814
|
+
$('#state_cleanup_btn').click(function () {
|
|
814
815
|
cleanConfirmation();
|
|
815
816
|
});
|
|
816
|
-
$('#fw_check_btn').click(function() {
|
|
817
|
+
$('#fw_check_btn').click(function () {
|
|
817
818
|
checkFwUpdate();
|
|
818
819
|
});
|
|
819
|
-
$('#touchlink_btn').click(function() {
|
|
820
|
+
$('#touchlink_btn').click(function () {
|
|
820
821
|
touchlinkReset();
|
|
821
822
|
showPairingProcess();
|
|
822
823
|
});
|
|
823
|
-
$('#pairing').click(function() {
|
|
824
|
-
if (!$('#pairing').hasClass('pulse'))
|
|
824
|
+
$('#pairing').click(function () {
|
|
825
|
+
if (!$('#pairing').hasClass('pulse')) {
|
|
825
826
|
letsPairing();
|
|
827
|
+
}
|
|
826
828
|
showPairingProcess();
|
|
827
829
|
});
|
|
828
830
|
|
|
829
|
-
$('#refresh').click(function() {
|
|
831
|
+
$('#refresh').click(function () {
|
|
830
832
|
getMap();
|
|
831
833
|
});
|
|
832
834
|
|
|
833
|
-
$('#reset-btn').click(function() {
|
|
835
|
+
$('#reset-btn').click(function () {
|
|
834
836
|
resetConfirmation();
|
|
835
837
|
});
|
|
836
838
|
|
|
837
|
-
$('#viewconfig').click(function() {
|
|
839
|
+
$('#viewconfig').click(function () {
|
|
838
840
|
showViewConfig();
|
|
839
841
|
});
|
|
840
842
|
|
|
841
|
-
$('#scan').click(function() {
|
|
843
|
+
$('#scan').click(function () {
|
|
842
844
|
showChannels();
|
|
843
845
|
});
|
|
844
846
|
|
|
@@ -847,18 +849,18 @@ function load(settings, onChange) {
|
|
|
847
849
|
showGroups();
|
|
848
850
|
});
|
|
849
851
|
|
|
850
|
-
$('#add_group').click(function() {
|
|
852
|
+
$('#add_group').click(function () {
|
|
851
853
|
// showGroupList(true);
|
|
852
|
-
const maxind = parseInt(Object.getOwnPropertyNames(groups).reduce((a,b) => a>b ? a : b, 0));
|
|
853
|
-
editGroupName(maxind+1, 'Group ' + maxind+1, true);
|
|
854
|
+
const maxind = parseInt(Object.getOwnPropertyNames(groups).reduce((a, b) => a > b ? a : b, 0));
|
|
855
|
+
editGroupName(maxind + 1, 'Group ' + maxind + 1, true);
|
|
854
856
|
});
|
|
855
|
-
$('#add_grp_btn').click(function() {
|
|
857
|
+
$('#add_grp_btn').click(function () {
|
|
856
858
|
// showGroupList(true);
|
|
857
|
-
const maxind = parseInt(Object.getOwnPropertyNames(groups).reduce((a,b) => a>b ? a : b, 0));
|
|
858
|
-
editGroupName(maxind+1, 'Group ' + maxind+1, true);
|
|
859
|
+
const maxind = parseInt(Object.getOwnPropertyNames(groups).reduce((a, b) => a > b ? a : b, 0));
|
|
860
|
+
editGroupName(maxind + 1, 'Group ' + maxind + 1, true);
|
|
859
861
|
});
|
|
860
862
|
|
|
861
|
-
$(document).ready(function() {
|
|
863
|
+
$(document).ready(function () {
|
|
862
864
|
$('.modal').modal({
|
|
863
865
|
startingTop: '30%',
|
|
864
866
|
endingTop: '10%',
|
|
@@ -882,7 +884,7 @@ function load(settings, onChange) {
|
|
|
882
884
|
$('#pairing').attr('data-tooltip', transText);
|
|
883
885
|
}
|
|
884
886
|
|
|
885
|
-
$('ul.tabs').on('click', 'a', function(e) {
|
|
887
|
+
$('ul.tabs').on('click', 'a', function (e) {
|
|
886
888
|
if ($(e.target).attr('id') == 'tabmap') {
|
|
887
889
|
redrawMap();
|
|
888
890
|
}
|
|
@@ -891,11 +893,11 @@ function load(settings, onChange) {
|
|
|
891
893
|
}
|
|
892
894
|
});
|
|
893
895
|
|
|
894
|
-
$('#add_exclude').click(function() {
|
|
896
|
+
$('#add_exclude').click(function () {
|
|
895
897
|
addExcludeDialog();
|
|
896
898
|
});
|
|
897
899
|
|
|
898
|
-
$('#add_binding').click(function() {
|
|
900
|
+
$('#add_binding').click(function () {
|
|
899
901
|
addBindingDialog();
|
|
900
902
|
});
|
|
901
903
|
|
|
@@ -934,7 +936,7 @@ function save(callback) {
|
|
|
934
936
|
const $this = $(this);
|
|
935
937
|
if (savedSettings.indexOf($this.attr('id')) === -1) return;
|
|
936
938
|
if ($this.hasClass('validate') && $this.hasClass('invalid')) {
|
|
937
|
-
showMessage('Invalid input for '
|
|
939
|
+
showMessage('Invalid input for ' + $this.attr('id'), _('Error'));
|
|
938
940
|
return;
|
|
939
941
|
}
|
|
940
942
|
if ($this.attr('type') === 'checkbox') {
|
|
@@ -948,7 +950,7 @@ function save(callback) {
|
|
|
948
950
|
|
|
949
951
|
|
|
950
952
|
function getDevId(adapterDevId) {
|
|
951
|
-
return adapterDevId.split('.').slice(0,3).join('.');
|
|
953
|
+
return adapterDevId.split('.').slice(0, 3).join('.');
|
|
952
954
|
}
|
|
953
955
|
|
|
954
956
|
// subscribe to changes
|
|
@@ -975,7 +977,7 @@ socket.on('stateChange', function (id, state) {
|
|
|
975
977
|
} else {
|
|
976
978
|
$('#pairing').addClass('pulse');
|
|
977
979
|
$('#pairing').html(state.val);
|
|
978
|
-
const percent = 100-100*state.val/($('#countDown').val() || 60);
|
|
980
|
+
const percent = 100 - 100 * state.val / ($('#countDown').val() || 60);
|
|
979
981
|
$('#progress_line').css('width', `${percent}%`);
|
|
980
982
|
}
|
|
981
983
|
} else if (id.match(/\.info\.pairingMessage$/)) {
|
|
@@ -1021,6 +1023,7 @@ socket.on('objectChange', function (id, obj) {
|
|
|
1021
1023
|
}
|
|
1022
1024
|
}
|
|
1023
1025
|
});
|
|
1026
|
+
|
|
1024
1027
|
/*
|
|
1025
1028
|
socket.emit('getObject', 'system.config', function (err, res) {
|
|
1026
1029
|
if (!err && res && res.common) {
|
|
@@ -1033,45 +1036,47 @@ socket.emit('getObject', 'system.config', function (err, res) {
|
|
|
1033
1036
|
function putEventToNode(devId) {
|
|
1034
1037
|
if (network) {
|
|
1035
1038
|
const nodesArray = Object.values(network.body.data.nodes._data);
|
|
1036
|
-
const node = nodesArray.find((node) => {
|
|
1039
|
+
const node = nodesArray.find((node) => {
|
|
1040
|
+
return node.id == devId;
|
|
1041
|
+
});
|
|
1037
1042
|
if (node) {
|
|
1038
1043
|
const exists = networkEvents.find((event) => {
|
|
1039
1044
|
return event.node == node.id;
|
|
1040
1045
|
});
|
|
1041
1046
|
if (!exists) {
|
|
1042
1047
|
networkEvents.push({node: node.id, radius: 0, forward: true});
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1048
|
+
// } else {
|
|
1049
|
+
// exists.radius = 0;
|
|
1050
|
+
// exists.forward = true;
|
|
1046
1051
|
}
|
|
1047
1052
|
}
|
|
1048
1053
|
}
|
|
1049
1054
|
}
|
|
1050
1055
|
|
|
1051
|
-
function showNetworkMap(devices, map){
|
|
1056
|
+
function showNetworkMap(devices, map) {
|
|
1052
1057
|
// create an object with nodes
|
|
1053
1058
|
const nodes = {};
|
|
1054
1059
|
// create an array with edges
|
|
1055
1060
|
const edges = [];
|
|
1056
1061
|
|
|
1057
1062
|
if (map.lqis == undefined || map.lqis.length === 0) { // first init
|
|
1058
|
-
$('#filterParent, #filterSibl, #filterPrvChild, #filterMesh').change(function() {
|
|
1063
|
+
$('#filterParent, #filterSibl, #filterPrvChild, #filterMesh').change(function () {
|
|
1059
1064
|
updateMapFilter();
|
|
1060
1065
|
});
|
|
1061
1066
|
}
|
|
1062
1067
|
|
|
1063
|
-
const createNode = function(dev, mapEntry) {
|
|
1068
|
+
const createNode = function (dev, mapEntry) {
|
|
1064
1069
|
if (dev.common && dev.common.type == 'group') return undefined;
|
|
1065
1070
|
const extInfo = (mapEntry && mapEntry.networkAddress) ? `\n (nwkAddr: 0x${mapEntry.networkAddress.toString(16)} | ${mapEntry.networkAddress})` : '';
|
|
1066
1071
|
const node = {
|
|
1067
1072
|
id: dev._id,
|
|
1068
|
-
label: (dev.link_quality >0 ? dev.common.name
|
|
1069
|
-
title: dev._id.replace(namespace+'.', '') + extInfo,
|
|
1073
|
+
label: (dev.link_quality > 0 ? dev.common.name : `${dev.common.name}\n(disconnected)`),
|
|
1074
|
+
title: dev._id.replace(namespace + '.', '') + extInfo,
|
|
1070
1075
|
shape: 'circularImage',
|
|
1071
1076
|
image: dev.icon,
|
|
1072
1077
|
imagePadding: {top: 5, bottom: 5, left: 5, right: 5},
|
|
1073
1078
|
color: {background: 'white', highlight: {background: 'white'}},
|
|
1074
|
-
font: {color:'#007700'},
|
|
1079
|
+
font: {color: '#007700'},
|
|
1075
1080
|
borderWidth: 1,
|
|
1076
1081
|
borderWidthSelected: 4,
|
|
1077
1082
|
};
|
|
@@ -1085,7 +1090,7 @@ function showNetworkMap(devices, map){
|
|
|
1085
1090
|
};
|
|
1086
1091
|
|
|
1087
1092
|
if (map.lqis) {
|
|
1088
|
-
map.lqis.forEach((mapEntry)=>{
|
|
1093
|
+
map.lqis.forEach((mapEntry) => {
|
|
1089
1094
|
const dev = getDevice(mapEntry.ieeeAddr);
|
|
1090
1095
|
if (!dev) {
|
|
1091
1096
|
//console.log("No dev with ieee "+mapEntry.ieeeAddr);
|
|
@@ -1098,8 +1103,7 @@ function showNetworkMap(devices, map){
|
|
|
1098
1103
|
if (node) {
|
|
1099
1104
|
nodes[mapEntry.ieeeAddr] = node;
|
|
1100
1105
|
}
|
|
1101
|
-
}
|
|
1102
|
-
else {
|
|
1106
|
+
} else {
|
|
1103
1107
|
node = nodes[mapEntry.ieeeAddr];
|
|
1104
1108
|
}
|
|
1105
1109
|
if (node) {
|
|
@@ -1117,7 +1121,7 @@ function showNetworkMap(devices, map){
|
|
|
1117
1121
|
|
|
1118
1122
|
if (mapEntry.relationship === 0 || mapEntry.relationship === 1) { // 0 - parent, 1 - child
|
|
1119
1123
|
// // parent/child
|
|
1120
|
-
if (mapEntry.status !== 'online'
|
|
1124
|
+
if (mapEntry.status !== 'online') {
|
|
1121
1125
|
label = label + ' (off)';
|
|
1122
1126
|
linkColor = '#ff0000';
|
|
1123
1127
|
}
|
|
@@ -1134,8 +1138,8 @@ function showNetworkMap(devices, map){
|
|
|
1134
1138
|
if (reverse) {
|
|
1135
1139
|
// update reverse edge
|
|
1136
1140
|
edge = reverse;
|
|
1137
|
-
edge.label += '\n'+label;
|
|
1138
|
-
edge.arrows.from = {
|
|
1141
|
+
edge.label += '\n' + label;
|
|
1142
|
+
edge.arrows.from = {enabled: false, scaleFactor: 0.5}; // start hidden if node is not selected
|
|
1139
1143
|
if (mapEntry.relationship == 1) { //
|
|
1140
1144
|
edge.color.color = linkColor;
|
|
1141
1145
|
edge.color.highlight = linkColor;
|
|
@@ -1150,7 +1154,7 @@ function showNetworkMap(devices, map){
|
|
|
1150
1154
|
size: 0, // start hidden
|
|
1151
1155
|
color: linkColor
|
|
1152
1156
|
},
|
|
1153
|
-
arrows: {
|
|
1157
|
+
arrows: {to: {enabled: false, scaleFactor: 0.5}},
|
|
1154
1158
|
//arrowStrikethrough: false,
|
|
1155
1159
|
color: {
|
|
1156
1160
|
color: linkColor,
|
|
@@ -1164,7 +1168,7 @@ function showNetworkMap(devices, map){
|
|
|
1164
1168
|
values.fromArrow = values.fromArrowScale != 1 ? true : false; // simplified, arrow existing if scale is not default value
|
|
1165
1169
|
},
|
|
1166
1170
|
label: () => {
|
|
1167
|
-
|
|
1171
|
+
// see onMapSelect workaround
|
|
1168
1172
|
// values.size = 10;
|
|
1169
1173
|
}
|
|
1170
1174
|
},
|
|
@@ -1230,15 +1234,16 @@ function showNetworkMap(devices, map){
|
|
|
1230
1234
|
const nodesArray = Object.values(nodes);
|
|
1231
1235
|
// add devices without network links to map
|
|
1232
1236
|
devices.forEach((dev) => {
|
|
1233
|
-
const node = nodesArray.find((node) => {
|
|
1237
|
+
const node = nodesArray.find((node) => {
|
|
1238
|
+
return node.id == dev._id;
|
|
1239
|
+
});
|
|
1234
1240
|
if (!node) {
|
|
1235
1241
|
const node = createNode(dev);
|
|
1236
1242
|
|
|
1237
|
-
if (node)
|
|
1238
|
-
|
|
1239
|
-
node.font = {color:'#ff0000'};
|
|
1243
|
+
if (node) {
|
|
1244
|
+
node.font = {color: '#ff0000'};
|
|
1240
1245
|
if (dev.info && dev.info.device._type == 'Coordinator') {
|
|
1241
|
-
node.font = {color:'#000000'};
|
|
1246
|
+
node.font = {color: '#000000'};
|
|
1242
1247
|
}
|
|
1243
1248
|
nodesArray.push(node);
|
|
1244
1249
|
}
|
|
@@ -1260,7 +1265,7 @@ function showNetworkMap(devices, map){
|
|
|
1260
1265
|
shape: 'box'
|
|
1261
1266
|
},
|
|
1262
1267
|
layout: {
|
|
1263
|
-
improvedLayout:true,
|
|
1268
|
+
improvedLayout: true,
|
|
1264
1269
|
}
|
|
1265
1270
|
};
|
|
1266
1271
|
|
|
@@ -1310,25 +1315,26 @@ function showNetworkMap(devices, map){
|
|
|
1310
1315
|
if (networkEvents.length > 0) {
|
|
1311
1316
|
network.redraw();
|
|
1312
1317
|
const toDelete = [];
|
|
1313
|
-
networkEvents.forEach((event, index)=>{
|
|
1318
|
+
networkEvents.forEach((event, index) => {
|
|
1314
1319
|
if (event.radius >= 1) {
|
|
1315
1320
|
toDelete.push(index);
|
|
1316
1321
|
} else {
|
|
1317
1322
|
event.radius += 0.08;
|
|
1318
1323
|
}
|
|
1319
1324
|
});
|
|
1320
|
-
toDelete.forEach((index)=>{
|
|
1325
|
+
toDelete.forEach((index) => {
|
|
1321
1326
|
networkEvents.splice(index, 1);
|
|
1322
1327
|
});
|
|
1323
1328
|
}
|
|
1324
1329
|
}
|
|
1325
|
-
|
|
1330
|
+
|
|
1331
|
+
network.on('beforeDrawing', function (ctx) {
|
|
1326
1332
|
if (networkEvents.length > 0) {
|
|
1327
|
-
networkEvents.forEach((event)=>{
|
|
1333
|
+
networkEvents.forEach((event) => {
|
|
1328
1334
|
const inode = event.node;
|
|
1329
1335
|
const nodePosition = network.getPositions();
|
|
1330
1336
|
event.radius = (event.radius > 1) ? 1 : event.radius;
|
|
1331
|
-
const cap = Math.cos(event.radius*Math.PI/2);
|
|
1337
|
+
const cap = Math.cos(event.radius * Math.PI / 2);
|
|
1332
1338
|
const colorCircle = `rgba(0, 255, 255, ${cap.toFixed(2)})`;
|
|
1333
1339
|
const colorBorder = `rgba(0, 255, 255, ${cap.toFixed(2)})`;
|
|
1334
1340
|
ctx.strokeStyle = colorCircle;
|
|
@@ -1345,11 +1351,11 @@ function showNetworkMap(devices, map){
|
|
|
1345
1351
|
function redrawMap() {
|
|
1346
1352
|
if (network != undefined && devices.length > 0) {
|
|
1347
1353
|
const width = ($('.adapter-body').width() || $('#main').width()) - 20,
|
|
1348
|
-
height = ($('.adapter-body').height() || ($('#main').height())) -120;
|
|
1354
|
+
height = ($('.adapter-body').height() || ($('#main').height())) - 120;
|
|
1349
1355
|
network.setSize(width, height);
|
|
1350
1356
|
network.redraw();
|
|
1351
1357
|
network.fit();
|
|
1352
|
-
network.moveTo({offset:{x:0.5 * width, y:0.5 * height}});
|
|
1358
|
+
network.moveTo({offset: {x: 0.5 * width, y: 0.5 * height}});
|
|
1353
1359
|
}
|
|
1354
1360
|
}
|
|
1355
1361
|
|
|
@@ -1363,9 +1369,9 @@ function updateMapFilter() {
|
|
|
1363
1369
|
const invisColor = $('#filterMesh').is(':checked') ? 0.2 : 0;
|
|
1364
1370
|
mapEdges.forEach((edge) => {
|
|
1365
1371
|
if (((edge.relationship === 0 || edge.relationship === 1) && showParent)
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1372
|
+
|| (edge.relationship === 2 && showSibl)
|
|
1373
|
+
|| (edge.relationship === 3 && showParent) // ignore relationship "unknown"
|
|
1374
|
+
|| (edge.relationship === 4 && showPrvChild)) {
|
|
1369
1375
|
edge.color.opacity = 1.0;
|
|
1370
1376
|
} else {
|
|
1371
1377
|
edge.color.opacity = invisColor;
|
|
@@ -1389,13 +1395,15 @@ function getComPorts(onChange) {
|
|
|
1389
1395
|
// }, 1000);
|
|
1390
1396
|
// return;
|
|
1391
1397
|
// }
|
|
1392
|
-
if (!list)
|
|
1398
|
+
if (!list) {
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1393
1401
|
const element = $('#ports');
|
|
1394
1402
|
for (let j = 0; j < list.length; j++) {
|
|
1395
|
-
element.append('<li><a href="#!">' + list[j].comName +'</a></li>');
|
|
1403
|
+
element.append('<li><a href="#!" data-value="' + list[j].comName + '">' + list[j].comName + (list[j].label ? (' [' + list[j].label + ']') : '') + '</a></li>');
|
|
1396
1404
|
}
|
|
1397
|
-
$('#ports a').click(function() {
|
|
1398
|
-
$('#port').val($(this).
|
|
1405
|
+
$('#ports a').click(function () {
|
|
1406
|
+
$('#port').val($(this).data('value'));
|
|
1399
1407
|
Materialize.updateTextFields();
|
|
1400
1408
|
onChange();
|
|
1401
1409
|
});
|
|
@@ -1405,29 +1413,33 @@ function getComPorts(onChange) {
|
|
|
1405
1413
|
function loadDeveloperTab() {
|
|
1406
1414
|
// fill device selector
|
|
1407
1415
|
updateSelect('#dev', devices,
|
|
1408
|
-
function(key, device) {
|
|
1416
|
+
function (key, device) {
|
|
1409
1417
|
if (device.hasOwnProperty('info')) {
|
|
1410
|
-
if (device.info.device._type
|
|
1418
|
+
if (device.info.device._type === 'Coordinator') {
|
|
1411
1419
|
return null;
|
|
1412
1420
|
}
|
|
1413
1421
|
return `${device.common.name} (${device.info.name})`;
|
|
1414
1422
|
} else { // fallback if device in list but not paired
|
|
1415
|
-
device.common.name + ' ' +device.native.id;
|
|
1423
|
+
return device.common.name + ' ' + device.native.id;
|
|
1416
1424
|
}
|
|
1417
1425
|
},
|
|
1418
|
-
function(key, device) {
|
|
1426
|
+
function (key, device) {
|
|
1419
1427
|
return device._id;
|
|
1420
1428
|
});
|
|
1421
1429
|
// add groups to device selector
|
|
1422
1430
|
const groupList = [];
|
|
1423
1431
|
for (const key in groups) {
|
|
1424
|
-
groupList.push({
|
|
1432
|
+
groupList.push({
|
|
1433
|
+
_id: namespace + '.' + key.toString(16).padStart(16, '0'),
|
|
1434
|
+
groupId: key,
|
|
1435
|
+
groupName: groups[key]
|
|
1436
|
+
});
|
|
1425
1437
|
}
|
|
1426
1438
|
updateSelect('#dev', groupList,
|
|
1427
|
-
function(key, device) {
|
|
1428
|
-
return 'Group '+device.groupId+': '+device.groupName;
|
|
1439
|
+
function (key, device) {
|
|
1440
|
+
return 'Group ' + device.groupId + ': ' + device.groupName;
|
|
1429
1441
|
},
|
|
1430
|
-
function(key, device) {
|
|
1442
|
+
function (key, device) {
|
|
1431
1443
|
return device._id;
|
|
1432
1444
|
}, true);
|
|
1433
1445
|
|
|
@@ -1437,10 +1449,10 @@ function loadDeveloperTab() {
|
|
|
1437
1449
|
populateSelector('#type', 'typeList', this.value);
|
|
1438
1450
|
|
|
1439
1451
|
if (responseCodes == false) {
|
|
1440
|
-
const getValue = function() { // convert to number if needed
|
|
1452
|
+
const getValue = function () { // convert to number if needed
|
|
1441
1453
|
let attrData = $('#value-input').val();
|
|
1442
1454
|
if (attrData.startsWith('"') && attrData.endsWith('"')) {
|
|
1443
|
-
attrData = attrData.substr(1, attrData.length -2);
|
|
1455
|
+
attrData = attrData.substr(1, attrData.length - 2);
|
|
1444
1456
|
} else {
|
|
1445
1457
|
const numValue = Number(attrData);
|
|
1446
1458
|
attrData = !isNaN(numValue) ? numValue : attrData;
|
|
@@ -1465,35 +1477,38 @@ function loadDeveloperTab() {
|
|
|
1465
1477
|
return data;
|
|
1466
1478
|
};
|
|
1467
1479
|
|
|
1468
|
-
const prepareExpertData = function() {
|
|
1480
|
+
const prepareExpertData = function () {
|
|
1469
1481
|
try {
|
|
1470
1482
|
return JSON.parse($('#expert-json').val());
|
|
1471
1483
|
} catch (exception) {
|
|
1472
1484
|
showDevRunInfo('JSON error', exception, 'yellow');
|
|
1473
1485
|
}
|
|
1474
1486
|
};
|
|
1475
|
-
const setExpertData = function(prop, value, removeIfEmpty = true) {
|
|
1487
|
+
const setExpertData = function (prop, value, removeIfEmpty = true) {
|
|
1476
1488
|
if (!$('#expert-mode').is(':checked')) {
|
|
1477
1489
|
return;
|
|
1478
1490
|
}
|
|
1479
|
-
if (!removeIfEmpty && value == null) {
|
|
1491
|
+
if (!removeIfEmpty && value == null) {
|
|
1492
|
+
value = '';
|
|
1493
|
+
}
|
|
1480
1494
|
let data;
|
|
1481
1495
|
if (prop) {
|
|
1482
1496
|
data = prepareExpertData();
|
|
1483
1497
|
// https://stackoverflow.com/a/6394168/6937282
|
|
1484
|
-
const assignVal = function index(obj,is, value) {
|
|
1498
|
+
const assignVal = function index(obj, is, value) {
|
|
1485
1499
|
if (typeof is == 'string') {
|
|
1486
|
-
return index(obj,is.split('.'), value);
|
|
1487
|
-
} else if (is.length
|
|
1500
|
+
return index(obj, is.split('.'), value);
|
|
1501
|
+
} else if (is.length === 1 && value !== undefined) {
|
|
1488
1502
|
if (value == null) {
|
|
1489
1503
|
return delete obj[is[0]];
|
|
1490
1504
|
} else {
|
|
1491
1505
|
return obj[is[0]] = value;
|
|
1492
1506
|
}
|
|
1493
|
-
} else if (is.length
|
|
1507
|
+
} else if (!is.length) {
|
|
1494
1508
|
return obj;
|
|
1495
|
-
} else
|
|
1496
|
-
return index(obj[is[0]],is.slice(1), value);
|
|
1509
|
+
} else {
|
|
1510
|
+
return index(obj[is[0]], is.slice(1), value);
|
|
1511
|
+
}
|
|
1497
1512
|
};
|
|
1498
1513
|
assignVal(data, prop, value);
|
|
1499
1514
|
} else {
|
|
@@ -1503,7 +1518,7 @@ function loadDeveloperTab() {
|
|
|
1503
1518
|
};
|
|
1504
1519
|
|
|
1505
1520
|
// init event listener only at first load
|
|
1506
|
-
$('#dev-selector').change(function() {
|
|
1521
|
+
$('#dev-selector').change(function () {
|
|
1507
1522
|
if (this.selectedIndex <= 0) {
|
|
1508
1523
|
return;
|
|
1509
1524
|
}
|
|
@@ -1514,48 +1529,48 @@ function loadDeveloperTab() {
|
|
|
1514
1529
|
|
|
1515
1530
|
const epList = device ? device.info.device._endpoints : null;
|
|
1516
1531
|
updateSelect('#ep', epList,
|
|
1517
|
-
function(key, ep) {
|
|
1532
|
+
function (key, ep) {
|
|
1518
1533
|
return ep.ID;
|
|
1519
1534
|
},
|
|
1520
|
-
function(key, ep) {
|
|
1535
|
+
function (key, ep) {
|
|
1521
1536
|
return ep.ID;
|
|
1522
1537
|
});
|
|
1523
1538
|
setExpertData('devId', this.value);
|
|
1524
1539
|
setExpertData('ep', $('#ep-selector').val(), false);
|
|
1525
1540
|
});
|
|
1526
1541
|
|
|
1527
|
-
$('#ep-selector').change(function() {
|
|
1542
|
+
$('#ep-selector').change(function () {
|
|
1528
1543
|
setExpertData('ep', this.value);
|
|
1529
1544
|
});
|
|
1530
1545
|
|
|
1531
|
-
$('#cid-selector').change(function() {
|
|
1546
|
+
$('#cid-selector').change(function () {
|
|
1532
1547
|
populateSelector('#attrid', 'attrIdList', this.value);
|
|
1533
|
-
if ($('#cmd-type-selector').val()
|
|
1548
|
+
if ($('#cmd-type-selector').val() === 'functional') {
|
|
1534
1549
|
const cid = $('#cid-selector option:selected').val();
|
|
1535
1550
|
populateSelector('#cmd', 'cmdListFunctional', cid);
|
|
1536
1551
|
}
|
|
1537
1552
|
setExpertData('cid', this.value);
|
|
1538
1553
|
});
|
|
1539
1554
|
|
|
1540
|
-
$('#cmd-type-selector').change(function() {
|
|
1541
|
-
if (this.value
|
|
1555
|
+
$('#cmd-type-selector').change(function () {
|
|
1556
|
+
if (this.value === 'foundation') {
|
|
1542
1557
|
populateSelector('#cmd', 'cmdListFoundation');
|
|
1543
|
-
} else if (this.value
|
|
1558
|
+
} else if (this.value === 'functional') {
|
|
1544
1559
|
const cid = $('#cid-selector option:selected').val();
|
|
1545
1560
|
populateSelector('#cmd', 'cmdListFunctional', cid);
|
|
1546
1561
|
}
|
|
1547
1562
|
setExpertData('cmdType', this.value);
|
|
1548
1563
|
});
|
|
1549
1564
|
|
|
1550
|
-
$('#cmd-selector').change(function() {
|
|
1565
|
+
$('#cmd-selector').change(function () {
|
|
1551
1566
|
setExpertData('cmd', this.value);
|
|
1552
1567
|
});
|
|
1553
|
-
$('#attrid-selector').change(function() {
|
|
1554
|
-
setExpertData('zclData', {[this.value]:{}});
|
|
1568
|
+
$('#attrid-selector').change(function () {
|
|
1569
|
+
setExpertData('zclData', {[this.value]: {}});
|
|
1555
1570
|
});
|
|
1556
1571
|
|
|
1557
1572
|
// value selector checkbox
|
|
1558
|
-
$('#value-needed').change(function() {
|
|
1573
|
+
$('#value-needed').change(function () {
|
|
1559
1574
|
const attr = $('#attrid-selector').val();
|
|
1560
1575
|
let attrData = null;
|
|
1561
1576
|
if (this.checked === true) {
|
|
@@ -1564,17 +1579,17 @@ function loadDeveloperTab() {
|
|
|
1564
1579
|
} else {
|
|
1565
1580
|
$('#value-input').attr('disabled', 'disabled');
|
|
1566
1581
|
}
|
|
1567
|
-
setExpertData('zclData.'+attr, attrData);
|
|
1582
|
+
setExpertData('zclData.' + attr, attrData);
|
|
1568
1583
|
$('#type-selector').select();
|
|
1569
1584
|
Materialize.updateTextFields();
|
|
1570
1585
|
});
|
|
1571
1586
|
|
|
1572
|
-
$('#value-input').keyup(function() {
|
|
1587
|
+
$('#value-input').keyup(function () {
|
|
1573
1588
|
const attr = $('#attrid-selector').val();
|
|
1574
|
-
setExpertData('zclData.'+attr, getValue());
|
|
1589
|
+
setExpertData('zclData.' + attr, getValue());
|
|
1575
1590
|
});
|
|
1576
1591
|
|
|
1577
|
-
$('#expert-mode').change(function() {
|
|
1592
|
+
$('#expert-mode').change(function () {
|
|
1578
1593
|
if (this.checked === true) {
|
|
1579
1594
|
setExpertData();
|
|
1580
1595
|
$('#expert-json-box').css('display', 'inline-block');
|
|
@@ -1585,7 +1600,7 @@ function loadDeveloperTab() {
|
|
|
1585
1600
|
Materialize.updateTextFields();
|
|
1586
1601
|
});
|
|
1587
1602
|
|
|
1588
|
-
$('#dev-send-btn').click(function() {
|
|
1603
|
+
$('#dev-send-btn').click(function () {
|
|
1589
1604
|
let data;
|
|
1590
1605
|
if ($('#expert-mode').is(':checked')) {
|
|
1591
1606
|
data = prepareExpertData();
|
|
@@ -1593,7 +1608,7 @@ function loadDeveloperTab() {
|
|
|
1593
1608
|
data = prepareData();
|
|
1594
1609
|
}
|
|
1595
1610
|
sendToZigbee(data.devId, data.ep, data.cid, data.cmd, data.cmdType, data.zclData, data.cfg, function (reply) {
|
|
1596
|
-
console.log('Reply from zigbee: '+ JSON.stringify(reply));
|
|
1611
|
+
console.log('Reply from zigbee: ' + JSON.stringify(reply));
|
|
1597
1612
|
if (reply.hasOwnProperty('localErr')) {
|
|
1598
1613
|
showDevRunInfo(reply.localErr, reply.errMsg, 'yellow');
|
|
1599
1614
|
} else if (reply.hasOwnProperty('localStatus')) {
|
|
@@ -1634,25 +1649,34 @@ function loadDeveloperTab() {
|
|
|
1634
1649
|
*/
|
|
1635
1650
|
function sendToZigbee(id, ep, cid, cmd, cmdType, zclData, cfg, callback) {
|
|
1636
1651
|
if (!id) {
|
|
1637
|
-
if (callback) {
|
|
1652
|
+
if (callback) {
|
|
1653
|
+
callback({localErr: 'Incomplete', errMsg: 'Please select Device and Endpoint!'});
|
|
1654
|
+
}
|
|
1638
1655
|
return;
|
|
1639
1656
|
}
|
|
1640
1657
|
if (!cid || !cmd || !cmdType) {
|
|
1641
|
-
if (callback) {
|
|
1658
|
+
if (callback) {
|
|
1659
|
+
callback({
|
|
1660
|
+
localErr: 'Incomplete',
|
|
1661
|
+
errMsg: 'Please choose ClusterId, Command, CommandType and AttributeId!'
|
|
1662
|
+
});
|
|
1663
|
+
}
|
|
1642
1664
|
return;
|
|
1643
1665
|
}
|
|
1644
1666
|
const data = {id: id, ep: ep, cid: cid, cmd: cmd, cmdType: cmdType, zclData: zclData, cfg: cfg};
|
|
1645
|
-
if (callback) {
|
|
1667
|
+
if (callback) {
|
|
1668
|
+
callback({localStatus: 'Send', errMsg: 'Waiting for reply...'});
|
|
1669
|
+
}
|
|
1646
1670
|
|
|
1647
|
-
const sendTimeout = setTimeout(function() {
|
|
1671
|
+
const sendTimeout = setTimeout(function () {
|
|
1648
1672
|
if (callback) {
|
|
1649
1673
|
callback({localErr: 'Timeout', errMsg: 'We did not receive any response.'});
|
|
1650
1674
|
}
|
|
1651
1675
|
}, 15000);
|
|
1652
1676
|
|
|
1653
|
-
console.log('Send to zigbee, id '+id+ ',ep '+ep+', cid '+cid+', cmd '+cmd+', cmdType '+cmdType+', zclData '+JSON.stringify(zclData));
|
|
1677
|
+
console.log('Send to zigbee, id ' + id + ',ep ' + ep + ', cid ' + cid + ', cmd ' + cmd + ', cmdType ' + cmdType + ', zclData ' + JSON.stringify(zclData));
|
|
1654
1678
|
|
|
1655
|
-
sendTo(namespace, 'sendToZigbee', data, function(reply) {
|
|
1679
|
+
sendTo(namespace, 'sendToZigbee', data, function (reply) {
|
|
1656
1680
|
clearTimeout(sendTimeout);
|
|
1657
1681
|
if (callback) {
|
|
1658
1682
|
callback(reply);
|
|
@@ -1665,11 +1689,10 @@ function sendToZigbee(id, ep, cid, cmd, cmdType, zclData, cfg, callback) {
|
|
|
1665
1689
|
*/
|
|
1666
1690
|
function showDevRunInfo(result, text, level) {
|
|
1667
1691
|
const card = $('#devActResult');
|
|
1668
|
-
if (level
|
|
1669
|
-
card.removeClass(
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
|
-
card.removeClass( 'yellow-text' ).addClass( 'white-text' );
|
|
1692
|
+
if (level === 'yellow') {
|
|
1693
|
+
card.removeClass('white-text').addClass('yellow-text');
|
|
1694
|
+
} else {
|
|
1695
|
+
card.removeClass('yellow-text').addClass('white-text');
|
|
1673
1696
|
}
|
|
1674
1697
|
$('#devActResult').text(result);
|
|
1675
1698
|
$('#devInfoMsg').text(text);
|
|
@@ -1677,13 +1700,13 @@ function showDevRunInfo(result, text, level) {
|
|
|
1677
1700
|
|
|
1678
1701
|
function addDevLog(reply) {
|
|
1679
1702
|
const statusCode = reply.statusCode;
|
|
1680
|
-
let logHtml = '<span>'+JSON.stringify(reply.msg)+'</span><br>';
|
|
1703
|
+
let logHtml = '<span>' + JSON.stringify(reply.msg) + '</span><br>';
|
|
1681
1704
|
if (responseCodes != undefined) {
|
|
1682
1705
|
const status = Object.keys(responseCodes).find(key => responseCodes[key] === statusCode);
|
|
1683
1706
|
if (statusCode == 0) {
|
|
1684
|
-
logHtml = '<span class="green-text">'+status+'</span> '+logHtml;
|
|
1707
|
+
logHtml = '<span class="green-text">' + status + '</span> ' + logHtml;
|
|
1685
1708
|
} else {
|
|
1686
|
-
logHtml = '<span class="yellow-text">'+status+'</span> '+logHtml;
|
|
1709
|
+
logHtml = '<span class="yellow-text">' + status + '</span> ' + logHtml;
|
|
1687
1710
|
}
|
|
1688
1711
|
}
|
|
1689
1712
|
const logView = $('#dev_result_log');
|
|
@@ -1695,7 +1718,7 @@ function addDevLog(reply) {
|
|
|
1695
1718
|
* Query adapter and update select with result
|
|
1696
1719
|
*/
|
|
1697
1720
|
function populateSelector(selectId, key, cid) {
|
|
1698
|
-
$(selectId+'>option:enabled').remove(); // remove existing elements
|
|
1721
|
+
$(selectId + '>option:enabled').remove(); // remove existing elements
|
|
1699
1722
|
$(selectId).select();
|
|
1700
1723
|
if (cid == '-2') {
|
|
1701
1724
|
updateSelect(selectId, null);
|
|
@@ -1706,7 +1729,7 @@ function populateSelector(selectId, key, cid) {
|
|
|
1706
1729
|
if (key === 'attrIdList') {
|
|
1707
1730
|
updateSelect(selectId, list,
|
|
1708
1731
|
(attrName, attr) => {
|
|
1709
|
-
return attrName + ' ('+attr.ID +', type '+attr.type+')';
|
|
1732
|
+
return attrName + ' (' + attr.ID + ', type ' + attr.type + ')';
|
|
1710
1733
|
},
|
|
1711
1734
|
(attrName) => {
|
|
1712
1735
|
return attrName;
|
|
@@ -1714,7 +1737,7 @@ function populateSelector(selectId, key, cid) {
|
|
|
1714
1737
|
} else if (key === 'typeList') {
|
|
1715
1738
|
updateSelect(selectId, list,
|
|
1716
1739
|
(name, val) => {
|
|
1717
|
-
return name +' ('+val+')';
|
|
1740
|
+
return name + ' (' + val + ')';
|
|
1718
1741
|
},
|
|
1719
1742
|
(name, val) => {
|
|
1720
1743
|
return val;
|
|
@@ -1722,7 +1745,7 @@ function populateSelector(selectId, key, cid) {
|
|
|
1722
1745
|
} else {
|
|
1723
1746
|
updateSelect(selectId, list,
|
|
1724
1747
|
(propName, propInfo) => {
|
|
1725
|
-
return propName +' ('+propInfo.ID+')';
|
|
1748
|
+
return propName + ' (' + propInfo.ID + ')';
|
|
1726
1749
|
},
|
|
1727
1750
|
(propName) => {
|
|
1728
1751
|
return propName;
|
|
@@ -1732,32 +1755,31 @@ function populateSelector(selectId, key, cid) {
|
|
|
1732
1755
|
}
|
|
1733
1756
|
|
|
1734
1757
|
function updateSelect(id, list, getText, getId, append = false) {
|
|
1735
|
-
const selectId = id+'-selector';
|
|
1758
|
+
const selectId = id + '-selector';
|
|
1736
1759
|
const mySelect = $(selectId);
|
|
1737
1760
|
if (!append) {
|
|
1738
|
-
$(selectId+'>:not(:first[disabled])').remove(); // remove existing elements, except first if disabled, (is 'Select...' info)
|
|
1761
|
+
$(selectId + '>:not(:first[disabled])').remove(); // remove existing elements, except first if disabled, (is 'Select...' info)
|
|
1739
1762
|
mySelect.select();
|
|
1740
1763
|
}
|
|
1741
1764
|
if (list == null && !append) {
|
|
1742
1765
|
const infoOption = new Option('Nothing available');
|
|
1743
1766
|
infoOption.disabled = true;
|
|
1744
|
-
mySelect.append(
|
|
1745
|
-
}
|
|
1746
|
-
else {
|
|
1767
|
+
mySelect.append(infoOption);
|
|
1768
|
+
} else {
|
|
1747
1769
|
const keys = Object.keys(list); // is index in case of array
|
|
1748
|
-
for (let i=0; i<keys.length; i++) {
|
|
1770
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1749
1771
|
const key = keys[i];
|
|
1750
1772
|
const item = list[key];
|
|
1751
1773
|
const optionText = getText(key, item);
|
|
1752
1774
|
if (optionText == null) {
|
|
1753
1775
|
continue;
|
|
1754
1776
|
}
|
|
1755
|
-
mySelect.append(
|
|
1777
|
+
mySelect.append(new Option(optionText, getId(key, item)));
|
|
1756
1778
|
}
|
|
1757
1779
|
}
|
|
1758
1780
|
|
|
1759
|
-
if ($(id+'-c-input').length > 0) {
|
|
1760
|
-
mySelect.append(
|
|
1781
|
+
if ($(id + '-c-input').length > 0) {
|
|
1782
|
+
mySelect.append(new Option('CUSTOM', -2));
|
|
1761
1783
|
}
|
|
1762
1784
|
// update select element (Materialize)
|
|
1763
1785
|
mySelect.select();
|
|
@@ -1786,17 +1808,17 @@ function showGroups() {
|
|
|
1786
1808
|
const element = $('#groups_table');
|
|
1787
1809
|
for (const j in groups) {
|
|
1788
1810
|
if (groups.hasOwnProperty(j)) {
|
|
1789
|
-
element.append(`<tr id="group_${j}" class="group"><td>${j}</td><td><div>${groups[j]}<span class="right"
|
|
1790
|
-
|
|
1791
|
-
|
|
1811
|
+
element.append(`<tr id="group_${j}" class="group"><td>${j}</td><td><div>${groups[j]}<span class="right">` +
|
|
1812
|
+
`<a id="${j}" name="groupedit" class="waves-effect green btn-floating"><i class="material-icons">edit</i></a>` +
|
|
1813
|
+
`<a id="${j}" name="groupdelete" class="waves-effect red btn-floating"><i class="material-icons">delete</i></a></span></div></td></tr>`);
|
|
1792
1814
|
}
|
|
1793
1815
|
}
|
|
1794
|
-
$(
|
|
1816
|
+
$('a.btn-floating[name=\'groupedit\']').click(function () {
|
|
1795
1817
|
const index = $(this).attr('id'),
|
|
1796
1818
|
name = groups[index];
|
|
1797
1819
|
editGroupName(index, name, false);
|
|
1798
1820
|
});
|
|
1799
|
-
$(
|
|
1821
|
+
$('a.btn-floating[name=\'groupdelete\']').click(function () {
|
|
1800
1822
|
const index = $(this).attr('id'),
|
|
1801
1823
|
name = groups[index];
|
|
1802
1824
|
deleteGroupConfirmation(index, name);
|
|
@@ -1808,53 +1830,51 @@ function editGroupName(id, name, isnew) {
|
|
|
1808
1830
|
//console.log('devices: '+ JSON.stringify(devices));
|
|
1809
1831
|
const groupables = [];
|
|
1810
1832
|
for (const d of devices) {
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1833
|
+
if (d && d.info && d.info.endpoints) {
|
|
1834
|
+
for (const ep of d.info.endpoints) {
|
|
1835
|
+
if (ep.inputClusters.includes(4)) {
|
|
1836
|
+
groupables.push(ep);
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1817
1839
|
}
|
|
1818
|
-
|
|
1819
|
-
//console.log('device ' + JSON.stringify(d));
|
|
1840
|
+
//console.log('device ' + JSON.stringify(d));
|
|
1820
1841
|
}
|
|
1821
1842
|
|
|
1822
1843
|
//var text = 'Enter new name for "'+name+'" ('+id+')?';
|
|
1823
1844
|
if (isnew) {
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
}
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
$('#groupedit').find(
|
|
1836
|
-
$('#groupedit
|
|
1837
|
-
$(
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
newName = $('#groupedit').find("input[id='g_name']").val();
|
|
1845
|
+
$('#groupedit').find('.editgroup').addClass('hide');
|
|
1846
|
+
$('#groupedit').find('.addgroup').removeClass('hide');
|
|
1847
|
+
$('#groupedit').find('.input-field.members').addClass('hide');
|
|
1848
|
+
$('#groupedit').find('.input-field.groupid').removeClass('hide');
|
|
1849
|
+
} else {
|
|
1850
|
+
$('#groupedit').find('.editgroup').removeClass('hide');
|
|
1851
|
+
$('#groupedit').find('.addgroup').addClass('hide');
|
|
1852
|
+
$('#groupedit').find('.input-field.members').removeClass('hide');
|
|
1853
|
+
$('#groupedit').find('.input-field.groupid').addClass('hide');
|
|
1854
|
+
}
|
|
1855
|
+
$('#groupedit').find('input[id=\'g_index\']').val(id);
|
|
1856
|
+
$('#groupedit').find('input[id=\'g_name\']').val(name);
|
|
1857
|
+
$('#groupedit a.btn[name=\'save\']').unbind('click');
|
|
1858
|
+
$('#groupedit a.btn[name=\'save\']').click(() => {
|
|
1859
|
+
const newId = $('#groupedit').find('input[id=\'g_index\']').val(),
|
|
1860
|
+
newName = $('#groupedit').find('input[id=\'g_name\']').val();
|
|
1841
1861
|
updateGroup(id, newId, newName);
|
|
1842
|
-
//
|
|
1843
|
-
//
|
|
1862
|
+
// showGroups();
|
|
1863
|
+
// getDevices();
|
|
1844
1864
|
});
|
|
1845
1865
|
$('#groupedit').modal('open');
|
|
1846
1866
|
Materialize.updateTextFields();
|
|
1847
1867
|
}
|
|
1848
1868
|
|
|
1849
1869
|
function deleteGroupConfirmation(id, name) {
|
|
1850
|
-
const text = translateWord('Do you really whant to delete group') + ' "'+name+'" ('+id+')?';
|
|
1870
|
+
const text = translateWord('Do you really whant to delete group') + ' "' + name + '" (' + id + ')?';
|
|
1851
1871
|
$('#modaldelete').find('p').text(text);
|
|
1852
1872
|
$('#forcediv').addClass('hide');
|
|
1853
|
-
$(
|
|
1854
|
-
$(
|
|
1873
|
+
$('#modaldelete a.btn[name=\'yes\']').unbind('click');
|
|
1874
|
+
$('#modaldelete a.btn[name=\'yes\']').click(() => {
|
|
1855
1875
|
deleteGroup(id);
|
|
1856
|
-
//
|
|
1857
|
-
//
|
|
1876
|
+
// showGroups();
|
|
1877
|
+
// getDevices();
|
|
1858
1878
|
});
|
|
1859
1879
|
$('#modaldelete').modal('open');
|
|
1860
1880
|
}
|
|
@@ -1862,8 +1882,8 @@ function deleteGroupConfirmation(id, name) {
|
|
|
1862
1882
|
function updateGroup(id, newId, newName) {
|
|
1863
1883
|
delete groups[id];
|
|
1864
1884
|
groups[newId] = newName;
|
|
1865
|
-
sendTo(namespace, 'renameGroup', {
|
|
1866
|
-
if (msg &&
|
|
1885
|
+
sendTo(namespace, 'renameGroup', {id: newId, name: newName}, function (msg) {
|
|
1886
|
+
if (msg && msg.error) {
|
|
1867
1887
|
showMessage(msg.error, _('Error'));
|
|
1868
1888
|
}
|
|
1869
1889
|
getDevices();
|
|
@@ -1872,8 +1892,8 @@ function updateGroup(id, newId, newName) {
|
|
|
1872
1892
|
|
|
1873
1893
|
function deleteGroup(id) {
|
|
1874
1894
|
delete groups[id];
|
|
1875
|
-
sendTo(namespace, 'deleteGroup', id
|
|
1876
|
-
if (msg &&
|
|
1895
|
+
sendTo(namespace, 'deleteGroup', id, function (msg) {
|
|
1896
|
+
if (msg && msg.error) {
|
|
1877
1897
|
showMessage(msg.error, _('Error'));
|
|
1878
1898
|
}
|
|
1879
1899
|
getDevices();
|
|
@@ -1881,58 +1901,55 @@ function deleteGroup(id) {
|
|
|
1881
1901
|
}
|
|
1882
1902
|
|
|
1883
1903
|
function updateDev(id, newName, newGroups) {
|
|
1884
|
-
const dev = devices.find((d) => d._id
|
|
1885
|
-
if (dev && dev.common.name
|
|
1904
|
+
const dev = devices.find((d) => d._id === id);
|
|
1905
|
+
if (dev && dev.common.name !== newName) {
|
|
1886
1906
|
renameDevice(id, newName);
|
|
1887
1907
|
}
|
|
1888
|
-
const keys = Object.keys(newGroups)
|
|
1889
|
-
if (keys && keys.length)
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
});
|
|
1902
|
-
showWaitingDialog('Updating group memberships', 10);
|
|
1908
|
+
const keys = Object.keys(newGroups);
|
|
1909
|
+
if (keys && keys.length) {
|
|
1910
|
+
sendTo(namespace, 'updateGroupMembership', {id: id, groups: newGroups}, function (msg) {
|
|
1911
|
+
closeWaitingDialog();
|
|
1912
|
+
if (msg && msg.error) {
|
|
1913
|
+
showMessage(msg.error, _('Error'));
|
|
1914
|
+
} else {
|
|
1915
|
+
// save dev-groups on success
|
|
1916
|
+
dev.groups = newGroups;
|
|
1917
|
+
}
|
|
1918
|
+
showDevices();
|
|
1919
|
+
});
|
|
1920
|
+
showWaitingDialog('Updating group memberships', 10);
|
|
1903
1921
|
|
|
1904
1922
|
}
|
|
1905
|
-
/*
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1923
|
+
/*
|
|
1924
|
+
if (dev.info.device._type == 'Router') {
|
|
1925
|
+
const oldGroups = devGroups[id] || [];
|
|
1926
|
+
if (oldGroups.toString() != newGroups.toString()) {
|
|
1927
|
+
devGroups[id] = newGroups;
|
|
1928
|
+
sendTo(namespace, 'updateGroupMembership', { id: id, groups: newGroups }, function (msg) {
|
|
1929
|
+
if (msg && msg.error) {
|
|
1930
|
+
showMessage(msg.error, _('Error'));
|
|
1931
|
+
}
|
|
1932
|
+
else {
|
|
1933
|
+
// save dev-groups on success
|
|
1934
|
+
dev.groups = newGroups;
|
|
1935
|
+
}
|
|
1936
|
+
showDevices();
|
|
1937
|
+
});
|
|
1938
|
+
}
|
|
1920
1939
|
}
|
|
1921
|
-
|
|
1922
|
-
*/
|
|
1940
|
+
*/
|
|
1923
1941
|
}
|
|
1924
1942
|
|
|
1925
1943
|
function resetConfirmation() {
|
|
1926
1944
|
$('#modalreset').modal('open');
|
|
1927
1945
|
const btn = $('#modalreset .modal-content a.btn');
|
|
1928
1946
|
btn.unbind('click');
|
|
1929
|
-
btn.click(function(e) {
|
|
1947
|
+
btn.click(function (e) {
|
|
1930
1948
|
sendTo(namespace, 'reset', {mode: e.target.id}, function (err) {
|
|
1931
1949
|
if (err) {
|
|
1932
1950
|
console.log(err);
|
|
1933
|
-
}
|
|
1934
|
-
|
|
1935
|
-
console.log('Reseted');
|
|
1951
|
+
} else {
|
|
1952
|
+
console.log('Reset done');
|
|
1936
1953
|
}
|
|
1937
1954
|
});
|
|
1938
1955
|
});
|
|
@@ -1942,7 +1959,7 @@ function showViewConfig() {
|
|
|
1942
1959
|
$('#modalviewconfig').modal('open');
|
|
1943
1960
|
}
|
|
1944
1961
|
|
|
1945
|
-
function prepareBindingDialog(bindObj){
|
|
1962
|
+
function prepareBindingDialog(bindObj) {
|
|
1946
1963
|
const binddevices = devices.slice();
|
|
1947
1964
|
binddevices.unshift('');
|
|
1948
1965
|
const bind_source = (bindObj) ? [bindObj.bind_source] : [''];
|
|
@@ -1953,12 +1970,12 @@ function prepareBindingDialog(bindObj){
|
|
|
1953
1970
|
const allowClustersName = {5: 'genScenes', 6: 'genOnOff', 8: 'genLevelCtrl', 768: 'lightingColorCtrl'};
|
|
1954
1971
|
// fill device selector
|
|
1955
1972
|
list2select('#bind_source', binddevices, bind_source,
|
|
1956
|
-
function(key, device) {
|
|
1973
|
+
function (key, device) {
|
|
1957
1974
|
if (device == '') {
|
|
1958
1975
|
return 'Select source device';
|
|
1959
1976
|
}
|
|
1960
1977
|
if (device.hasOwnProperty('info')) {
|
|
1961
|
-
if (device.info.device._type
|
|
1978
|
+
if (device.info.device._type === 'Coordinator') {
|
|
1962
1979
|
return null;
|
|
1963
1980
|
}
|
|
1964
1981
|
// check for output clusters
|
|
@@ -1978,19 +1995,18 @@ function prepareBindingDialog(bindObj){
|
|
|
1978
1995
|
return null;
|
|
1979
1996
|
}
|
|
1980
1997
|
return device.common.name;
|
|
1981
|
-
}
|
|
1982
|
-
|
|
1983
|
-
device.common.name + ' ' +device.native.id;
|
|
1998
|
+
} else { // fallback if device in list but not paired
|
|
1999
|
+
return device.common.name + ' ' + device.native.id;
|
|
1984
2000
|
}
|
|
1985
2001
|
},
|
|
1986
|
-
function(key, device) {
|
|
2002
|
+
function (key, device) {
|
|
1987
2003
|
if (device == '') {
|
|
1988
2004
|
return '';
|
|
1989
2005
|
} else {
|
|
1990
2006
|
return device._id;
|
|
1991
2007
|
}
|
|
1992
2008
|
},
|
|
1993
|
-
function(key, device) {
|
|
2009
|
+
function (key, device) {
|
|
1994
2010
|
if (device == '') {
|
|
1995
2011
|
return 'disabled';
|
|
1996
2012
|
} else if (device.icon) {
|
|
@@ -2005,12 +2021,12 @@ function prepareBindingDialog(bindObj){
|
|
|
2005
2021
|
bindtargets.push({'_id': key, 'groupId': key, 'groupName': groups[key]});
|
|
2006
2022
|
}
|
|
2007
2023
|
list2select('#bind_target', bindtargets, bind_target,
|
|
2008
|
-
function(key, device) {
|
|
2024
|
+
function (key, device) {
|
|
2009
2025
|
if (device == '') {
|
|
2010
2026
|
return 'Select target device';
|
|
2011
2027
|
}
|
|
2012
2028
|
if (device.hasOwnProperty('info')) {
|
|
2013
|
-
if (device.info.device._type
|
|
2029
|
+
if (device.info.device._type === 'Coordinator') {
|
|
2014
2030
|
return null;
|
|
2015
2031
|
}
|
|
2016
2032
|
// check for input clusters
|
|
@@ -2036,14 +2052,14 @@ function prepareBindingDialog(bindObj){
|
|
|
2036
2052
|
}
|
|
2037
2053
|
}
|
|
2038
2054
|
},
|
|
2039
|
-
function(key, device) {
|
|
2055
|
+
function (key, device) {
|
|
2040
2056
|
if (device == '') {
|
|
2041
2057
|
return '';
|
|
2042
2058
|
} else {
|
|
2043
2059
|
return device._id;
|
|
2044
2060
|
}
|
|
2045
2061
|
},
|
|
2046
|
-
function(key, device) {
|
|
2062
|
+
function (key, device) {
|
|
2047
2063
|
if (device == '') {
|
|
2048
2064
|
return 'disabled';
|
|
2049
2065
|
} else if (device.icon) {
|
|
@@ -2062,13 +2078,17 @@ function prepareBindingDialog(bindObj){
|
|
|
2062
2078
|
const epList = device ? device.info.endpoints : [];
|
|
2063
2079
|
const sClusterList = epList.map((ep) => {
|
|
2064
2080
|
const clusters = ep.outputClusters.map((cl) => {
|
|
2065
|
-
return allowClusters.includes(cl) ? {ID: ep.ID+'_'+cl, name: allowClustersName[cl]} : null;
|
|
2066
|
-
}).filter((i) => {
|
|
2067
|
-
|
|
2068
|
-
|
|
2081
|
+
return allowClusters.includes(cl) ? {ID: ep.ID + '_' + cl, name: allowClustersName[cl]} : null;
|
|
2082
|
+
}).filter((i) => {
|
|
2083
|
+
return i != null;
|
|
2084
|
+
});
|
|
2085
|
+
return clusters.length == 0 ? null : [{ID: ep.ID, name: 'all'}, clusters];
|
|
2086
|
+
}).flat(2).filter((i) => {
|
|
2087
|
+
return i != null;
|
|
2088
|
+
});
|
|
2069
2089
|
list2select('#bind_source_ep', sClusterList, (selected) ? [selected] : [],
|
|
2070
2090
|
(key, ep) => {
|
|
2071
|
-
return ep.ID+' '+ep.name;
|
|
2091
|
+
return ep.ID + ' ' + ep.name;
|
|
2072
2092
|
},
|
|
2073
2093
|
(key, ep) => {
|
|
2074
2094
|
return ep.ID;
|
|
@@ -2084,13 +2104,20 @@ function prepareBindingDialog(bindObj){
|
|
|
2084
2104
|
const epList = device ? device.info.endpoints : [];
|
|
2085
2105
|
const tClusterList = epList.map((ep) => {
|
|
2086
2106
|
const clusters = ep.inputClusters.map((cl) => {
|
|
2087
|
-
return (allowClusters.includes(cl) && (!sourceCl || sourceCl == cl)) ? {
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2107
|
+
return (allowClusters.includes(cl) && (!sourceCl || sourceCl == cl)) ? {
|
|
2108
|
+
ID: ep.ID + '_' + cl,
|
|
2109
|
+
name: allowClustersName[cl]
|
|
2110
|
+
} : null;
|
|
2111
|
+
}).filter((i) => {
|
|
2112
|
+
return i != null;
|
|
2113
|
+
});
|
|
2114
|
+
return !clusters.length ? null : [{ID: ep.ID, name: 'all'}, clusters];
|
|
2115
|
+
}).flat(2).filter(i => {
|
|
2116
|
+
return i != null;
|
|
2117
|
+
});
|
|
2091
2118
|
list2select('#bind_target_ep', tClusterList, (selected) ? [selected] : [],
|
|
2092
2119
|
(key, ep) => {
|
|
2093
|
-
return ep.ID+' '+ep.name;
|
|
2120
|
+
return ep.ID + ' ' + ep.name;
|
|
2094
2121
|
},
|
|
2095
2122
|
(key, ep) => {
|
|
2096
2123
|
return ep.ID;
|
|
@@ -2098,7 +2125,7 @@ function prepareBindingDialog(bindObj){
|
|
|
2098
2125
|
);
|
|
2099
2126
|
};
|
|
2100
2127
|
|
|
2101
|
-
$('#bind_source').change(function() {
|
|
2128
|
+
$('#bind_source').change(function () {
|
|
2102
2129
|
if (this.selectedIndex <= 0) {
|
|
2103
2130
|
return;
|
|
2104
2131
|
}
|
|
@@ -2110,7 +2137,7 @@ function prepareBindingDialog(bindObj){
|
|
|
2110
2137
|
configureSourceEp();
|
|
2111
2138
|
}
|
|
2112
2139
|
|
|
2113
|
-
$('#bind_target').change(function() {
|
|
2140
|
+
$('#bind_target').change(function () {
|
|
2114
2141
|
if (this.selectedIndex <= 0) {
|
|
2115
2142
|
return;
|
|
2116
2143
|
}
|
|
@@ -2123,7 +2150,7 @@ function prepareBindingDialog(bindObj){
|
|
|
2123
2150
|
configureTargetEp();
|
|
2124
2151
|
}
|
|
2125
2152
|
|
|
2126
|
-
$('#bind_source_ep').change(function() {
|
|
2153
|
+
$('#bind_source_ep').change(function () {
|
|
2127
2154
|
$('#bind_target').trigger('change');
|
|
2128
2155
|
});
|
|
2129
2156
|
|
|
@@ -2132,8 +2159,8 @@ function prepareBindingDialog(bindObj){
|
|
|
2132
2159
|
}
|
|
2133
2160
|
|
|
2134
2161
|
function addBindingDialog() {
|
|
2135
|
-
$(
|
|
2136
|
-
$(
|
|
2162
|
+
$('#bindingmodaledit a.btn[name=\'save\']').unbind('click');
|
|
2163
|
+
$('#bindingmodaledit a.btn[name=\'save\']').click(() => {
|
|
2137
2164
|
const //bind_id = $('#bindingmodaledit').find("input[id='bind_id']").val(),
|
|
2138
2165
|
bind_source = $('#bindingmodaledit').find('#bind_source option:selected').val(),
|
|
2139
2166
|
bind_source_ep = $('#bindingmodaledit').find('#bind_source_ep option:selected').val(),
|
|
@@ -2157,10 +2184,8 @@ function addBinding(bind_source, bind_source_ep, bind_target, bind_target_ep, un
|
|
|
2157
2184
|
unbind_from_coordinator
|
|
2158
2185
|
}, function (msg) {
|
|
2159
2186
|
closeWaitingDialog();
|
|
2160
|
-
if (msg) {
|
|
2161
|
-
|
|
2162
|
-
showMessage(msg.error, _('Error'));
|
|
2163
|
-
}
|
|
2187
|
+
if (msg && msg.error) {
|
|
2188
|
+
showMessage(msg.error, _('Error'));
|
|
2164
2189
|
}
|
|
2165
2190
|
getBinding();
|
|
2166
2191
|
});
|
|
@@ -2177,10 +2202,8 @@ function editBinding(bind_id, bind_source, bind_source_ep, bind_target, bind_tar
|
|
|
2177
2202
|
unbind_from_coordinator
|
|
2178
2203
|
}, function (msg) {
|
|
2179
2204
|
closeWaitingDialog();
|
|
2180
|
-
if (msg) {
|
|
2181
|
-
|
|
2182
|
-
showMessage(msg.error, _('Error'));
|
|
2183
|
-
}
|
|
2205
|
+
if (msg && msg.error) {
|
|
2206
|
+
showMessage(msg.error, _('Error'));
|
|
2184
2207
|
}
|
|
2185
2208
|
getBinding();
|
|
2186
2209
|
});
|
|
@@ -2188,8 +2211,8 @@ function editBinding(bind_id, bind_source, bind_source_ep, bind_target, bind_tar
|
|
|
2188
2211
|
}
|
|
2189
2212
|
|
|
2190
2213
|
function editBindingDialog(bindObj) {
|
|
2191
|
-
$(
|
|
2192
|
-
$(
|
|
2214
|
+
$('#bindingmodaledit a.btn[name=\'save\']').unbind('click');
|
|
2215
|
+
$('#bindingmodaledit a.btn[name=\'save\']').click(() => {
|
|
2193
2216
|
const //bind_id = $('#bindingmodaledit').find("input[id='bind_id']").val(),
|
|
2194
2217
|
bind_source = $('#bindingmodaledit').find('#bind_source option:selected').val(),
|
|
2195
2218
|
bind_source_ep = $('#bindingmodaledit').find('#bind_source_ep option:selected').val(),
|
|
@@ -2225,9 +2248,9 @@ function showBinding() {
|
|
|
2225
2248
|
<i class="right">${target_icon}</i>
|
|
2226
2249
|
<div style="min-height:72px; font-size: 0.8em" class="truncate">
|
|
2227
2250
|
<ul>
|
|
2228
|
-
<li><span class="label">source:</span><span>0x${bind_source.replace(namespace+'.', '')}</span></li>
|
|
2251
|
+
<li><span class="label">source:</span><span>0x${bind_source.replace(namespace + '.', '')}</span></li>
|
|
2229
2252
|
<li><span class="label">endpoint:</span><span>${bind_source_ep}</span></li>
|
|
2230
|
-
<li><span class="label">target:</span><span>0x${bind_target.replace(namespace+'.', '')}</span></li>
|
|
2253
|
+
<li><span class="label">target:</span><span>0x${bind_target.replace(namespace + '.', '')}</span></li>
|
|
2231
2254
|
<li><span class="label">endpoint:</span><span>${bind_target_ep}</span></li>
|
|
2232
2255
|
</ul>
|
|
2233
2256
|
</div>
|
|
@@ -2249,11 +2272,11 @@ function showBinding() {
|
|
|
2249
2272
|
element.append(card);
|
|
2250
2273
|
});
|
|
2251
2274
|
|
|
2252
|
-
$(
|
|
2275
|
+
$('#binding button[name=\'delete\']').click(function () {
|
|
2253
2276
|
const bind_id = $(this).parents('.binding')[0].id;
|
|
2254
2277
|
deleteBindingConfirmation(bind_id);
|
|
2255
2278
|
});
|
|
2256
|
-
$(
|
|
2279
|
+
$('#binding button[name=\'edit\']').click(function () {
|
|
2257
2280
|
const bind_id = $(this).parents('.binding')[0].id;
|
|
2258
2281
|
const bindObj = binding.find((b) => b.id == bind_id);
|
|
2259
2282
|
if (bindObj) {
|
|
@@ -2280,8 +2303,8 @@ function deleteBindingConfirmation(id) {
|
|
|
2280
2303
|
$('#modaldelete').find('p').text(text);
|
|
2281
2304
|
//$('#forcediv').removeClass('hide');
|
|
2282
2305
|
$('#forcediv').addClass('hide');
|
|
2283
|
-
$(
|
|
2284
|
-
$(
|
|
2306
|
+
$('#modaldelete a.btn[name=\'yes\']').unbind('click');
|
|
2307
|
+
$('#modaldelete a.btn[name=\'yes\']').click(() => {
|
|
2285
2308
|
deleteBinding(id);
|
|
2286
2309
|
});
|
|
2287
2310
|
$('#modaldelete').modal('open');
|
|
@@ -2314,14 +2337,14 @@ function genDevInfo(device) {
|
|
|
2314
2337
|
const dev = (device && device.info) ? device.info.device : undefined;
|
|
2315
2338
|
const mapped = (device && device.info) ? device.info.mapped : undefined;
|
|
2316
2339
|
if (!dev) return `<div class="truncate">No info</div>`;
|
|
2317
|
-
const genRow = function(name, value, refresh) {
|
|
2340
|
+
const genRow = function (name, value, refresh) {
|
|
2318
2341
|
if (value === undefined) {
|
|
2319
2342
|
return '';
|
|
2320
2343
|
} else {
|
|
2321
2344
|
return `<li><span class="label">${name}:</span><span>${value}</span></li>`;
|
|
2322
2345
|
}
|
|
2323
2346
|
};
|
|
2324
|
-
const genRowValues = function(name, value) {
|
|
2347
|
+
const genRowValues = function (name, value) {
|
|
2325
2348
|
if (value === undefined) {
|
|
2326
2349
|
return '';
|
|
2327
2350
|
} else {
|
|
@@ -2356,7 +2379,7 @@ function genDevInfo(device) {
|
|
|
2356
2379
|
</div>`;
|
|
2357
2380
|
}
|
|
2358
2381
|
const imgSrc = device.icon || device.common.icon;
|
|
2359
|
-
const imgInfo = (imgSrc) ? `<img src=${imgSrc} width='150px' onerror="this.onerror=null;this.src='img/unavailable.png';"><div class="divider"></div
|
|
2382
|
+
const imgInfo = (imgSrc) ? `<img src=${imgSrc} width='150px' onerror="this.onerror=null;this.src='img/unavailable.png';"><div class="divider"></div>` : '';
|
|
2360
2383
|
const info =
|
|
2361
2384
|
`<div class="col s12 m6 l6 xl6">
|
|
2362
2385
|
${imgInfo}
|
|
@@ -2388,29 +2411,28 @@ function genDevInfo(device) {
|
|
|
2388
2411
|
return info;
|
|
2389
2412
|
}
|
|
2390
2413
|
|
|
2391
|
-
function showDevInfo(id){
|
|
2414
|
+
function showDevInfo(id) {
|
|
2392
2415
|
const info = genDevInfo(getDeviceByID(id));
|
|
2393
2416
|
$('#devinfo').html(info);
|
|
2394
2417
|
$('#modaldevinfo').modal('open');
|
|
2395
2418
|
}
|
|
2396
2419
|
|
|
2397
|
-
function showGroupList(show){
|
|
2420
|
+
function showGroupList(show) {
|
|
2398
2421
|
const htmlsections = [];
|
|
2399
2422
|
for (const groupid in devGroups) {
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
htmlsections.push(`
|
|
2423
|
+
const dev = devGroups[groupid];
|
|
2424
|
+
const grpname = (dev.common && dev.common.name ? dev.common.name : 'Group ' + groupid);
|
|
2425
|
+
const selectables = [];
|
|
2426
|
+
const members = [];
|
|
2427
|
+
if (dev && dev.memberinfo) {
|
|
2428
|
+
selectables.push(`<select id="members_${groupid}" multiple>`);
|
|
2429
|
+
for (let m = 0; m < dev.memberinfo.length; m++) {
|
|
2430
|
+
members.push(`${dev.memberinfo[m].device}.${dev.memberinfo[m].epid} (${dev.memberinfo[m].ieee})`);
|
|
2431
|
+
selectables.push(`<option value="${m}">${dev.memberinfo[m].device}.${dev.memberinfo[m].epid} (...${dev.memberinfo[m].ieee.slice(-4)})</option>`);
|
|
2432
|
+
}
|
|
2433
|
+
selectables.push('</select>');
|
|
2434
|
+
}
|
|
2435
|
+
htmlsections.push(`
|
|
2414
2436
|
<div class="row">
|
|
2415
2437
|
<div class="col s4 m4 l4">
|
|
2416
2438
|
<h5>${grpname}<h5>
|
|
@@ -2423,38 +2445,38 @@ function showGroupList(show){
|
|
|
2423
2445
|
}
|
|
2424
2446
|
|
|
2425
2447
|
$('#grouplist').html(htmlsections.join(''));
|
|
2426
|
-
$('#add').click(function() {
|
|
2427
|
-
const maxind = parseInt(Object.getOwnPropertyNames(groups).reduce((a,b) => a>b ? a : b, 0));
|
|
2428
|
-
editGroupName(maxind+1, 'Group ' + maxind+1, true);
|
|
2448
|
+
$('#add').click(function () {
|
|
2449
|
+
const maxind = parseInt(Object.getOwnPropertyNames(groups).reduce((a, b) => a > b ? a : b, 0));
|
|
2450
|
+
editGroupName(maxind + 1, 'Group ' + maxind + 1, true);
|
|
2429
2451
|
showGroupList(false);
|
|
2430
2452
|
});
|
|
2431
2453
|
|
|
2432
|
-
$(
|
|
2433
|
-
$(
|
|
2454
|
+
$('#modalgrouplist a.btn[name=\'save\']').unbind('click');
|
|
2455
|
+
$('#modalgrouplist a.btn[name=\'save\']').click(() => {
|
|
2434
2456
|
});
|
|
2435
2457
|
if (show) $('#modalgrouplist').modal('open');
|
|
2436
2458
|
}
|
|
2437
2459
|
|
|
2438
2460
|
let waitingTimeout, waitingInt;
|
|
2439
2461
|
|
|
2440
|
-
function showWaitingDialog(text, timeout){
|
|
2462
|
+
function showWaitingDialog(text, timeout) {
|
|
2441
2463
|
let countDown = timeout;
|
|
2442
|
-
waitingInt = setInterval(function() {
|
|
2464
|
+
waitingInt = setInterval(function () {
|
|
2443
2465
|
countDown -= 1;
|
|
2444
|
-
const percent = 100-100*countDown/timeout;
|
|
2466
|
+
const percent = 100 - 100 * countDown / timeout;
|
|
2445
2467
|
$('#waiting_progress_line').css('width', `${percent}%`);
|
|
2446
2468
|
}, 1000);
|
|
2447
|
-
waitingTimeout = setTimeout(function() {
|
|
2469
|
+
waitingTimeout = setTimeout(function () {
|
|
2448
2470
|
$('#waiting_progress_line').css('width', `0%`);
|
|
2449
2471
|
clearTimeout(waitingInt);
|
|
2450
2472
|
clearTimeout(waitingTimeout);
|
|
2451
2473
|
$('#modalWaiting').modal('close');
|
|
2452
|
-
}, timeout*1000);
|
|
2474
|
+
}, timeout * 1000);
|
|
2453
2475
|
$('#waiting_message').text(text);
|
|
2454
2476
|
$('#modalWaiting').modal('open');
|
|
2455
2477
|
}
|
|
2456
2478
|
|
|
2457
|
-
function closeWaitingDialog(){
|
|
2479
|
+
function closeWaitingDialog() {
|
|
2458
2480
|
if (waitingInt) clearTimeout(waitingInt);
|
|
2459
2481
|
if (waitingTimeout) clearTimeout(waitingTimeout);
|
|
2460
2482
|
$('#modalWaiting').modal('close');
|
|
@@ -2471,7 +2493,7 @@ function showChannels() {
|
|
|
2471
2493
|
$('#modalchannels').modal('open');
|
|
2472
2494
|
let info = '';
|
|
2473
2495
|
for (let ch = 11; ch < 27; ch++) {
|
|
2474
|
-
const value = msg.energyvalues[ch-11];
|
|
2496
|
+
const value = msg.energyvalues[ch - 11];
|
|
2475
2497
|
info +=
|
|
2476
2498
|
`<div style="padding-top: 10px">
|
|
2477
2499
|
<span class="">№ ${ch}: ${value}%</span>
|
|
@@ -2529,7 +2551,7 @@ function prepareExcludeDialog(excludeObj) {
|
|
|
2529
2551
|
|
|
2530
2552
|
list2select('#exclude_target', onlyOneTargets, exclude_target,
|
|
2531
2553
|
|
|
2532
|
-
function(key, device) {
|
|
2554
|
+
function (key, device) {
|
|
2533
2555
|
if (device == '') {
|
|
2534
2556
|
return 'Select model';
|
|
2535
2557
|
}
|
|
@@ -2542,14 +2564,14 @@ function prepareExcludeDialog(excludeObj) {
|
|
|
2542
2564
|
return device.common.type;
|
|
2543
2565
|
}
|
|
2544
2566
|
},
|
|
2545
|
-
function(key, device) {
|
|
2567
|
+
function (key, device) {
|
|
2546
2568
|
if (device == '') {
|
|
2547
2569
|
return '';
|
|
2548
2570
|
} else {
|
|
2549
2571
|
return device._id;
|
|
2550
2572
|
}
|
|
2551
2573
|
},
|
|
2552
|
-
function(key, device) {
|
|
2574
|
+
function (key, device) {
|
|
2553
2575
|
if (device == '') {
|
|
2554
2576
|
return 'disabled';
|
|
2555
2577
|
} else if (device.icon) {
|
|
@@ -2563,8 +2585,8 @@ function prepareExcludeDialog(excludeObj) {
|
|
|
2563
2585
|
}
|
|
2564
2586
|
|
|
2565
2587
|
function addExcludeDialog() {
|
|
2566
|
-
$(
|
|
2567
|
-
$(
|
|
2588
|
+
$('#excludemodaledit a.btn[name=\'save\']').unbind('click');
|
|
2589
|
+
$('#excludemodaledit a.btn[name=\'save\']').click(() => {
|
|
2568
2590
|
const exclude_id = $('#excludemodaledit').find('#exclude_target option:selected').val();
|
|
2569
2591
|
|
|
2570
2592
|
const ids = devices.map(el => el._id);
|
|
@@ -2647,7 +2669,7 @@ function showExclude() {
|
|
|
2647
2669
|
element.append(card);
|
|
2648
2670
|
});
|
|
2649
2671
|
|
|
2650
|
-
$(
|
|
2672
|
+
$('#exclude button[name=\'delete\']').click(function () {
|
|
2651
2673
|
const exclude_id = $(this).parents('.exclude')[0].id;
|
|
2652
2674
|
deleteExcludeConfirmation(exclude_id);
|
|
2653
2675
|
deleteExclude(exclude_id);
|
|
@@ -2655,14 +2677,13 @@ function showExclude() {
|
|
|
2655
2677
|
}
|
|
2656
2678
|
|
|
2657
2679
|
|
|
2658
|
-
|
|
2659
2680
|
function deleteExcludeConfirmation(id) {
|
|
2660
2681
|
const text = translateWord('Do you really want to delete exclude?');
|
|
2661
2682
|
$('#modaldelete').find('p').text(text);
|
|
2662
2683
|
//$('#forcediv').removeClass('hide');
|
|
2663
2684
|
$('#forcediv').addClass('hide');
|
|
2664
|
-
$(
|
|
2665
|
-
$(
|
|
2685
|
+
$('#modaldelete a.btn[name=\'yes\']').unbind('click');
|
|
2686
|
+
$('#modaldelete a.btn[name=\'yes\']').click(() => {
|
|
2666
2687
|
deleteExclude(id);
|
|
2667
2688
|
});
|
|
2668
2689
|
$('#modaldelete').modal('open');
|
|
@@ -2703,7 +2724,7 @@ function doFilter(inputText) {
|
|
|
2703
2724
|
} else {
|
|
2704
2725
|
return room;
|
|
2705
2726
|
}
|
|
2706
|
-
}).filter((item)=>item != undefined).map((item)=>item.toLowerCase().trim());
|
|
2727
|
+
}).filter((item) => item != undefined).map((item) => item.toLowerCase().trim());
|
|
2707
2728
|
valid = rooms.includes(roomFilter);
|
|
2708
2729
|
} else {
|
|
2709
2730
|
valid = false;
|
|
@@ -2720,9 +2741,9 @@ function doFilter(inputText) {
|
|
|
2720
2741
|
function doSort() {
|
|
2721
2742
|
if (shuffleInstance) {
|
|
2722
2743
|
const sortOrder = $('#device-order-btn').text().toLowerCase();
|
|
2723
|
-
if (sortOrder
|
|
2744
|
+
if (sortOrder === 'default') {
|
|
2724
2745
|
shuffleInstance.sort({});
|
|
2725
|
-
} else if (sortOrder
|
|
2746
|
+
} else if (sortOrder === 'a-z') {
|
|
2726
2747
|
shuffleInstance.sort({
|
|
2727
2748
|
by: sortByTitle
|
|
2728
2749
|
});
|
|
@@ -2736,12 +2757,12 @@ function sortByTitle(element) {
|
|
|
2736
2757
|
|
|
2737
2758
|
function getDashCard(dev, groupImage) {
|
|
2738
2759
|
const title = dev.common.name,
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2760
|
+
id = dev._id,
|
|
2761
|
+
type = dev.common.type,
|
|
2762
|
+
img_src = (groupImage ? groupImage : dev.icon || dev.common.icon),
|
|
2763
|
+
isActive = !dev.common.deactivated,
|
|
2764
|
+
rooms = [],
|
|
2765
|
+
lang = systemLang || 'en';
|
|
2745
2766
|
const paired = (dev.paired) ? '' : '<i class="material-icons right">leak_remove</i>';
|
|
2746
2767
|
const rid = id.split('.').join('_');
|
|
2747
2768
|
const modelUrl = (!type) ? '' : `<a href="https://www.zigbee2mqtt.io/devices/${type}.html" target="_blank" rel="noopener noreferrer">${type}</a>`;
|
|
@@ -2750,46 +2771,46 @@ function getDashCard(dev, groupImage) {
|
|
|
2750
2771
|
battery_cls = getBatteryCls(dev.battery),
|
|
2751
2772
|
lqi_cls = getLQICls(dev.link_quality),
|
|
2752
2773
|
battery = (dev.battery && isActive) ? `<div class="col tool"><i id="${rid}_battery_icon" class="material-icons ${battery_cls}">battery_std</i><div id="${rid}_battery" class="center" style="font-size:0.7em">${dev.battery}</div></div>` : '',
|
|
2753
|
-
lq = (dev.link_quality > 0 && isActive) ? `<div class="col tool"><i id="${rid}_link_quality_icon" class="material-icons ${lqi_cls}">network_check</i><div id="${rid}_link_quality" class="center" style="font-size:0.7em">${dev.link_quality}</div></div>` : (isActive ? '<div class="col tool"><i class="material-icons icon-green">check_circle</i></div>':''),
|
|
2754
|
-
status = (dev.link_quality > 0 && isActive) ? `<div class="col tool"><i class="material-icons icon-green">check_circle</i></div>` : (groupImage || !isActive ? '': `<div class="col tool"><i class="material-icons icon-black">leak_remove</i></div>`),
|
|
2755
|
-
permitJoinBtn = (isActive && dev.info && dev.info.device._type
|
|
2774
|
+
lq = (dev.link_quality > 0 && isActive) ? `<div class="col tool"><i id="${rid}_link_quality_icon" class="material-icons ${lqi_cls}">network_check</i><div id="${rid}_link_quality" class="center" style="font-size:0.7em">${dev.link_quality}</div></div>` : (isActive ? '<div class="col tool"><i class="material-icons icon-green">check_circle</i></div>' : ''),
|
|
2775
|
+
status = (dev.link_quality > 0 && isActive) ? `<div class="col tool"><i class="material-icons icon-green">check_circle</i></div>` : (groupImage || !isActive ? '' : `<div class="col tool"><i class="material-icons icon-black">leak_remove</i></div>`),
|
|
2776
|
+
permitJoinBtn = (isActive && dev.info && dev.info.device._type === 'Router') ? '<button name="join" class="btn-floating btn-small waves-effect waves-light right hoverable green"><i class="material-icons tiny">leak_add</i></button>' : '',
|
|
2756
2777
|
infoBtn = (nwk) ? `<button name="info" class="left btn-flat btn-small"><i class="material-icons icon-blue">info</i></button>` : '',
|
|
2757
2778
|
idleTime = (dev.link_quality_lc > 0 && isActive) ? `<div class="col tool"><i id="${rid}_link_quality_lc_icon" class="material-icons idletime">access_time</i><div id="${rid}_link_quality_lc" class="center" style="font-size:0.7em">${getIdleTime(dev.link_quality_lc)}</div></div>` : '';
|
|
2758
|
-
const info = (dev.statesDef) ? dev.statesDef.map((stateDef)=>{
|
|
2779
|
+
const info = (dev.statesDef) ? dev.statesDef.map((stateDef) => {
|
|
2759
2780
|
const id = stateDef.id;
|
|
2760
2781
|
const sid = id.split('.').join('_');
|
|
2761
2782
|
let val = stateDef.val || '';
|
|
2762
|
-
if (stateDef.role
|
|
2763
|
-
val = `<span class="switch"><label><input type="checkbox" ${(val) ?
|
|
2764
|
-
} else if (stateDef.role
|
|
2765
|
-
val = `<span class="range-field dash"><input type="range" min="0" max="100" ${(val != undefined) ? `value="${val}"` :
|
|
2766
|
-
} else if (stateDef.role
|
|
2767
|
-
val = `<span class="range-field dash"><input type="range" min="150" max="500" ${(val != undefined) ? `value="${val}"` :
|
|
2768
|
-
} else if (stateDef.type
|
|
2783
|
+
if (stateDef.role === 'switch' && stateDef.write) {
|
|
2784
|
+
val = `<span class="switch"><label><input type="checkbox" ${(val) ? 'checked' : ''}><span class="lever"></span></label></span>`;
|
|
2785
|
+
} else if (stateDef.role === 'level.dimmer' && stateDef.write) {
|
|
2786
|
+
val = `<span class="range-field dash"><input type="range" min="0" max="100" ${(val != undefined) ? `value="${val}"` : ''} /></span>`;
|
|
2787
|
+
} else if (stateDef.role === 'level.color.temperature' && stateDef.write) {
|
|
2788
|
+
val = `<span class="range-field dash"><input type="range" min="150" max="500" ${(val != undefined) ? `value="${val}"` : ''} /></span>`;
|
|
2789
|
+
} else if (stateDef.type === 'boolean') {
|
|
2769
2790
|
const disabled = (stateDef.write) ? '' : 'disabled="disabled"';
|
|
2770
|
-
val = `<label class="dash"><input type="checkbox" ${(val == true) ?
|
|
2791
|
+
val = `<label class="dash"><input type="checkbox" ${(val == true) ? 'checked=\'checked\'' : ''} ${disabled}/><span></span></label>`;
|
|
2771
2792
|
} else if (stateDef.states && stateDef.write) {
|
|
2772
2793
|
let options;
|
|
2773
|
-
if(typeof stateDef.states ==
|
|
2794
|
+
if (typeof stateDef.states == 'string') {
|
|
2774
2795
|
const sts = stateDef.states.split(';');
|
|
2775
2796
|
options = sts.map((item) => {
|
|
2776
2797
|
const v = item.split(':');
|
|
2777
|
-
return `<option value="${v[0]}" ${(val == v[0]) ?
|
|
2798
|
+
return `<option value="${v[0]}" ${(val == v[0]) ? 'selected' : ''}>${v[1]}</option>`;
|
|
2778
2799
|
});
|
|
2779
2800
|
} else {
|
|
2780
2801
|
options = [];
|
|
2781
|
-
for(const [key, value] of Object.entries(stateDef.states)) {
|
|
2782
|
-
options.push(`<option value="${key}" ${(val == key) ?
|
|
2802
|
+
for (const [key, value] of Object.entries(stateDef.states)) {
|
|
2803
|
+
options.push(`<option value="${key}" ${(val == key) ? 'selected' : ''}>${value}</option>`);
|
|
2783
2804
|
}
|
|
2784
2805
|
}
|
|
2785
|
-
val = `<select class="browser-default enum" style="height: 16px; padding:
|
|
2806
|
+
val = `<select class="browser-default enum" style="height: 16px; padding: 0; width: auto; display: inline-block">${options.join('')}</select>`;
|
|
2786
2807
|
} else {
|
|
2787
2808
|
val = `<span class="dash value">${val} ${(stateDef.unit) ? stateDef.unit : ''}</span>`;
|
|
2788
2809
|
}
|
|
2789
2810
|
return `<li><span class="label dash truncate">${stateDef.name}</span><span id=${sid} oid=${id} class="state">${val}</span></li>`;
|
|
2790
2811
|
}).join('') : '';
|
|
2791
2812
|
const dashCard = `
|
|
2792
|
-
<div class="card-content zcard ${isActive?'':'bg_red'}">
|
|
2813
|
+
<div class="card-content zcard ${isActive ? '' : 'bg_red'}">
|
|
2793
2814
|
<div class="flip" style="cursor: pointer">
|
|
2794
2815
|
<span class="top right small" style="border-radius: 50%">
|
|
2795
2816
|
${idleTime}
|
|
@@ -2802,7 +2823,7 @@ function getDashCard(dev, groupImage) {
|
|
|
2802
2823
|
<i class="left">${image}</i>
|
|
2803
2824
|
<div style="min-height:88px; font-size: 0.8em; height: 130px; overflow-y: auto" class="truncate">
|
|
2804
2825
|
<ul>
|
|
2805
|
-
${(isActive?info:'Device deactivated')}
|
|
2826
|
+
${(isActive ? info : 'Device deactivated')}
|
|
2806
2827
|
</ul>
|
|
2807
2828
|
</div>
|
|
2808
2829
|
<div class="footer right-align"></div>
|
|
@@ -2815,19 +2836,19 @@ function setDashStates(id, state) {
|
|
|
2815
2836
|
const devId = getDevId(id);
|
|
2816
2837
|
const dev = getDeviceByID(devId);
|
|
2817
2838
|
if (dev) {
|
|
2818
|
-
const stateDef = dev.statesDef.find((stateDef)=> stateDef.id == id);
|
|
2839
|
+
const stateDef = dev.statesDef.find((stateDef) => stateDef.id == id);
|
|
2819
2840
|
if (stateDef) {
|
|
2820
2841
|
const sid = id.split('.').join('_');
|
|
2821
|
-
if (stateDef.role
|
|
2822
|
-
$(`#${sid}`).find(
|
|
2823
|
-
} else if (stateDef.role
|
|
2824
|
-
$(`#${sid}`).find(
|
|
2825
|
-
} else if (stateDef.role
|
|
2826
|
-
$(`#${sid}`).find(
|
|
2842
|
+
if (stateDef.role === 'switch' && stateDef.write) {
|
|
2843
|
+
$(`#${sid}`).find('input[type=\'checkbox\']').prop('checked', state.val);
|
|
2844
|
+
} else if (stateDef.role === 'level.dimmer' && stateDef.write) {
|
|
2845
|
+
$(`#${sid}`).find('input[type=\'range\']').prop('value', state.val);
|
|
2846
|
+
} else if (stateDef.role === 'level.color.temperature' && stateDef.write) {
|
|
2847
|
+
$(`#${sid}`).find('input[type=\'range\']').prop('value', state.val);
|
|
2827
2848
|
} else if (stateDef.states && stateDef.write) {
|
|
2828
2849
|
$(`#${sid}`).find(`select option[value=${state.val}]`).prop('selected', true);
|
|
2829
|
-
} else if (stateDef.type
|
|
2830
|
-
$(`#${sid}`).find(
|
|
2850
|
+
} else if (stateDef.type === 'boolean') {
|
|
2851
|
+
$(`#${sid}`).find('input[type=\'checkbox\']').prop('checked', state.val);
|
|
2831
2852
|
} else {
|
|
2832
2853
|
$(`#${sid}`).find('.value').text(`${state.val} ${(stateDef.unit) ? stateDef.unit : ''}`);
|
|
2833
2854
|
}
|
|
@@ -2836,23 +2857,23 @@ function setDashStates(id, state) {
|
|
|
2836
2857
|
}
|
|
2837
2858
|
|
|
2838
2859
|
function hookControls() {
|
|
2839
|
-
$(
|
|
2860
|
+
$('input[type=\'checkbox\']').change(function (event) {
|
|
2840
2861
|
const val = $(this).is(':checked');
|
|
2841
|
-
const id = $(this).parents(
|
|
2862
|
+
const id = $(this).parents('.state').attr('oid');
|
|
2842
2863
|
sendTo(namespace, 'setState', {id: id, val: val}, function (data) {
|
|
2843
2864
|
//console.log(data);
|
|
2844
2865
|
});
|
|
2845
2866
|
});
|
|
2846
|
-
$(
|
|
2867
|
+
$('input[type=\'range\']').change(function (event) {
|
|
2847
2868
|
const val = $(this).val();
|
|
2848
|
-
const id = $(this).parents(
|
|
2869
|
+
const id = $(this).parents('.state').attr('oid');
|
|
2849
2870
|
sendTo(namespace, 'setState', {id: id, val: val}, function (data) {
|
|
2850
2871
|
//console.log(data);
|
|
2851
2872
|
});
|
|
2852
2873
|
});
|
|
2853
|
-
$(
|
|
2874
|
+
$('.state select').on('change', function () {
|
|
2854
2875
|
const val = $(this).val();
|
|
2855
|
-
const id = $(this).parents(
|
|
2876
|
+
const id = $(this).parents('.state').attr('oid');
|
|
2856
2877
|
sendTo(namespace, 'setState', {id: id, val: val}, function (data) {
|
|
2857
2878
|
//console.log(data);
|
|
2858
2879
|
});
|
|
@@ -2860,12 +2881,12 @@ function hookControls() {
|
|
|
2860
2881
|
}
|
|
2861
2882
|
|
|
2862
2883
|
function getIdleTime(value) {
|
|
2863
|
-
return (value) ? moment(new Date(value)).fromNow(true) :
|
|
2884
|
+
return (value) ? moment(new Date(value)).fromNow(true) : '';
|
|
2864
2885
|
}
|
|
2865
2886
|
|
|
2866
2887
|
function updateCardTimer() {
|
|
2867
2888
|
if (devices) {
|
|
2868
|
-
devices.forEach((dev)=>{
|
|
2889
|
+
devices.forEach((dev) => {
|
|
2869
2890
|
const id = dev._id;
|
|
2870
2891
|
if (id) {
|
|
2871
2892
|
const rid = id.split('.').join('_');
|
|
@@ -2882,9 +2903,7 @@ function updateDevice(id) {
|
|
|
2882
2903
|
showMessage(devs.error, _('Error'));
|
|
2883
2904
|
} else {
|
|
2884
2905
|
removeDevice(id);
|
|
2885
|
-
devs.forEach((dev)
|
|
2886
|
-
devices.push(dev);
|
|
2887
|
-
})
|
|
2906
|
+
devs.forEach(dev => devices.push(dev));
|
|
2888
2907
|
showDevices();
|
|
2889
2908
|
}
|
|
2890
2909
|
}
|
|
@@ -2902,21 +2921,21 @@ function removeDevice(id) {
|
|
|
2902
2921
|
}
|
|
2903
2922
|
|
|
2904
2923
|
function swapActive(id) {
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2924
|
+
const dev = getDeviceByID(id);
|
|
2925
|
+
if (dev && dev.common) {
|
|
2926
|
+
dev.common.deactivated = !(dev.common.deactivated);
|
|
2927
|
+
sendTo(namespace, 'setDeviceActivated', {id: id, deactivated: dev.common.deactivated}, function () {
|
|
2928
|
+
showDevices();
|
|
2929
|
+
});
|
|
2930
|
+
}
|
|
2912
2931
|
}
|
|
2913
2932
|
|
|
2914
2933
|
function reconfigureDlg(id) {
|
|
2915
2934
|
const text = translateWord(`Do you really want to reconfigure device?`);
|
|
2916
2935
|
$('#modalreconfigure').find('p').text(text);
|
|
2917
|
-
$(
|
|
2918
|
-
$(
|
|
2919
|
-
reconfigureDevice(id
|
|
2936
|
+
$('#modalreconfigure a.btn[name=\'yes\']').unbind('click');
|
|
2937
|
+
$('#modalreconfigure a.btn[name=\'yes\']').click(() => {
|
|
2938
|
+
reconfigureDevice(id/*, force*/);
|
|
2920
2939
|
});
|
|
2921
2940
|
$('#modalreconfigure').modal('open');
|
|
2922
2941
|
Materialize.updateTextFields();
|