iobroker.zigbee 2.0.0 → 2.0.2
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 +40 -10
- package/admin/admin.js +312 -125
- package/admin/img/PTM 215Z.png +0 -0
- package/admin/img/group_0.png +0 -0
- package/admin/img/group_x.png +0 -0
- package/admin/img/philips_hue_lom001.png +0 -0
- package/admin/index_m.html +95 -45
- package/admin/tab_m.html +116 -48
- package/docs/de/img/Zigbee_config_de.png +0 -0
- package/docs/de/img/Zigbee_tab_de.png +0 -0
- package/docs/de/readme.md +21 -28
- package/docs/en/img/Zigbee_config_en.png +0 -0
- package/docs/en/img/Zigbee_tab_en.png +0 -0
- package/docs/tutorial/groups-1.png +0 -0
- package/docs/tutorial/groups-2.png +0 -0
- package/docs/tutorial/tab-dev-1.png +0 -0
- package/io-package.json +55 -41
- package/lib/binding.js +1 -1
- package/lib/colors.js +7 -0
- package/lib/commands.js +136 -20
- package/lib/developer.js +0 -0
- package/lib/devices.js +88 -74
- package/lib/exclude.js +30 -54
- package/lib/exposes.js +247 -290
- package/lib/groups.js +84 -29
- package/lib/localConfig.js +301 -0
- package/lib/ota.js +5 -4
- package/lib/statescontroller.js +452 -185
- package/lib/utils.js +5 -3
- package/lib/zbDeviceAvailability.js +16 -30
- package/lib/zbDeviceConfigure.js +55 -28
- package/lib/zbDeviceEvent.js +2 -13
- package/lib/zigbeecontroller.js +335 -214
- package/main.js +181 -65
- package/package.json +8 -7
package/admin/admin.js
CHANGED
|
@@ -3,13 +3,17 @@
|
|
|
3
3
|
/*
|
|
4
4
|
* you must run 'iobroker upload zigbee' if you edited this file to make changes visible
|
|
5
5
|
*/
|
|
6
|
+
|
|
7
|
+
|
|
6
8
|
const Materialize = (typeof M !== 'undefined') ? M : Materialize,
|
|
7
9
|
anime = (typeof M !== 'undefined') ? M.anime : anime,
|
|
8
10
|
namespace = 'zigbee.' + instance,
|
|
9
11
|
namespaceLen = namespace.length;
|
|
10
12
|
let devices = [],
|
|
13
|
+
debugDevices = [],
|
|
11
14
|
messages = [],
|
|
12
15
|
map = {},
|
|
16
|
+
namedColors = [],
|
|
13
17
|
mapEdges = null,
|
|
14
18
|
network,
|
|
15
19
|
networkEvents,
|
|
@@ -26,7 +30,8 @@ let devices = [],
|
|
|
26
30
|
channel: 'd2'
|
|
27
31
|
},
|
|
28
32
|
cidList,
|
|
29
|
-
shuffleInstance
|
|
33
|
+
shuffleInstance,
|
|
34
|
+
errorData = [];
|
|
30
35
|
const updateCardInterval = setInterval(updateCardTimer, 6000);
|
|
31
36
|
|
|
32
37
|
const networkOptions = {
|
|
@@ -94,7 +99,7 @@ function getLQICls(value) {
|
|
|
94
99
|
if (value < 20) return 'icon-red';
|
|
95
100
|
if (value < 50) return 'icon-orange';
|
|
96
101
|
}
|
|
97
|
-
return '';
|
|
102
|
+
return 'icon-green';
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
|
|
@@ -172,8 +177,8 @@ function getGroupCard(dev) {
|
|
|
172
177
|
;
|
|
173
178
|
info = info.concat(` </ul>
|
|
174
179
|
</div>`);
|
|
175
|
-
const image = `<img src="
|
|
176
|
-
const dashCard = getDashCard(dev,
|
|
180
|
+
const image = `<img src="${dev.common.icon}" width="64px" onerror="this.onerror=null;this.src='img/unavailable.png';">`;
|
|
181
|
+
const dashCard = getDashCard(dev, dev.common.icon, memberCount > 0);
|
|
177
182
|
const card = `<div id="${id}" class="device group">
|
|
178
183
|
<div class="card hoverable flipable">
|
|
179
184
|
<div class="front face">${dashCard}</div>
|
|
@@ -199,6 +204,9 @@ function getGroupCard(dev) {
|
|
|
199
204
|
<button name="editgrp" class="right btn-flat btn-small">
|
|
200
205
|
<i class="material-icons icon-green">edit</i>
|
|
201
206
|
</button>
|
|
207
|
+
<button name="swapimage" class="right btn-flat btn-small tooltipped" title="Edit">
|
|
208
|
+
<i class="material-icons icon-black">image</i>
|
|
209
|
+
</button>
|
|
202
210
|
</div>
|
|
203
211
|
</div>
|
|
204
212
|
</div>
|
|
@@ -213,14 +221,18 @@ function sanitizeModelParameter(parameter) {
|
|
|
213
221
|
}
|
|
214
222
|
|
|
215
223
|
function getCard(dev) {
|
|
224
|
+
//console.warn(JSON.stringify(dev));
|
|
225
|
+
if (!dev._id) return '';
|
|
216
226
|
const title = dev.common.name,
|
|
217
|
-
id = dev._id,
|
|
227
|
+
id = (dev._id ? dev._id : ''),
|
|
218
228
|
type = (dev.common.type ? dev.common.type : 'unknown'),
|
|
219
229
|
type_url = (dev.common.type ? sanitizeModelParameter(dev.common.type) : 'unknown'),
|
|
220
|
-
img_src = dev.icon || dev.
|
|
230
|
+
img_src = dev.common.icon || dev.icon,
|
|
221
231
|
rooms = [],
|
|
222
232
|
isActive = (dev.common.deactivated ? false : true),
|
|
223
|
-
lang = systemLang || 'en'
|
|
233
|
+
lang = systemLang || 'en',
|
|
234
|
+
ieee = id.replace(namespace + '.', ''),
|
|
235
|
+
isDebug = checkDebugDevice(ieee);
|
|
224
236
|
for (const r in dev.rooms) {
|
|
225
237
|
if (dev.rooms[r].hasOwnProperty(lang)) {
|
|
226
238
|
rooms.push(dev.rooms[r][lang]);
|
|
@@ -228,6 +240,7 @@ function getCard(dev) {
|
|
|
228
240
|
rooms.push(dev.rooms[r]);
|
|
229
241
|
}
|
|
230
242
|
}
|
|
243
|
+
console.warn('debug for ' + ieee + ' is ' + isDebug);
|
|
231
244
|
const room = rooms.join(',') || ' ';
|
|
232
245
|
const paired = (dev.paired) ? '' : '<i class="material-icons right">leak_remove</i>';
|
|
233
246
|
const rid = id.split('.').join('_');
|
|
@@ -237,18 +250,20 @@ function getCard(dev) {
|
|
|
237
250
|
battery_cls = (isActive ? getBatteryCls(dev.battery) : ''),
|
|
238
251
|
lqi_cls = getLQICls(dev.link_quality),
|
|
239
252
|
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>` : '',
|
|
240
|
-
lq = (dev.link_quality > 0
|
|
241
|
-
|
|
253
|
+
lq = (dev.link_quality > 0)
|
|
254
|
+
? `<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>`
|
|
255
|
+
: `<div class="col tool"><i class="material-icons icon-black">leak_remove</i></div>`,
|
|
256
|
+
status = (isActive ? lq : `<div class="col tool"><i class="material-icons icon-red">cancel</i></div>`),
|
|
242
257
|
info = `<div style="min-height:88px; font-size: 0.8em" class="truncate">
|
|
243
258
|
<ul>
|
|
244
|
-
<li><span class="labelinfo">ieee:</span><span>0x${
|
|
259
|
+
<li><span class="labelinfo">ieee:</span><span>0x${ieee}</span></li>
|
|
245
260
|
<li><span class="labelinfo">nwk:</span><span>${(nwk) ? nwk.toString() + ' (0x' + nwk.toString(16) + ')' : ''}</span></li>
|
|
246
261
|
<li><span class="labelinfo">model:</span><span>${modelUrl}</span></li>
|
|
247
262
|
<li><span class="labelinfo">groups:</span><span>${dev.groupNames || ''}</span></li>
|
|
248
263
|
</ul>
|
|
249
264
|
</div>`,
|
|
250
|
-
|
|
251
|
-
|
|
265
|
+
deactBtn = `<button name="swapactive" class="right btn-flat btn-small tooltipped" title="${(isActive ? 'Deactivate' : 'Activate')}"><i class="material-icons ${(isActive ? 'icon-green' : 'icon-red')}">power_settings_new</i></button>`,
|
|
266
|
+
debugBtn = `<button name="swapdebug" class="right btn-flat btn-small tooltipped" title="${(isDebug > -1 ? (isDebug > 0) ?'Automatic by '+debugDevices[isDebug-1]: 'Disable Debug' : 'Enable Debug')}"><i class="material-icons icon-${(isDebug > -1 ? (isDebug > 0 ? 'orange' : 'green') : 'gray')}">bug_report</i></button>`,
|
|
252
267
|
infoBtn = (nwk) ? `<button name="info" class="left btn-flat btn-small"><i class="material-icons icon-blue">info</i></button>` : '';
|
|
253
268
|
const dashCard = getDashCard(dev);
|
|
254
269
|
const card = `<div id="${id}" class="device">
|
|
@@ -259,7 +274,7 @@ function getCard(dev) {
|
|
|
259
274
|
<div class="flip" style="cursor: pointer">
|
|
260
275
|
<span class="top right small" style="border-radius: 50%">
|
|
261
276
|
${battery}
|
|
262
|
-
|
|
277
|
+
<!--${lq}-->
|
|
263
278
|
${status}
|
|
264
279
|
</span>
|
|
265
280
|
<!--/a--!>
|
|
@@ -274,17 +289,20 @@ function getCard(dev) {
|
|
|
274
289
|
${infoBtn}
|
|
275
290
|
<span class="left" style="padding-top:8px">${room}</span>
|
|
276
291
|
<span class="left fw_info"></span>
|
|
277
|
-
<button name="delete" class="right btn-flat btn-small">
|
|
278
|
-
<i class="material-icons icon-
|
|
292
|
+
<button name="delete" class="right btn-flat btn-small tooltipped" title="Delete">
|
|
293
|
+
<i class="material-icons icon-red">delete</i>
|
|
279
294
|
</button>
|
|
280
|
-
<button name="edit" class="right btn-flat btn-small">
|
|
281
|
-
<i class="material-icons icon-
|
|
295
|
+
<button name="edit" class="right btn-flat btn-small tooltipped" title="Edit">
|
|
296
|
+
<i class="material-icons icon-black">edit</i>
|
|
297
|
+
</button>
|
|
298
|
+
<button name="swapimage" class="right btn-flat btn-small tooltipped" title="Select Image">
|
|
299
|
+
<i class="material-icons icon-black">image</i>
|
|
282
300
|
</button>
|
|
283
301
|
<button name="reconfigure" class="right btn-flat btn-small tooltipped" title="Reconfigure">
|
|
284
302
|
<i class="material-icons icon-red">sync</i>
|
|
285
303
|
</button>
|
|
286
304
|
${deactBtn}
|
|
287
|
-
${
|
|
305
|
+
${debugBtn}
|
|
288
306
|
</div>
|
|
289
307
|
</div>
|
|
290
308
|
</div>
|
|
@@ -364,6 +382,7 @@ function cleanConfirmation() {
|
|
|
364
382
|
const text = translateWord('Do you really want to remove orphaned states?');
|
|
365
383
|
$('#modalclean').find('p').text(text);
|
|
366
384
|
$('#cforce').prop('checked', false);
|
|
385
|
+
$('#cforce').removeClass('hide');
|
|
367
386
|
$('#cforcediv').removeClass('hide');
|
|
368
387
|
$('#modalclean a.btn[name=\'yes\']').unbind('click');
|
|
369
388
|
$('#modalclean a.btn[name=\'yes\']').click(() => {
|
|
@@ -479,14 +498,18 @@ function cleanDeviceStates(force) {
|
|
|
479
498
|
if (msg.error) {
|
|
480
499
|
showMessage(msg.error, _('Error'));
|
|
481
500
|
} else {
|
|
501
|
+
if (msg.stateList) {
|
|
502
|
+
//showMessage(msg.stateList.join('<p>'), 'State cleanup results');
|
|
503
|
+
}
|
|
482
504
|
getDevices();
|
|
483
505
|
}
|
|
484
506
|
}
|
|
485
507
|
});
|
|
486
|
-
showWaitingDialog('
|
|
508
|
+
showWaitingDialog('Orphaned states are being removed', 10);
|
|
487
509
|
}
|
|
488
510
|
|
|
489
511
|
function renameDevice(id, name) {
|
|
512
|
+
showMessage('rename device with ' + id + ' and ' + name, _('Error'));
|
|
490
513
|
sendTo(namespace, 'renameDevice', {id: id, name: name}, function (msg) {
|
|
491
514
|
if (msg) {
|
|
492
515
|
if (msg.error) {
|
|
@@ -616,11 +639,24 @@ function showDevices() {
|
|
|
616
639
|
const name = getDevName(dev_block);
|
|
617
640
|
editName(id, name);
|
|
618
641
|
});
|
|
642
|
+
$('.card-reveal-buttons button[name=\'swapdebug\']').click(function () {
|
|
643
|
+
const dev_block = $(this).parents('div.device');
|
|
644
|
+
const id = getDevId(dev_block);
|
|
645
|
+
const name = getDevName(dev_block);
|
|
646
|
+
toggleDebugDevice(id, name);
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
$('.card-reveal-buttons button[name=\'swapimage\']').click(function () {
|
|
650
|
+
const dev_block = $(this).parents('div.device');
|
|
651
|
+
const id = getDevId(dev_block);
|
|
652
|
+
selectImageOverride(id);
|
|
653
|
+
});
|
|
654
|
+
|
|
619
655
|
$('.card-reveal-buttons button[name=\'editgrp\']').click(function () {
|
|
620
656
|
const dev_block = $(this).parents('div.device');
|
|
621
657
|
const id = dev_block.attr('id').replace(namespace + '.group_', '');
|
|
622
658
|
const name = getDevName(dev_block);
|
|
623
|
-
|
|
659
|
+
editGroup(id, name, false);
|
|
624
660
|
});
|
|
625
661
|
$('button.btn-floating[name=\'join\']').click(function () {
|
|
626
662
|
const dev_block = $(this).parents('div.device');
|
|
@@ -751,9 +787,111 @@ function getCoordinatorInfo() {
|
|
|
751
787
|
}
|
|
752
788
|
});
|
|
753
789
|
}
|
|
790
|
+
function checkDebugDevice(id) {
|
|
791
|
+
if (debugDevices.indexOf(id) > -1) return 0
|
|
792
|
+
for (const addressPart of debugDevices) {
|
|
793
|
+
if (typeof id === 'string' && id.includes(addressPart)) {
|
|
794
|
+
return debugDevices.indexOf(addressPart)+1;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
return -1;
|
|
798
|
+
}
|
|
799
|
+
async function toggleDebugDevice(id) {
|
|
800
|
+
sendTo(namespace, 'setDeviceDebug', {id:id}, function (msg) {
|
|
801
|
+
sendTo(namespace, 'getDebugDevices', {}, function(msg) {
|
|
802
|
+
if (msg && typeof (msg.debugDevices == 'array')) {
|
|
803
|
+
debugDevices = msg.debugDevices;
|
|
804
|
+
}
|
|
805
|
+
else
|
|
806
|
+
debugDevices = [];
|
|
807
|
+
showDevices();
|
|
808
|
+
});
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
function updateDeviceData(device, data, global) {
|
|
813
|
+
sendTo(namespace, 'updateDeviceData', {target: device, data:data, global:global}, function(msg) {
|
|
814
|
+
if (msg && msg.hasOwnProperty.error) {
|
|
815
|
+
showMessage(msg.error, _('Error'));
|
|
816
|
+
}
|
|
817
|
+
getDevices();
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
async function selectImageOverride(id) {
|
|
823
|
+
const dev = devices.find((d) => d._id == id);
|
|
824
|
+
const imghtml = `<img src="${dev.common.icon || dev.icon}" width="80px">`
|
|
825
|
+
//console.error(imghtml)
|
|
826
|
+
const selectItems= [''];
|
|
827
|
+
$('#chooseimage').find('input[id=\'d_name\']').val(dev.common.name);
|
|
828
|
+
$('#chooseimage').find('.currentIcon').html(imghtml);
|
|
829
|
+
|
|
830
|
+
sendTo(namespace, 'getLocalImages', {}, function(msg) {
|
|
831
|
+
if (msg && msg.imageData) {
|
|
832
|
+
const imagedata = msg.imageData;
|
|
833
|
+
console.warn(JSON.stringify(dev.common));
|
|
834
|
+
const default_icon = (dev.common.type === 'group' ? dev.common.modelIcon : `img/${dev.common.type.replace(/\//g, '-')}.png`);
|
|
835
|
+
if (dev.legacyIcon) imagedata.unshift( { file:dev.legacyIcon, name:'legacy', data:dev.legacyIcon});
|
|
836
|
+
imagedata.unshift( { file:'none', name:'default', data:default_icon});
|
|
837
|
+
imagedata.unshift( { file:'current', name:'current', data:dev.common.icon || dev.icon});
|
|
838
|
+
|
|
839
|
+
list2select('#images', imagedata, selectItems,
|
|
840
|
+
function (key, image) {
|
|
841
|
+
return image.name
|
|
842
|
+
},
|
|
843
|
+
function (key, image) {
|
|
844
|
+
return image.file;
|
|
845
|
+
},
|
|
846
|
+
function (key, image) {
|
|
847
|
+
if (image.file.length < 50) {
|
|
848
|
+
return `data-icon="${image.data}"`;
|
|
849
|
+
} else {
|
|
850
|
+
return `data-icon="data:image/png; base64, ${image.data}"`;
|
|
851
|
+
}
|
|
852
|
+
},
|
|
853
|
+
);
|
|
854
|
+
|
|
855
|
+
$('#chooseimage a.btn[name=\'save\']').unbind('click');
|
|
856
|
+
$('#chooseimage a.btn[name=\'save\']').click(() => {
|
|
857
|
+
const image = $('#chooseimage').find('#images option:selected').val();
|
|
858
|
+
const global = $('#chooseimage').find('#globaloverride').prop('checked');
|
|
859
|
+
const name = $('#chooseimage').find('input[id=\'d_name\']').val();
|
|
860
|
+
console.warn(`update device image : ${id} : ${image} : ${global} : ${name} : ${dev.common.name}`);
|
|
861
|
+
const data = {};
|
|
862
|
+
if (image != 'current') data.icon= image;
|
|
863
|
+
if (name != dev.common.name) data.name = name;
|
|
864
|
+
updateDeviceData(id, data, global);
|
|
865
|
+
});
|
|
866
|
+
$('#chooseimage').modal('open');
|
|
867
|
+
Materialize.updateTextFields();
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
}
|
|
754
871
|
|
|
755
872
|
function getDevices() {
|
|
756
873
|
getCoordinatorInfo();
|
|
874
|
+
sendTo(namespace, 'getDeviceCleanupRequired', {}, function(msg) {
|
|
875
|
+
if (msg) {
|
|
876
|
+
if (msg.clean)
|
|
877
|
+
$('#state_cleanup_btn').removeClass('hide');
|
|
878
|
+
else
|
|
879
|
+
$('#state_cleanup_btn').addClass('hide');
|
|
880
|
+
if (msg.errors && msg.errors.length > 0) {
|
|
881
|
+
$('#show_errors_btn').removeClass('hide');
|
|
882
|
+
errorData = msg.errors;
|
|
883
|
+
}
|
|
884
|
+
else
|
|
885
|
+
$('#show_errors_btn').addClass('hide');
|
|
886
|
+
}
|
|
887
|
+
})
|
|
888
|
+
sendTo(namespace, 'getDebugDevices', {}, function(msg) {
|
|
889
|
+
if (msg && typeof (msg.debugDevices == 'array')) {
|
|
890
|
+
debugDevices = msg.debugDevices;
|
|
891
|
+
}
|
|
892
|
+
else
|
|
893
|
+
debugDevices = [];
|
|
894
|
+
});
|
|
757
895
|
sendTo(namespace, 'getDevices', {}, function (msg) {
|
|
758
896
|
if (msg) {
|
|
759
897
|
if (msg.error) {
|
|
@@ -768,6 +906,14 @@ function getDevices() {
|
|
|
768
906
|
});
|
|
769
907
|
}
|
|
770
908
|
|
|
909
|
+
function getNamedColors() {
|
|
910
|
+
sendTo(namespace, 'getNamedColors', {}, function(msg) {
|
|
911
|
+
if (msg && typeof msg.colors) {
|
|
912
|
+
namedColors = msg.colors;
|
|
913
|
+
}
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
|
|
771
917
|
function getDeviceCards() {
|
|
772
918
|
return $('#devices .device').not('.group');
|
|
773
919
|
}
|
|
@@ -787,6 +933,9 @@ function getMap() {
|
|
|
787
933
|
if (msg.error) {
|
|
788
934
|
showMessage(msg.error, _('Error'));
|
|
789
935
|
} else {
|
|
936
|
+
if (msg.errors.length > 0 && $('#errorCollectionOn').is(':checked')) {
|
|
937
|
+
showMessage(msg.errors.join('<p>'), 'Map generation messages');
|
|
938
|
+
}
|
|
790
939
|
map = msg;
|
|
791
940
|
showNetworkMap(devices, map);
|
|
792
941
|
}
|
|
@@ -794,14 +943,24 @@ function getMap() {
|
|
|
794
943
|
});
|
|
795
944
|
}
|
|
796
945
|
|
|
946
|
+
function getRandomExtPanID()
|
|
947
|
+
{
|
|
948
|
+
const bytes = [];
|
|
949
|
+
for (let i = 0;i<16;i++) {
|
|
950
|
+
bytes.push(Math.floor(Math.random() * 16).toString(16));
|
|
951
|
+
}
|
|
952
|
+
return bytes.join('');
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
|
|
797
956
|
// the function loadSettings has to exist ...
|
|
798
957
|
|
|
799
958
|
function load(settings, onChange) {
|
|
800
959
|
if (settings.panID === undefined) {
|
|
801
|
-
settings.panID =
|
|
960
|
+
settings.panID = Math.floor(Math.random() * 10000);
|
|
802
961
|
}
|
|
803
962
|
if (settings.extPanID === undefined) {
|
|
804
|
-
settings.extPanID =
|
|
963
|
+
settings.extPanID = getRandomExtPanID();
|
|
805
964
|
}
|
|
806
965
|
// fix for previous wrong value
|
|
807
966
|
if (settings.extPanID === 'DDDDDDDDDDDDDDD') {
|
|
@@ -844,11 +1003,13 @@ function load(settings, onChange) {
|
|
|
844
1003
|
}
|
|
845
1004
|
}
|
|
846
1005
|
|
|
1006
|
+
|
|
847
1007
|
getComPorts(onChange);
|
|
848
1008
|
|
|
849
1009
|
//dialog = new MatDialog({EndingTop: '50%'});
|
|
850
1010
|
getDevices();
|
|
851
|
-
|
|
1011
|
+
getNamedColors();
|
|
1012
|
+
//getMap();
|
|
852
1013
|
//addCard();
|
|
853
1014
|
|
|
854
1015
|
// Signal to admin, that no changes yet
|
|
@@ -857,6 +1018,9 @@ function load(settings, onChange) {
|
|
|
857
1018
|
$('#state_cleanup_btn').click(function () {
|
|
858
1019
|
cleanConfirmation();
|
|
859
1020
|
});
|
|
1021
|
+
$('#show_errors_btn').click(function () {
|
|
1022
|
+
showMessage(errorData.join('<br>'), 'Stashed error messages');
|
|
1023
|
+
});
|
|
860
1024
|
$('#fw_check_btn').click(function () {
|
|
861
1025
|
checkFwUpdate();
|
|
862
1026
|
});
|
|
@@ -889,17 +1053,17 @@ function load(settings, onChange) {
|
|
|
889
1053
|
|
|
890
1054
|
sendTo(namespace, 'getGroups', {}, function (data) {
|
|
891
1055
|
groups = data.groups;
|
|
892
|
-
showGroups();
|
|
1056
|
+
//showGroups();
|
|
893
1057
|
});
|
|
894
1058
|
|
|
895
1059
|
$('#add_group').click(function () {
|
|
896
1060
|
const maxind = parseInt(Object.getOwnPropertyNames(groups).reduce((a, b) => a > b ? a : b, 0));
|
|
897
|
-
|
|
1061
|
+
addGroup(maxind + 1, 'Group ' + maxind + 1);
|
|
898
1062
|
});
|
|
899
1063
|
|
|
900
1064
|
$('#add_grp_btn').click(function () {
|
|
901
1065
|
const maxind = parseInt(Object.getOwnPropertyNames(groups).reduce((a, b) => a > b ? a : b, 0));
|
|
902
|
-
|
|
1066
|
+
addGroup(maxind + 1, 'Group ' + maxind + 1);
|
|
903
1067
|
});
|
|
904
1068
|
|
|
905
1069
|
$('#code_pairing').click(function () {
|
|
@@ -1065,7 +1229,7 @@ socket.on('stateChange', function (id, state) {
|
|
|
1065
1229
|
socket.on('objectChange', function (id, obj) {
|
|
1066
1230
|
if (id.substring(0, namespaceLen) !== namespace) return;
|
|
1067
1231
|
//console.log('objectChange', id, obj);
|
|
1068
|
-
if (obj && obj.type == 'device' && obj.common.type !== 'group') {
|
|
1232
|
+
if (obj && obj.type == 'device') { // && obj.common.type !== 'group') {
|
|
1069
1233
|
updateDevice(id);
|
|
1070
1234
|
}
|
|
1071
1235
|
if (!obj) {
|
|
@@ -1128,10 +1292,10 @@ function showNetworkMap(devices, map) {
|
|
|
1128
1292
|
label: (dev.link_quality > 0 ? dev.common.name : `${dev.common.name}\n(disconnected)`),
|
|
1129
1293
|
title: dev._id.replace(namespace + '.', '') + extInfo,
|
|
1130
1294
|
shape: 'circularImage',
|
|
1131
|
-
image: dev.icon,
|
|
1295
|
+
image: dev.common.icon || dev.icon,
|
|
1132
1296
|
imagePadding: {top: 5, bottom: 5, left: 5, right: 5},
|
|
1133
|
-
color: {background: '
|
|
1134
|
-
font: {color: '#
|
|
1297
|
+
color: {background: '#cccccc', highlight: {background: 'white'}},
|
|
1298
|
+
font: {color: '#00bb00'},
|
|
1135
1299
|
borderWidth: 1,
|
|
1136
1300
|
borderWidthSelected: 4,
|
|
1137
1301
|
};
|
|
@@ -1139,7 +1303,7 @@ function showNetworkMap(devices, map) {
|
|
|
1139
1303
|
// node.shape = 'star';
|
|
1140
1304
|
node.image = 'zigbee.png';
|
|
1141
1305
|
node.label = 'Coordinator';
|
|
1142
|
-
delete node.color;
|
|
1306
|
+
// delete node.color;
|
|
1143
1307
|
}
|
|
1144
1308
|
return node;
|
|
1145
1309
|
};
|
|
@@ -1178,7 +1342,7 @@ function showNetworkMap(devices, map) {
|
|
|
1178
1342
|
// // parent/child
|
|
1179
1343
|
if (mapEntry.status !== 'online') {
|
|
1180
1344
|
label = label + ' (off)';
|
|
1181
|
-
linkColor = '#
|
|
1345
|
+
linkColor = '#660000';
|
|
1182
1346
|
}
|
|
1183
1347
|
if (mapEntry.lqi < 10) {
|
|
1184
1348
|
linkColor = '#ff0000';
|
|
@@ -1236,8 +1400,6 @@ function showNetworkMap(devices, map) {
|
|
|
1236
1400
|
}
|
|
1237
1401
|
});
|
|
1238
1402
|
}
|
|
1239
|
-
|
|
1240
|
-
// routing
|
|
1241
1403
|
/*
|
|
1242
1404
|
if (map.routing) {
|
|
1243
1405
|
map.routing.forEach((route)=>{
|
|
@@ -1248,7 +1410,7 @@ function showNetworkMap(devices, map) {
|
|
|
1248
1410
|
const to = routeDest._id;
|
|
1249
1411
|
const from = routeSource._id;
|
|
1250
1412
|
const label = route.status;
|
|
1251
|
-
const linkColor = '#
|
|
1413
|
+
const linkColor = '#ff55ff';
|
|
1252
1414
|
const edge = {
|
|
1253
1415
|
from: from,
|
|
1254
1416
|
to: to,
|
|
@@ -1298,7 +1460,7 @@ function showNetworkMap(devices, map) {
|
|
|
1298
1460
|
if (node) {
|
|
1299
1461
|
node.font = {color: '#ff0000'};
|
|
1300
1462
|
if (dev.info && dev.info.device._type == 'Coordinator') {
|
|
1301
|
-
node.font = {color: '#
|
|
1463
|
+
node.font = {color: '#00ff00'};
|
|
1302
1464
|
}
|
|
1303
1465
|
nodesArray.push(node);
|
|
1304
1466
|
}
|
|
@@ -1324,6 +1486,7 @@ function showNetworkMap(devices, map) {
|
|
|
1324
1486
|
const options = data.edges._data.get(id);
|
|
1325
1487
|
if (select) {
|
|
1326
1488
|
options.font.size = 15;
|
|
1489
|
+
console.warn(JSON.stringify(options.font));
|
|
1327
1490
|
} else {
|
|
1328
1491
|
options.font.size = 0;
|
|
1329
1492
|
}
|
|
@@ -1335,15 +1498,16 @@ function showNetworkMap(devices, map) {
|
|
|
1335
1498
|
doSelection(false, event.previousSelection.edges, this.body.data);
|
|
1336
1499
|
}
|
|
1337
1500
|
doSelection(true, event.edges, this.body.data);
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1501
|
+
/*
|
|
1502
|
+
if (event.nodes) {
|
|
1503
|
+
event.nodes.forEach((node)=>{
|
|
1504
|
+
//const options = network.clustering.findNode[node];
|
|
1505
|
+
network.clustering.updateClusteredNode(
|
|
1506
|
+
node, {size: 50}
|
|
1507
|
+
);
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
*/
|
|
1347
1511
|
};
|
|
1348
1512
|
network.on('selectNode', onMapSelect);
|
|
1349
1513
|
network.on('deselectNode', onMapSelect);
|
|
@@ -1848,6 +2012,7 @@ function list2select(selector, list, selected, getText, getKey, getData) {
|
|
|
1848
2012
|
element.select();
|
|
1849
2013
|
}
|
|
1850
2014
|
|
|
2015
|
+
/*
|
|
1851
2016
|
function showGroups() {
|
|
1852
2017
|
$('#groups_table').find('.group').remove();
|
|
1853
2018
|
if (!groups) return;
|
|
@@ -1870,48 +2035,59 @@ function showGroups() {
|
|
|
1870
2035
|
deleteGroupConfirmation(index, name);
|
|
1871
2036
|
});
|
|
1872
2037
|
}
|
|
2038
|
+
*/
|
|
1873
2039
|
|
|
1874
|
-
function
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
groupables.push(ep);
|
|
1883
|
-
}
|
|
1884
|
-
}
|
|
2040
|
+
function editGroup(id, name) {
|
|
2041
|
+
const grp = devGroups[id];
|
|
2042
|
+
let info = '';
|
|
2043
|
+
if (grp && grp.memberinfo) {
|
|
2044
|
+
for (let m=0; m< grp.memberinfo.length; m++) {
|
|
2045
|
+
const mi = grp.memberinfo[m];
|
|
2046
|
+
if (mi)
|
|
2047
|
+
info = info.concat(`<li class="collection-item"><label><input id="member_${m}" type="checkbox" checked="checked"/><span for="member_${m}">${mi.device} Endpoint ${mi.epid} (${mi.ieee})</span></label></li>`);
|
|
1885
2048
|
}
|
|
1886
|
-
//console.log('device ' + JSON.stringify(d));
|
|
1887
2049
|
}
|
|
1888
|
-
|
|
2050
|
+
$('#groupedit').find('.collection').html(info);
|
|
1889
2051
|
//var text = 'Enter new name for "'+name+'" ('+id+')?';
|
|
1890
|
-
|
|
1891
|
-
$('#groupedit').find('.editgroup').addClass('hide');
|
|
1892
|
-
$('#groupedit').find('.addgroup').removeClass('hide');
|
|
1893
|
-
$('#groupedit').find('.input-field.members').addClass('hide');
|
|
1894
|
-
$('#groupedit').find('.input-field.groupid').removeClass('hide');
|
|
1895
|
-
} else {
|
|
1896
|
-
$('#groupedit').find('.editgroup').removeClass('hide');
|
|
1897
|
-
$('#groupedit').find('.addgroup').addClass('hide');
|
|
1898
|
-
$('#groupedit').find('.input-field.members').removeClass('hide');
|
|
1899
|
-
$('#groupedit').find('.input-field.groupid').addClass('hide');
|
|
1900
|
-
}
|
|
2052
|
+
$('#groupedit').find('.editgroup').removeClass('hide');
|
|
1901
2053
|
$('#groupedit').find('input[id=\'g_index\']').val(id);
|
|
1902
2054
|
$('#groupedit').find('input[id=\'g_name\']').val(name);
|
|
1903
2055
|
$('#groupedit a.btn[name=\'save\']').unbind('click');
|
|
1904
2056
|
$('#groupedit a.btn[name=\'save\']').click(() => {
|
|
1905
|
-
const
|
|
1906
|
-
|
|
1907
|
-
|
|
2057
|
+
const newName = $('#groupedit').find('input[id=\'g_name\']').val();
|
|
2058
|
+
const Id = $('#groupedit').find('input[id=\'g_index\']').val();
|
|
2059
|
+
const grp = devGroups[Id];
|
|
2060
|
+
const removeMembers = [];
|
|
2061
|
+
if (grp && grp.memberinfo) {
|
|
2062
|
+
for (let m=0; m<grp.memberinfo.length;m++) {
|
|
2063
|
+
const member = grp.memberinfo[m];
|
|
2064
|
+
if (!$(`#member_${m}`).prop('checked'))
|
|
2065
|
+
removeMembers.push({id:member.ieee.replace('0x',''), ep:member.epid})
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
console.warn(`ID: ${Id} name: ${newName} removeMembers: ${JSON.stringify(removeMembers)}`)
|
|
2069
|
+
updateGroup(Id, newName, (removeMembers.length > 0 ? removeMembers: undefined));
|
|
1908
2070
|
// showGroups();
|
|
1909
|
-
|
|
2071
|
+
getDevices();
|
|
1910
2072
|
});
|
|
1911
2073
|
$('#groupedit').modal('open');
|
|
1912
2074
|
Materialize.updateTextFields();
|
|
1913
2075
|
}
|
|
1914
2076
|
|
|
2077
|
+
function addGroup(id, name) {
|
|
2078
|
+
//var text = 'Enter new name for "'+name+'" ('+id+')?';
|
|
2079
|
+
$('#groupadd').find('input[id=\'g_index\']').val(id);
|
|
2080
|
+
$('#groupadd').find('input[id=\'g_name\']').val(name);
|
|
2081
|
+
$('#groupadd a.btn[name=\'save\']').unbind('click');
|
|
2082
|
+
$('#groupadd a.btn[name=\'save\']').click(() => {
|
|
2083
|
+
const newId = $('#groupadd').find('input[id=\'g_index\']').val(),
|
|
2084
|
+
newName = $('#groupadd').find('input[id=\'g_name\']').val();
|
|
2085
|
+
updateGroup(newId, newName);
|
|
2086
|
+
});
|
|
2087
|
+
$('#groupadd').modal('open');
|
|
2088
|
+
Materialize.updateTextFields();
|
|
2089
|
+
}
|
|
2090
|
+
|
|
1915
2091
|
function deleteGroupConfirmation(id, name) {
|
|
1916
2092
|
const text = translateWord('Do you really whant to delete group') + ' "' + name + '" (' + id + ')?';
|
|
1917
2093
|
$('#modaldelete').find('p').text(text);
|
|
@@ -1925,10 +2101,9 @@ function deleteGroupConfirmation(id, name) {
|
|
|
1925
2101
|
$('#modaldelete').modal('open');
|
|
1926
2102
|
}
|
|
1927
2103
|
|
|
1928
|
-
function updateGroup(
|
|
1929
|
-
delete groups[id];
|
|
2104
|
+
function updateGroup(newId, newName, remove) {
|
|
1930
2105
|
groups[newId] = newName;
|
|
1931
|
-
sendTo(namespace, 'renameGroup', {id: newId, name: newName}, function (msg) {
|
|
2106
|
+
sendTo(namespace, 'renameGroup', {id: newId, name: newName, remove: remove}, function (msg) {
|
|
1932
2107
|
if (msg && msg.error) {
|
|
1933
2108
|
showMessage(msg.error, _('Error'));
|
|
1934
2109
|
}
|
|
@@ -1948,12 +2123,20 @@ function deleteGroup(id) {
|
|
|
1948
2123
|
|
|
1949
2124
|
function updateDev(id, newName, newGroups) {
|
|
1950
2125
|
const dev = devices.find((d) => d._id === id);
|
|
1951
|
-
|
|
1952
|
-
|
|
2126
|
+
const command = {id: id, name: id};
|
|
2127
|
+
let needName = false;
|
|
2128
|
+
if (dev) {
|
|
2129
|
+
if (dev.common.name !== newName) {
|
|
2130
|
+
command.name = newName;
|
|
2131
|
+
needName = true;
|
|
2132
|
+
}
|
|
2133
|
+
else command.name = dev.common.name;
|
|
1953
2134
|
}
|
|
2135
|
+
|
|
1954
2136
|
const keys = Object.keys(newGroups);
|
|
1955
2137
|
if (keys && keys.length) {
|
|
1956
|
-
|
|
2138
|
+
command.groups = newGroups
|
|
2139
|
+
sendTo(namespace, 'updateGroupMembership', command, function (msg) {
|
|
1957
2140
|
closeWaitingDialog();
|
|
1958
2141
|
if (msg && msg.error) {
|
|
1959
2142
|
showMessage(msg.error, _('Error'));
|
|
@@ -1965,24 +2148,20 @@ function updateDev(id, newName, newGroups) {
|
|
|
1965
2148
|
showWaitingDialog('Updating group memberships', 10);
|
|
1966
2149
|
|
|
1967
2150
|
}
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
else {
|
|
1978
|
-
// save dev-groups on success
|
|
1979
|
-
dev.groups = newGroups;
|
|
1980
|
-
}
|
|
1981
|
-
showDevices();
|
|
1982
|
-
});
|
|
2151
|
+
else if (needName)
|
|
2152
|
+
{
|
|
2153
|
+
sendTo(namespace, 'renameDevice', command, function(msg) {
|
|
2154
|
+
//closeWaitingDialog();
|
|
2155
|
+
if (msg && msg.error) {
|
|
2156
|
+
showMessage(msg.error, _('Error'));
|
|
2157
|
+
} else {
|
|
2158
|
+
// save dev-groups on success
|
|
2159
|
+
getDevices();
|
|
1983
2160
|
}
|
|
1984
|
-
|
|
1985
|
-
|
|
2161
|
+
|
|
2162
|
+
})
|
|
2163
|
+
|
|
2164
|
+
}
|
|
1986
2165
|
}
|
|
1987
2166
|
|
|
1988
2167
|
function resetConfirmation() {
|
|
@@ -2462,6 +2641,7 @@ function showDevInfo(id) {
|
|
|
2462
2641
|
$('#modaldevinfo').modal('open');
|
|
2463
2642
|
}
|
|
2464
2643
|
|
|
2644
|
+
/*
|
|
2465
2645
|
function showGroupList(show) {
|
|
2466
2646
|
const htmlsections = [];
|
|
2467
2647
|
for (const groupid in devGroups) {
|
|
@@ -2492,7 +2672,7 @@ function showGroupList(show) {
|
|
|
2492
2672
|
$('#grouplist').html(htmlsections.join(''));
|
|
2493
2673
|
$('#add').click(function () {
|
|
2494
2674
|
const maxind = parseInt(Object.getOwnPropertyNames(groups).reduce((a, b) => a > b ? a : b, 0));
|
|
2495
|
-
|
|
2675
|
+
addGroup(maxind + 1, 'Group ' + maxind + 1, true);
|
|
2496
2676
|
showGroupList(false);
|
|
2497
2677
|
});
|
|
2498
2678
|
|
|
@@ -2501,6 +2681,7 @@ function showGroupList(show) {
|
|
|
2501
2681
|
});
|
|
2502
2682
|
if (show) $('#modalgrouplist').modal('open');
|
|
2503
2683
|
}
|
|
2684
|
+
*/
|
|
2504
2685
|
|
|
2505
2686
|
let waitingTimeout, waitingInt;
|
|
2506
2687
|
|
|
@@ -2640,27 +2821,29 @@ function addExcludeDialog() {
|
|
|
2640
2821
|
const ids = devices.map(el => el._id);
|
|
2641
2822
|
const idx = ids.indexOf(exclude_id);
|
|
2642
2823
|
const exclude_model = devices[idx];
|
|
2824
|
+
console.warn('calling addExclude mit model ' + exclude_model)
|
|
2643
2825
|
|
|
2644
2826
|
addExclude(exclude_model);
|
|
2645
2827
|
});
|
|
2646
2828
|
prepareExcludeDialog();
|
|
2647
|
-
|
|
2829
|
+
console.warn('opening dialog');
|
|
2648
2830
|
$('#excludemodaledit').modal('open');
|
|
2649
2831
|
Materialize.updateTextFields();
|
|
2650
2832
|
}
|
|
2651
2833
|
|
|
2652
2834
|
function addExclude(exclude_model) {
|
|
2653
|
-
|
|
2654
|
-
exclude_model: exclude_model
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2835
|
+
if (typeof exclude_model == 'object' && exclude_model.hasOwnProperty('common'))
|
|
2836
|
+
sendTo(namespace, 'addExclude', { exclude_model: exclude_model }, function (msg) {
|
|
2837
|
+
closeWaitingDialog();
|
|
2838
|
+
if (msg) {
|
|
2839
|
+
if (msg.error) {
|
|
2840
|
+
showMessage(msg.error, _('Error'));
|
|
2841
|
+
}
|
|
2660
2842
|
}
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2843
|
+
console.log('getting excludes ?');
|
|
2844
|
+
getExclude();
|
|
2845
|
+
});
|
|
2846
|
+
else closeWaitingDialog();
|
|
2664
2847
|
}
|
|
2665
2848
|
|
|
2666
2849
|
function getExclude() {
|
|
@@ -2669,10 +2852,10 @@ function getExclude() {
|
|
|
2669
2852
|
if (msg.error) {
|
|
2670
2853
|
showMessage(msg.error, _('Error'));
|
|
2671
2854
|
} else {
|
|
2672
|
-
excludes = msg;
|
|
2855
|
+
excludes = msg.legacy;
|
|
2673
2856
|
showExclude();
|
|
2674
2857
|
}
|
|
2675
|
-
}
|
|
2858
|
+
} else console.warn('getExclude without msg')
|
|
2676
2859
|
});
|
|
2677
2860
|
}
|
|
2678
2861
|
|
|
@@ -2684,14 +2867,11 @@ function showExclude() {
|
|
|
2684
2867
|
return;
|
|
2685
2868
|
}
|
|
2686
2869
|
|
|
2687
|
-
excludes.forEach(
|
|
2688
|
-
const exclude_id =
|
|
2689
|
-
|
|
2870
|
+
excludes.forEach(id => {
|
|
2871
|
+
const exclude_id = id.key;
|
|
2872
|
+
const exclude_icon = id.value;
|
|
2690
2873
|
const exclude_dev = devices.find((d) => d.common.type == exclude_id) || {common: {name: exclude_id}};
|
|
2691
|
-
// exclude_icon = (exclude_dev.icon) ? `<img src="${exclude_dev.icon}" width="64px">` : '';
|
|
2692
|
-
|
|
2693
2874
|
const modelUrl = (!exclude_id) ? '' : `<a href="https://www.zigbee2mqtt.io/devices/${sanitizeModelParameter(exclude_id)}.html" target="_blank" rel="noopener noreferrer">${exclude_id}</a>`;
|
|
2694
|
-
|
|
2695
2875
|
const card = `
|
|
2696
2876
|
<div id="${exclude_id}" class="exclude col s12 m6 l4 xl3" style="height: 135px;padding-bottom: 10px;">
|
|
2697
2877
|
<div class="card hoverable">
|
|
@@ -2720,7 +2900,7 @@ function showExclude() {
|
|
|
2720
2900
|
$('#exclude button[name=\'delete\']').click(function () {
|
|
2721
2901
|
const exclude_id = $(this).parents('.exclude')[0].id;
|
|
2722
2902
|
deleteExcludeConfirmation(exclude_id);
|
|
2723
|
-
deleteExclude(exclude_id);
|
|
2903
|
+
//deleteExclude(exclude_id);
|
|
2724
2904
|
});
|
|
2725
2905
|
}
|
|
2726
2906
|
|
|
@@ -2745,6 +2925,7 @@ function deleteExclude(id) {
|
|
|
2745
2925
|
showMessage(msg.error, _('Error'));
|
|
2746
2926
|
}
|
|
2747
2927
|
}
|
|
2928
|
+
console.log('getting excludes ?');
|
|
2748
2929
|
getExclude();
|
|
2749
2930
|
});
|
|
2750
2931
|
}
|
|
@@ -2827,11 +3008,11 @@ function sortByTitle(element) {
|
|
|
2827
3008
|
return element.querySelector('.card-title').textContent.toLowerCase().trim();
|
|
2828
3009
|
}
|
|
2829
3010
|
|
|
2830
|
-
function getDashCard(dev, groupImage) {
|
|
3011
|
+
function getDashCard(dev, groupImage, groupstatus) {
|
|
2831
3012
|
const title = dev.common.name,
|
|
2832
3013
|
id = dev._id,
|
|
2833
3014
|
type = dev.common.type,
|
|
2834
|
-
img_src = (groupImage ? groupImage : dev.icon || dev.
|
|
3015
|
+
img_src = (groupImage ? groupImage : dev.common.icon || dev.icon),
|
|
2835
3016
|
isActive = !dev.common.deactivated,
|
|
2836
3017
|
rooms = [],
|
|
2837
3018
|
lang = systemLang || 'en';
|
|
@@ -2842,11 +3023,12 @@ function getDashCard(dev, groupImage) {
|
|
|
2842
3023
|
nwk = (dev.info && dev.info.device) ? dev.info.device._networkAddress : undefined,
|
|
2843
3024
|
battery_cls = getBatteryCls(dev.battery),
|
|
2844
3025
|
lqi_cls = getLQICls(dev.link_quality),
|
|
3026
|
+
unconnected_icon = (groupImage ? (groupstatus ? '<div class="col tool"><i class="material-icons icon-green">check_circle</i></div>' : '<div class="col tool"><i class="material-icons icon-red">cancel</i></div>') :'<div class="col tool"><i class="material-icons icon-red">leak_remove</i></div>'),
|
|
2845
3027
|
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>` : '',
|
|
2846
|
-
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 ?
|
|
2847
|
-
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>`),
|
|
2848
|
-
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>' : '',
|
|
2849
|
-
infoBtn = (nwk) ? `<button name="info" class="left btn-flat btn-small"><i class="material-icons icon-blue">info</i></button>` : '',
|
|
3028
|
+
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 ? unconnected_icon : ''),
|
|
3029
|
+
//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>`),
|
|
3030
|
+
//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>' : '',
|
|
3031
|
+
//infoBtn = (nwk) ? `<button name="info" class="left btn-flat btn-small"><i class="material-icons icon-blue">info</i></button>` : '',
|
|
2850
3032
|
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>` : '';
|
|
2851
3033
|
const info = (dev.statesDef) ? dev.statesDef.map((stateDef) => {
|
|
2852
3034
|
const id = stateDef.id;
|
|
@@ -2861,6 +3043,12 @@ function getDashCard(dev, groupImage) {
|
|
|
2861
3043
|
} else if (stateDef.type === 'boolean') {
|
|
2862
3044
|
const disabled = (stateDef.write) ? '' : 'disabled="disabled"';
|
|
2863
3045
|
val = `<label class="dash"><input type="checkbox" ${(val == true) ? 'checked=\'checked\'' : ''} ${disabled}/><span></span></label>`;
|
|
3046
|
+
} else if (stateDef.role === 'level.color.rgb') {
|
|
3047
|
+
const options = []
|
|
3048
|
+
for (const key of namedColors) {
|
|
3049
|
+
options.push(`<option value="${key}" ${val===key ? 'selected' : ''}>${key}</option>`);
|
|
3050
|
+
}
|
|
3051
|
+
val = `<select class="browser-default enum" style="color : white; background-color: grey; height: 16px; padding: 0; width: auto; display: inline-block">${options.join('')}</select>`;
|
|
2864
3052
|
} else if (stateDef.states && stateDef.write) {
|
|
2865
3053
|
let options;
|
|
2866
3054
|
if (typeof stateDef.states == 'string') {
|
|
@@ -2872,7 +3060,7 @@ function getDashCard(dev, groupImage) {
|
|
|
2872
3060
|
} else {
|
|
2873
3061
|
options = [];
|
|
2874
3062
|
for (const [key, value] of Object.entries(stateDef.states)) {
|
|
2875
|
-
options.push(`<option value="${key}" ${(val == key) ? 'selected' : ''}>${
|
|
3063
|
+
options.push(`<option value="${key}" ${(val == key) ? 'selected' : ''}>${key}</option>`);
|
|
2876
3064
|
}
|
|
2877
3065
|
}
|
|
2878
3066
|
val = `<select class="browser-default enum" style="color : white; background-color: grey; height: 16px; padding: 0; width: auto; display: inline-block">${options.join('')}</select>`;
|
|
@@ -2888,7 +3076,6 @@ function getDashCard(dev, groupImage) {
|
|
|
2888
3076
|
${idleTime}
|
|
2889
3077
|
${battery}
|
|
2890
3078
|
${lq}
|
|
2891
|
-
${status}
|
|
2892
3079
|
</span>
|
|
2893
3080
|
<span class="card-title truncate">${title}</span>
|
|
2894
3081
|
</div>
|