iobroker.zigbee 1.6.6 → 1.6.15
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 +73 -14
- package/admin/admin.js +261 -39
- package/admin/img/14153905L.png +0 -0
- package/admin/img/81855.png +0 -0
- package/admin/img/HG06338.png +0 -0
- package/admin/img/R7060.png +0 -0
- package/admin/img/TI0001-cover.png +0 -0
- package/admin/img/WHD02.png +0 -0
- package/admin/img/ikea_E1812.png +0 -0
- package/admin/index_m.html +165 -19
- package/admin/tab_m.html +161 -211
- package/admin/words.js +29 -28
- package/docs/tutorial/zigbee.png +0 -0
- package/io-package.json +36 -2
- package/lib/commands.js +75 -9
- package/lib/developer.js +6 -2
- package/lib/devices.js +41 -2
- package/lib/exposes.js +16 -10
- package/lib/groups.js +54 -28
- package/lib/ota.js +26 -0
- package/lib/rgb.js +30 -0
- package/lib/states.js +40 -14
- package/lib/statescontroller.js +217 -92
- package/lib/zbBaseExtension.js +4 -3
- package/lib/zbDelayedAction.js +1 -0
- package/lib/zbDeviceAvailability.js +14 -2
- package/lib/zbDeviceConfigure.js +11 -7
- package/lib/zbDeviceEvent.js +6 -0
- package/lib/zigbeecontroller.js +119 -17
- package/main.js +8 -4
- package/package.json +11 -8
- package/.devcontainer/devcontainer.json +0 -36
- package/.devcontainer/docker-compose.yml +0 -51
- package/.devcontainer/iobroker/Dockerfile +0 -2
- package/.devcontainer/nginx/nginx.conf +0 -33
- package/.devcontainer/parcel/Dockerfile +0 -9
- package/.devcontainer/parcel/run.sh +0 -7
package/admin/admin.js
CHANGED
|
@@ -129,6 +129,7 @@ function getGroupCard(dev) {
|
|
|
129
129
|
title = dev.common.name,
|
|
130
130
|
lq = '<div class="col tool"><i class="material-icons icon-green">check_circle</i></div>',
|
|
131
131
|
rooms = [],
|
|
132
|
+
numid = parseInt(id.replace(namespace+'.group_', '')),
|
|
132
133
|
lang = systemLang || 'en';
|
|
133
134
|
for (const r in dev.rooms) {
|
|
134
135
|
if (dev.rooms[r].hasOwnProperty(lang)) {
|
|
@@ -137,16 +138,17 @@ function getGroupCard(dev) {
|
|
|
137
138
|
rooms.push(dev.rooms[r]);
|
|
138
139
|
}
|
|
139
140
|
}
|
|
141
|
+
devGroups[numid] = dev;
|
|
140
142
|
const room = rooms.join(',') || ' ';
|
|
141
143
|
let memberCount = 0;
|
|
142
144
|
let info = `<div style="min-height:88px; font-size: 0.8em; height: 98px; overflow-y: auto" class="truncate">
|
|
143
145
|
<ul>`;
|
|
144
|
-
info = info.concat(`<li><span class="labelinfo">Group ${
|
|
146
|
+
info = info.concat(`<li><span class="labelinfo">Group ${numid}</span></li>`);
|
|
145
147
|
if (dev.memberinfo === undefined) {
|
|
146
148
|
info = info.concat(`<li><span class="labelinfo">No devices in group</span></li>`);
|
|
147
149
|
} else {
|
|
148
150
|
for (let m=0;m < dev.memberinfo.length; m++) {
|
|
149
|
-
info = info.concat(`<li><span
|
|
151
|
+
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>`);
|
|
150
152
|
}
|
|
151
153
|
memberCount = (dev.memberinfo.length<8?dev.memberinfo.length:7);
|
|
152
154
|
};
|
|
@@ -199,6 +201,7 @@ function getCard(dev) {
|
|
|
199
201
|
type_url = (dev.common.type ? sanitizeModelParameter(dev.common.type) : 'unknown'),
|
|
200
202
|
img_src = dev.icon || dev.common.icon,
|
|
201
203
|
rooms = [],
|
|
204
|
+
isActive = (dev.common.deactivated ? false : true),
|
|
202
205
|
lang = systemLang || 'en';
|
|
203
206
|
for (const r in dev.rooms) {
|
|
204
207
|
if (dev.rooms[r].hasOwnProperty(lang)) {
|
|
@@ -213,11 +216,11 @@ function getCard(dev) {
|
|
|
213
216
|
const modelUrl = (!type) ? '' : `<a href="https://www.zigbee2mqtt.io/devices/${type_url}.html" target="_blank" rel="noopener noreferrer">${type}</a>`;
|
|
214
217
|
const image = `<img src="${img_src}" width="80px" onerror="this.onerror=null;this.src='img/unavailable.png';">`,
|
|
215
218
|
nwk = (dev.info && dev.info.device) ? dev.info.device._networkAddress : undefined,
|
|
216
|
-
battery_cls = getBatteryCls(dev.battery),
|
|
219
|
+
battery_cls = (isActive ? getBatteryCls(dev.battery):''),
|
|
217
220
|
lqi_cls = getLQICls(dev.link_quality),
|
|
218
|
-
battery = (dev.battery) ? `<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>` : '',
|
|
219
|
-
lq = (dev.link_quality
|
|
220
|
-
status = (dev.link_quality
|
|
221
|
+
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
|
+
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>`:''),
|
|
221
224
|
info = `<div style="min-height:88px; font-size: 0.8em" class="truncate">
|
|
222
225
|
<ul>
|
|
223
226
|
<li><span class="labelinfo">ieee:</span><span>0x${id.replace(namespace+'.', '')}</span></li>
|
|
@@ -227,10 +230,11 @@ function getCard(dev) {
|
|
|
227
230
|
</ul>
|
|
228
231
|
</div>`,
|
|
229
232
|
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>`,
|
|
230
234
|
infoBtn = (nwk) ? `<button name="info" class="left btn-flat btn-small"><i class="material-icons icon-blue">info</i></button>` : '';
|
|
231
235
|
const dashCard = getDashCard(dev);
|
|
232
236
|
const card = `<div id="${id}" class="device">
|
|
233
|
-
<div class="card hoverable flipable">
|
|
237
|
+
<div class="card hoverable flipable ${isActive?'':'bg_red'}">
|
|
234
238
|
<div class="front face">${dashCard}</div>
|
|
235
239
|
<div class="back face">
|
|
236
240
|
<div class="card-content zcard">
|
|
@@ -258,6 +262,10 @@ function getCard(dev) {
|
|
|
258
262
|
<button name="edit" class="right btn-flat btn-small">
|
|
259
263
|
<i class="material-icons icon-green">edit</i>
|
|
260
264
|
</button>
|
|
265
|
+
<button name="reconfigure" class="right btn-flat btn-small tooltipped" title="Reconfigure">
|
|
266
|
+
<i class="material-icons icon-red">sync</i>
|
|
267
|
+
</button>
|
|
268
|
+
${deactBtn}
|
|
261
269
|
${permitJoinBtn}
|
|
262
270
|
</div>
|
|
263
271
|
</div>
|
|
@@ -348,25 +356,96 @@ function cleanConfirmation() {
|
|
|
348
356
|
Materialize.updateTextFields();
|
|
349
357
|
}
|
|
350
358
|
|
|
359
|
+
function EndPointIDfromEndPoint(ep)
|
|
360
|
+
{
|
|
361
|
+
if (ep && ep.deviceIeeeAddress && ep.ID)
|
|
362
|
+
return `${ep.deviceIeeeAddress}:${ep.ID}`;
|
|
363
|
+
return 'unidentified';
|
|
364
|
+
}
|
|
365
|
+
|
|
351
366
|
function editName(id, name) {
|
|
367
|
+
console.log('editName called with '+name);
|
|
352
368
|
const dev = devices.find((d) => d._id == id);
|
|
353
369
|
$('#modaledit').find("input[id='d_name']").val(name);
|
|
354
|
-
if (dev.info && dev.info.device._type == 'Router') {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
370
|
+
// if (dev.info && dev.info.device._type == 'Router') {
|
|
371
|
+
const groupables = [];
|
|
372
|
+
if (dev && dev.info && dev.info.endpoints) {
|
|
373
|
+
for (const ep of dev.info.endpoints) {
|
|
374
|
+
if (ep.inputClusters.includes(4)) {
|
|
375
|
+
groupables.push({ epid:EndPointIDfromEndPoint(ep), ep:ep, memberOf:[]});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
const numEP = groupables.length;
|
|
380
|
+
// console.log('groupables: '+JSON.stringify(groupables));
|
|
381
|
+
$('#modaledit').find('.row.epid0').addClass('hide');
|
|
382
|
+
$('#modaledit').find('.row.epid1').addClass('hide');
|
|
383
|
+
$('#modaledit').find('.row.epid2').addClass('hide');
|
|
384
|
+
$('#modaledit').find('.row.epid3').addClass('hide');
|
|
385
|
+
if (numEP > 0) {
|
|
386
|
+
// go through all the groups. Find the ones to list for each groupable
|
|
387
|
+
if (numEP == 1) {
|
|
388
|
+
$('#modaledit').find('.endpointid').addClass('hide');
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
$('#modaledit').find('.endpointid').removeClass('hide');
|
|
392
|
+
}
|
|
393
|
+
for (const d of devices) {
|
|
394
|
+
if (d && d.common && d.common.type == 'group') {
|
|
395
|
+
if (d.hasOwnProperty("memberinfo")) {
|
|
396
|
+
for (const member of d.memberinfo) {
|
|
397
|
+
const epid = EndPointIDfromEndPoint(member.ep)
|
|
398
|
+
for (var i=0;i<groupables.length;i++) {
|
|
399
|
+
if (groupables[i].epid == epid) {
|
|
400
|
+
groupables[i].memberOf.push(d.native.id.replace('group_', ''));
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
console.log("groupables: " + JSON.stringify(groupables));
|
|
408
|
+
for (var i = 0;i<groupables.length;i++)
|
|
409
|
+
{
|
|
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
|
+
}
|
|
416
|
+
}
|
|
417
|
+
// } else {
|
|
418
|
+
// $('#modaledit').find('.input-field.endpoints').addClass('hide');
|
|
419
|
+
// $('#modaledit').find('.input-field.groups').addClass('hide');
|
|
420
|
+
// }
|
|
360
421
|
$("#modaledit a.btn[name='save']").unbind('click');
|
|
361
422
|
$("#modaledit a.btn[name='save']").click(() => {
|
|
362
|
-
const newName = $('#modaledit').find("input[id='d_name']").val()
|
|
363
|
-
|
|
364
|
-
|
|
423
|
+
const newName = $('#modaledit').find("input[id='d_name']").val();
|
|
424
|
+
const groupsbyid = {};
|
|
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
|
+
}
|
|
432
|
+
console.log('grpid ' + JSON.stringify(groupsbyid));
|
|
433
|
+
updateDev(id, newName, groupsbyid);
|
|
365
434
|
});
|
|
366
435
|
$('#modaledit').modal('open');
|
|
367
436
|
Materialize.updateTextFields();
|
|
368
437
|
}
|
|
369
438
|
|
|
439
|
+
function GenerateGroupChange(oldmembers, newmembers)
|
|
440
|
+
{
|
|
441
|
+
let grpchng = [];
|
|
442
|
+
for (const oldg of oldmembers)
|
|
443
|
+
if (!newmembers.includes(oldg)) grpchng.push('-'+oldg);
|
|
444
|
+
for (const newg of newmembers)
|
|
445
|
+
if (!oldmembers.includes(newg)) grpchng.push(newg)
|
|
446
|
+
return grpchng;
|
|
447
|
+
}
|
|
448
|
+
|
|
370
449
|
function deleteDevice(id, force) {
|
|
371
450
|
sendTo(namespace, 'deleteDevice', {id: id, force: force}, function (msg) {
|
|
372
451
|
closeWaitingDialog();
|
|
@@ -438,7 +517,6 @@ function showDevices() {
|
|
|
438
517
|
}
|
|
439
518
|
return 0;
|
|
440
519
|
});
|
|
441
|
-
devGroups = {};
|
|
442
520
|
for (let i=0;i < devices.length; i++) {
|
|
443
521
|
const d = devices[i];
|
|
444
522
|
if (!d.info) {
|
|
@@ -455,7 +533,7 @@ function showDevices() {
|
|
|
455
533
|
} else {
|
|
456
534
|
//if (d.groups && d.info && d.info.device._type == "Router") {
|
|
457
535
|
if (d.groups) {
|
|
458
|
-
devGroups[d._id] = d.groups;
|
|
536
|
+
// devGroups[d._id] = d.groups;
|
|
459
537
|
if (typeof d.groups.map == 'function') {
|
|
460
538
|
d.groupNames = d.groups.map(item=>{
|
|
461
539
|
return groups[item] || '';
|
|
@@ -529,7 +607,7 @@ function showDevices() {
|
|
|
529
607
|
const dev_block = $(this).parents('div.device'),
|
|
530
608
|
id = dev_block.attr('id').replace(namespace+'.group_', ''),
|
|
531
609
|
name = getDevName(dev_block);
|
|
532
|
-
editGroupName(id, name);
|
|
610
|
+
editGroupName(id, name, false);
|
|
533
611
|
});
|
|
534
612
|
$("button.btn-floating[name='join']").click(function() {
|
|
535
613
|
const dev_block = $(this).parents('div.device');
|
|
@@ -548,6 +626,14 @@ function showDevices() {
|
|
|
548
626
|
$("a.btn-flat[name='close']").click((e) => {
|
|
549
627
|
closeReval(e);
|
|
550
628
|
});
|
|
629
|
+
$(".card-reveal-buttons button[name='reconfigure']").click(function() {
|
|
630
|
+
const dev_block = $(this).parents('div.device');
|
|
631
|
+
reconfigureDlg(getDevId(dev_block));
|
|
632
|
+
});
|
|
633
|
+
$(".card-reveal-buttons button[name='swapactive']").click(function() {
|
|
634
|
+
const dev_block = $(this).parents('div.device');
|
|
635
|
+
swapActive(getDevId(dev_block));
|
|
636
|
+
});
|
|
551
637
|
|
|
552
638
|
showNetworkMap(devices, map);
|
|
553
639
|
translateAll();
|
|
@@ -762,13 +848,14 @@ function load(settings, onChange) {
|
|
|
762
848
|
});
|
|
763
849
|
|
|
764
850
|
$('#add_group').click(function() {
|
|
851
|
+
// showGroupList(true);
|
|
765
852
|
const maxind = parseInt(Object.getOwnPropertyNames(groups).reduce((a,b) => a>b ? a : b, 0));
|
|
766
|
-
editGroupName(maxind+1, '');
|
|
853
|
+
editGroupName(maxind+1, 'Group ' + maxind+1, true);
|
|
767
854
|
});
|
|
768
855
|
$('#add_grp_btn').click(function() {
|
|
856
|
+
// showGroupList(true);
|
|
769
857
|
const maxind = parseInt(Object.getOwnPropertyNames(groups).reduce((a,b) => a>b ? a : b, 0));
|
|
770
|
-
editGroupName(maxind+1, '');
|
|
771
|
-
getDevices();
|
|
858
|
+
editGroupName(maxind+1, 'Group ' + maxind+1, true);
|
|
772
859
|
});
|
|
773
860
|
|
|
774
861
|
$(document).ready(function() {
|
|
@@ -1706,7 +1793,7 @@ function showGroups() {
|
|
|
1706
1793
|
$("a.btn-floating[name='groupedit']").click(function() {
|
|
1707
1794
|
const index = $(this).attr('id'),
|
|
1708
1795
|
name = groups[index];
|
|
1709
|
-
editGroupName(index, name);
|
|
1796
|
+
editGroupName(index, name, false);
|
|
1710
1797
|
});
|
|
1711
1798
|
$("a.btn-floating[name='groupdelete']").click(function() {
|
|
1712
1799
|
const index = $(this).attr('id'),
|
|
@@ -1715,8 +1802,35 @@ function showGroups() {
|
|
|
1715
1802
|
});
|
|
1716
1803
|
}
|
|
1717
1804
|
|
|
1718
|
-
function editGroupName(id, name) {
|
|
1805
|
+
function editGroupName(id, name, isnew) {
|
|
1806
|
+
//const dev = devices.find((d) => d._id == id);
|
|
1807
|
+
//console.log('devices: '+ JSON.stringify(devices));
|
|
1808
|
+
const groupables = [];
|
|
1809
|
+
for (const d of devices) {
|
|
1810
|
+
if (d && d.info && d.info.endpoints) {
|
|
1811
|
+
for (const ep of d.info.endpoints) {
|
|
1812
|
+
if (ep.inputClusters.includes(4))
|
|
1813
|
+
{
|
|
1814
|
+
groupables.push(ep);
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
//console.log('device ' + JSON.stringify(d));
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1719
1821
|
//var text = 'Enter new name for "'+name+'" ('+id+')?';
|
|
1822
|
+
if (isnew) {
|
|
1823
|
+
$('#groupedit').find('.editgroup').addClass('hide');
|
|
1824
|
+
$('#groupedit').find('.addgroup').removeClass('hide');
|
|
1825
|
+
$('#groupedit').find('.input-field.members').addClass('hide');
|
|
1826
|
+
$('#groupedit').find('.input-field.groupid').removeClass('hide');
|
|
1827
|
+
}
|
|
1828
|
+
else {
|
|
1829
|
+
$('#groupedit').find('.editgroup').removeClass('hide');
|
|
1830
|
+
$('#groupedit').find('.addgroup').addClass('hide');
|
|
1831
|
+
$('#groupedit').find('.input-field.members').removeClass('hide');
|
|
1832
|
+
$('#groupedit').find('.input-field.groupid').addClass('hide');
|
|
1833
|
+
}
|
|
1720
1834
|
$('#groupedit').find("input[id='g_index']").val(id);
|
|
1721
1835
|
$('#groupedit').find("input[id='g_name']").val(name);
|
|
1722
1836
|
$("#groupedit a.btn[name='save']").unbind('click');
|
|
@@ -1725,7 +1839,7 @@ function editGroupName(id, name) {
|
|
|
1725
1839
|
newName = $('#groupedit').find("input[id='g_name']").val();
|
|
1726
1840
|
updateGroup(id, newId, newName);
|
|
1727
1841
|
// showGroups();
|
|
1728
|
-
getDevices();
|
|
1842
|
+
// getDevices();
|
|
1729
1843
|
});
|
|
1730
1844
|
$('#groupedit').modal('open');
|
|
1731
1845
|
Materialize.updateTextFields();
|
|
@@ -1739,7 +1853,7 @@ function deleteGroupConfirmation(id, name) {
|
|
|
1739
1853
|
$("#modaldelete a.btn[name='yes']").click(() => {
|
|
1740
1854
|
deleteGroup(id);
|
|
1741
1855
|
// showGroups();
|
|
1742
|
-
getDevices();
|
|
1856
|
+
// getDevices();
|
|
1743
1857
|
});
|
|
1744
1858
|
$('#modaldelete').modal('open');
|
|
1745
1859
|
}
|
|
@@ -1747,12 +1861,22 @@ function deleteGroupConfirmation(id, name) {
|
|
|
1747
1861
|
function updateGroup(id, newId, newName) {
|
|
1748
1862
|
delete groups[id];
|
|
1749
1863
|
groups[newId] = newName;
|
|
1750
|
-
sendTo(namespace, 'renameGroup', { id: newId, name: newName} )
|
|
1864
|
+
sendTo(namespace, 'renameGroup', { id: newId, name: newName}, function(msg) {
|
|
1865
|
+
if (msg && ms.error) {
|
|
1866
|
+
showMessage(msg.error, _('Error'));
|
|
1867
|
+
}
|
|
1868
|
+
getDevices();
|
|
1869
|
+
});
|
|
1751
1870
|
}
|
|
1752
1871
|
|
|
1753
1872
|
function deleteGroup(id) {
|
|
1754
1873
|
delete groups[id];
|
|
1755
|
-
sendTo(namespace, 'deleteGroup', id )
|
|
1874
|
+
sendTo(namespace, 'deleteGroup', id , function(msg) {
|
|
1875
|
+
if (msg && ms.error) {
|
|
1876
|
+
showMessage(msg.error, _('Error'));
|
|
1877
|
+
}
|
|
1878
|
+
getDevices();
|
|
1879
|
+
});
|
|
1756
1880
|
}
|
|
1757
1881
|
|
|
1758
1882
|
function updateDev(id, newName, newGroups) {
|
|
@@ -1760,6 +1884,24 @@ function updateDev(id, newName, newGroups) {
|
|
|
1760
1884
|
if (dev && dev.common.name != newName) {
|
|
1761
1885
|
renameDevice(id, newName);
|
|
1762
1886
|
}
|
|
1887
|
+
const keys = Object.keys(newGroups)
|
|
1888
|
+
if (keys && keys.length)
|
|
1889
|
+
{
|
|
1890
|
+
sendTo(namespace, 'updateGroupMembership', { id: id, groups: newGroups }, function (msg) {
|
|
1891
|
+
closeWaitingDialog();
|
|
1892
|
+
if (msg && msg.error) {
|
|
1893
|
+
showMessage(msg.error, _('Error'));
|
|
1894
|
+
}
|
|
1895
|
+
else {
|
|
1896
|
+
// save dev-groups on success
|
|
1897
|
+
dev.groups = newGroups;
|
|
1898
|
+
}
|
|
1899
|
+
showDevices();
|
|
1900
|
+
});
|
|
1901
|
+
showWaitingDialog('Updating group memberships', 10);
|
|
1902
|
+
|
|
1903
|
+
}
|
|
1904
|
+
/*
|
|
1763
1905
|
if (dev.info.device._type == 'Router') {
|
|
1764
1906
|
const oldGroups = devGroups[id] || [];
|
|
1765
1907
|
if (oldGroups.toString() != newGroups.toString()) {
|
|
@@ -1776,6 +1918,7 @@ function updateDev(id, newName, newGroups) {
|
|
|
1776
1918
|
});
|
|
1777
1919
|
}
|
|
1778
1920
|
}
|
|
1921
|
+
*/
|
|
1779
1922
|
}
|
|
1780
1923
|
|
|
1781
1924
|
function resetConfirmation() {
|
|
@@ -2170,7 +2313,7 @@ function genDevInfo(device) {
|
|
|
2170
2313
|
const dev = (device && device.info) ? device.info.device : undefined;
|
|
2171
2314
|
const mapped = (device && device.info) ? device.info.mapped : undefined;
|
|
2172
2315
|
if (!dev) return `<div class="truncate">No info</div>`;
|
|
2173
|
-
const genRow = function(name, value) {
|
|
2316
|
+
const genRow = function(name, value, refresh) {
|
|
2174
2317
|
if (value === undefined) {
|
|
2175
2318
|
return '';
|
|
2176
2319
|
} else {
|
|
@@ -2234,7 +2377,7 @@ function genDevInfo(device) {
|
|
|
2234
2377
|
${genRow('date code', dev._dateCode)}
|
|
2235
2378
|
${genRow('build', dev._softwareBuildID)}
|
|
2236
2379
|
${genRow('interviewed', dev._interviewCompleted)}
|
|
2237
|
-
${genRow('configured', (dev.meta.configured === 1))}
|
|
2380
|
+
${genRow('configured', (dev.meta.configured === 1), true)}
|
|
2238
2381
|
</ul>
|
|
2239
2382
|
</div>
|
|
2240
2383
|
</div>
|
|
@@ -2250,17 +2393,60 @@ function showDevInfo(id){
|
|
|
2250
2393
|
$('#modaldevinfo').modal('open');
|
|
2251
2394
|
}
|
|
2252
2395
|
|
|
2396
|
+
function showGroupList(show){
|
|
2397
|
+
const htmlsections = [];
|
|
2398
|
+
for (const groupid in devGroups) {
|
|
2399
|
+
const dev = devGroups[groupid];
|
|
2400
|
+
const grpname = (dev.common && dev.common.name?dev.common.name:'Group '+groupid);
|
|
2401
|
+
const selectables = [];
|
|
2402
|
+
const members = [];
|
|
2403
|
+
if (dev && dev.memberinfo)
|
|
2404
|
+
{
|
|
2405
|
+
selectables.push(`<select id="members_${groupid}" multiple>`)
|
|
2406
|
+
for (let m=0;m<dev.memberinfo.length; m++) {
|
|
2407
|
+
members.push(`${dev.memberinfo[m].device}.${dev.memberinfo[m].epid} (${dev.memberinfo[m].ieee})`)
|
|
2408
|
+
selectables.push(`<option value="${m}">${dev.memberinfo[m].device}.${dev.memberinfo[m].epid} (...${dev.memberinfo[m].ieee.slice(-4)})</option>`);
|
|
2409
|
+
}
|
|
2410
|
+
selectables.push('</select>');
|
|
2411
|
+
}
|
|
2412
|
+
htmlsections.push(`
|
|
2413
|
+
<div class="row">
|
|
2414
|
+
<div class="col s4 m4 l4">
|
|
2415
|
+
<h5>${grpname}<h5>
|
|
2416
|
+
</div>
|
|
2417
|
+
<div class=col s7 m7 l7">
|
|
2418
|
+
${members.join('<br>')}
|
|
2419
|
+
</div>
|
|
2420
|
+
</div>
|
|
2421
|
+
`);
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
$('#grouplist').html(htmlsections.join(''));
|
|
2425
|
+
$('#add').click(function() {
|
|
2426
|
+
const maxind = parseInt(Object.getOwnPropertyNames(groups).reduce((a,b) => a>b ? a : b, 0));
|
|
2427
|
+
editGroupName(maxind+1, 'Group ' + maxind+1, true);
|
|
2428
|
+
showGroupList(false);
|
|
2429
|
+
});
|
|
2430
|
+
|
|
2431
|
+
$("#modalgrouplist a.btn[name='save']").unbind('click');
|
|
2432
|
+
$("#modalgrouplist a.btn[name='save']").click(() => {
|
|
2433
|
+
});
|
|
2434
|
+
if (show) $('#modalgrouplist').modal('open');
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2437
|
+
let waitingTimeout, waitingInt;
|
|
2253
2438
|
|
|
2254
2439
|
function showWaitingDialog(text, timeout){
|
|
2255
2440
|
let countDown = timeout;
|
|
2256
|
-
|
|
2441
|
+
waitingInt = setInterval(function() {
|
|
2257
2442
|
countDown -= 1;
|
|
2258
2443
|
const percent = 100-100*countDown/timeout;
|
|
2259
2444
|
$('#waiting_progress_line').css('width', `${percent}%`);
|
|
2260
2445
|
}, 1000);
|
|
2261
|
-
setTimeout(function() {
|
|
2446
|
+
waitingTimeout = setTimeout(function() {
|
|
2262
2447
|
$('#waiting_progress_line').css('width', `0%`);
|
|
2263
2448
|
clearTimeout(waitingInt);
|
|
2449
|
+
clearTimeout(waitingTimeout);
|
|
2264
2450
|
$('#modalWaiting').modal('close');
|
|
2265
2451
|
}, timeout*1000);
|
|
2266
2452
|
$('#waiting_message').text(text);
|
|
@@ -2268,6 +2454,8 @@ function showWaitingDialog(text, timeout){
|
|
|
2268
2454
|
}
|
|
2269
2455
|
|
|
2270
2456
|
function closeWaitingDialog(){
|
|
2457
|
+
if (waitingInt) clearTimeout(waitingInt);
|
|
2458
|
+
if (waitingTimeout) clearTimeout(waitingTimeout);
|
|
2271
2459
|
$('#modalWaiting').modal('close');
|
|
2272
2460
|
}
|
|
2273
2461
|
|
|
@@ -2550,6 +2738,7 @@ function getDashCard(dev, groupImage) {
|
|
|
2550
2738
|
id = dev._id,
|
|
2551
2739
|
type = dev.common.type,
|
|
2552
2740
|
img_src = (groupImage ? groupImage: dev.icon || dev.common.icon),
|
|
2741
|
+
isActive = (dev.common.deactivated ? false : true),
|
|
2553
2742
|
rooms = [],
|
|
2554
2743
|
lang = systemLang || 'en';
|
|
2555
2744
|
const paired = (dev.paired) ? '' : '<i class="material-icons right">leak_remove</i>';
|
|
@@ -2559,12 +2748,12 @@ function getDashCard(dev, groupImage) {
|
|
|
2559
2748
|
nwk = (dev.info && dev.info.device) ? dev.info.device._networkAddress : undefined,
|
|
2560
2749
|
battery_cls = getBatteryCls(dev.battery),
|
|
2561
2750
|
lqi_cls = getLQICls(dev.link_quality),
|
|
2562
|
-
battery = (dev.battery) ? `<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>` : '',
|
|
2563
|
-
lq = (dev.link_quality
|
|
2564
|
-
status = (dev.link_quality
|
|
2565
|
-
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>' : '',
|
|
2751
|
+
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>` : '',
|
|
2752
|
+
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>':''),
|
|
2753
|
+
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>`),
|
|
2754
|
+
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>' : '',
|
|
2566
2755
|
infoBtn = (nwk) ? `<button name="info" class="left btn-flat btn-small"><i class="material-icons icon-blue">info</i></button>` : '',
|
|
2567
|
-
idleTime = (dev.link_quality_lc > 0) ? `<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>` : '';
|
|
2756
|
+
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>` : '';
|
|
2568
2757
|
const info = (dev.statesDef) ? dev.statesDef.map((stateDef)=>{
|
|
2569
2758
|
const id = stateDef.id;
|
|
2570
2759
|
const sid = id.split('.').join('_');
|
|
@@ -2591,7 +2780,7 @@ function getDashCard(dev, groupImage) {
|
|
|
2591
2780
|
return `<li><span class="label dash truncate">${stateDef.name}</span><span id=${sid} oid=${id} class="state">${val}</span></li>`;
|
|
2592
2781
|
}).join('') : '';
|
|
2593
2782
|
const dashCard = `
|
|
2594
|
-
<div class="card-content zcard">
|
|
2783
|
+
<div class="card-content zcard ${isActive?'':'bg_red'}">
|
|
2595
2784
|
<div class="flip" style="cursor: pointer">
|
|
2596
2785
|
<span class="top right small" style="border-radius: 50%">
|
|
2597
2786
|
${idleTime}
|
|
@@ -2604,7 +2793,7 @@ function getDashCard(dev, groupImage) {
|
|
|
2604
2793
|
<i class="left">${image}</i>
|
|
2605
2794
|
<div style="min-height:88px; font-size: 0.8em; height: 130px; overflow-y: auto" class="truncate">
|
|
2606
2795
|
<ul>
|
|
2607
|
-
${info}
|
|
2796
|
+
${(isActive?info:'Device deactivated')}
|
|
2608
2797
|
</ul>
|
|
2609
2798
|
</div>
|
|
2610
2799
|
<div class="footer right-align"></div>
|
|
@@ -2702,3 +2891,36 @@ function removeDevice(id) {
|
|
|
2702
2891
|
}
|
|
2703
2892
|
}
|
|
2704
2893
|
}
|
|
2894
|
+
|
|
2895
|
+
function swapActive(id) {
|
|
2896
|
+
const dev = getDeviceByID(id);
|
|
2897
|
+
if (dev && dev.common) {
|
|
2898
|
+
dev.common.deactivated = !(dev.common.deactivated)
|
|
2899
|
+
sendTo(namespace, 'setDeviceActivated', {id: id, deactivated: dev.common.deactivated}, function () {
|
|
2900
|
+
showDevices();
|
|
2901
|
+
});
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
function reconfigureDlg(id) {
|
|
2906
|
+
const text = translateWord(`Do you really want to reconfigure device?`);
|
|
2907
|
+
$('#modalreconfigure').find('p').text(text);
|
|
2908
|
+
$("#modalreconfigure a.btn[name='yes']").unbind('click');
|
|
2909
|
+
$("#modalreconfigure a.btn[name='yes']").click(() => {
|
|
2910
|
+
reconfigureDevice(id, force);
|
|
2911
|
+
});
|
|
2912
|
+
$('#modalreconfigure').modal('open');
|
|
2913
|
+
Materialize.updateTextFields();
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2916
|
+
function reconfigureDevice(id) {
|
|
2917
|
+
sendTo(namespace, 'reconfigure', {id: id}, function (msg) {
|
|
2918
|
+
closeWaitingDialog();
|
|
2919
|
+
if (msg) {
|
|
2920
|
+
if (msg.error) {
|
|
2921
|
+
showMessage(msg.error, _('Error'));
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
});
|
|
2925
|
+
showWaitingDialog('Device is being reconfigure', 30);
|
|
2926
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|