iobroker.zigbee 3.0.5 → 3.1.4
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 +34 -0
- package/admin/admin.js +475 -230
- package/admin/i18n/de/translations.json +16 -16
- package/admin/index_m.html +84 -91
- package/admin/tab_m.html +38 -16
- package/docs/de/readme.md +1 -1
- package/docs/en/readme.md +4 -2
- package/io-package.json +35 -28
- package/lib/DeviceDebug.js +25 -2
- package/lib/binding.js +8 -8
- package/lib/commands.js +386 -326
- package/lib/developer.js +2 -2
- package/lib/devices.js +13 -9
- package/lib/exclude.js +1 -1
- package/lib/exposes.js +56 -24
- package/lib/groups.js +408 -73
- package/lib/localConfig.js +23 -12
- package/lib/networkmap.js +10 -2
- package/lib/states.js +32 -2
- package/lib/statescontroller.js +361 -209
- package/lib/utils.js +7 -5
- package/lib/zbDelayedAction.js +4 -4
- package/lib/zbDeviceAvailability.js +102 -46
- package/lib/zbDeviceConfigure.js +7 -0
- package/lib/zbDeviceEvent.js +40 -7
- package/lib/zigbeecontroller.js +552 -75
- package/main.js +168 -505
- package/package.json +8 -11
- package/lib/tools.js +0 -55
package/admin/admin.js
CHANGED
|
@@ -22,11 +22,15 @@ let devices = [],
|
|
|
22
22
|
binding = [],
|
|
23
23
|
excludes = [],
|
|
24
24
|
coordinatorinfo = {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
installSource: 'IADefault_1',
|
|
26
|
+
channel: '-1',
|
|
27
|
+
port: 'Default_1',
|
|
28
|
+
installedVersion: 'Default_1',
|
|
29
|
+
type: 'Default_1',
|
|
30
|
+
revision: 'Default_1',
|
|
31
|
+
version: '9-9.9.9.9',
|
|
32
|
+
herdsman: '4.0.0',
|
|
33
|
+
converters: '24.0.0',
|
|
30
34
|
},
|
|
31
35
|
cidList,
|
|
32
36
|
shuffleInstance,
|
|
@@ -56,9 +60,9 @@ const networkOptions = {
|
|
|
56
60
|
|
|
57
61
|
|
|
58
62
|
const savedSettings = [
|
|
59
|
-
'port', 'panID', 'channel', 'disableLed', 'countDown', 'groups', 'extPanID', 'precfgkey', 'transmitPower',
|
|
60
|
-
'adapterType', 'debugHerdsman', 'disableBackup', '
|
|
61
|
-
'warnOnDeviceAnnouncement', 'baudRate', 'flowCTRL', 'autostart'
|
|
63
|
+
'port', 'panID', 'channel', 'disableLed', 'countDown', 'groups', 'extPanID', 'precfgkey', 'transmitPower','useNewCompositeStates',
|
|
64
|
+
'adapterType', 'debugHerdsman', 'disableBackup', 'external', 'startWithInconsistent','pingTimeout','listDevicesAtStart',
|
|
65
|
+
'warnOnDeviceAnnouncement', 'baudRate', 'flowCTRL', 'autostart', 'readAtAnnounce', 'startReadDelay', 'readAllAtStart','pingCluster'
|
|
62
66
|
];
|
|
63
67
|
|
|
64
68
|
function getDeviceByID(ID) {
|
|
@@ -74,7 +78,7 @@ function getDeviceByID(ID) {
|
|
|
74
78
|
function getDevice(ieeeAddr) {
|
|
75
79
|
return devices.find((devInfo) => {
|
|
76
80
|
try {
|
|
77
|
-
return devInfo.info.device.
|
|
81
|
+
return devInfo.info.device.ieee == ieeeAddr;
|
|
78
82
|
} catch (e) {
|
|
79
83
|
//console.log("No dev with ieee " + ieeeAddr);
|
|
80
84
|
}
|
|
@@ -85,7 +89,7 @@ function getDevice(ieeeAddr) {
|
|
|
85
89
|
function getDeviceByNetwork(nwk) {
|
|
86
90
|
return devices.find((devInfo) => {
|
|
87
91
|
try {
|
|
88
|
-
return devInfo.info.device.
|
|
92
|
+
return devInfo.info.device.nwk == nwk;
|
|
89
93
|
} catch (e) {
|
|
90
94
|
//console.log("No dev with nwkAddr " + nwk);
|
|
91
95
|
}
|
|
@@ -111,14 +115,15 @@ function getLQICls(value) {
|
|
|
111
115
|
|
|
112
116
|
function getCoordinatorCard(dev) {
|
|
113
117
|
const title = 'Zigbee Coordinator',
|
|
114
|
-
id = dev._id,
|
|
118
|
+
id = dev && dev._id ? dev._id : '0x00000000',
|
|
115
119
|
img_src = 'zigbee.png',
|
|
116
120
|
rid = id.split('.').join('_'),
|
|
117
121
|
image = `<img src="${img_src}" width="80px">`,
|
|
118
122
|
paired = '',
|
|
119
|
-
status = `<div class="col tool"><i class="material-icons icon-green">check_circle</i></div>`,
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
status = coordinatorinfo.autostart ? (dev ? `<div class="col tool"><i class="material-icons icon-green">check_circle</i></div>` : `<div class="col tool"><i class="material-icons icon-red">remove_circle</i></div>`) : `<div class="col tool"><i class="material-icons icon-orange">pause_circle_filled</i></div>`,
|
|
124
|
+
//status = dev ? `<div class="col tool"><i class="material-icons icon-green">check_circle</i></div>` : `<div class="col tool"><i class="material-icons icon-red">remove_circle</i></div>`,
|
|
125
|
+
lqi_cls = dev ? getLQICls(dev.link_quality) : -1,
|
|
126
|
+
lq = (dev && dev.link_quality) ? `<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>` : '',
|
|
122
127
|
info = `<div style="min-height:88px; font-size: 0.8em" class="truncate">
|
|
123
128
|
<ul>
|
|
124
129
|
<li><span class="label">type:</span><span>${coordinatorinfo.type}</span></li>
|
|
@@ -126,15 +131,21 @@ function getCoordinatorCard(dev) {
|
|
|
126
131
|
<li><span class="label">revision:</span><span>${coordinatorinfo.revision}</span></li>
|
|
127
132
|
<li><span class="label">port:</span><span>${coordinatorinfo.port}</span></li>
|
|
128
133
|
<li><span class="label">channel:</span><span>${coordinatorinfo.channel}</span></li>
|
|
134
|
+
<li><span class="label">------------</span><span>Software versions </span></li>
|
|
135
|
+
<li><span class="label">adapter:</span><span>${coordinatorinfo.installedVersion}</span></li>
|
|
136
|
+
<li><span class="label">installed from:</span><span>${coordinatorinfo.installSource}</span></li>
|
|
137
|
+
<li><span class="label">ZHC / ZH:</span><span>${coordinatorinfo.converters} / ${coordinatorinfo.herdsman}</span></li>
|
|
129
138
|
</ul>
|
|
130
139
|
</div>`,
|
|
131
|
-
permitJoinBtn =
|
|
140
|
+
permitJoinBtn = '<div class="col tool"><button name="joinCard" class="waves-effect btn-small btn-flat right hoverable green"><i class="material-icons icon-green">leak_add</i></button></div>',
|
|
141
|
+
//permitJoinBtn = `<div class="col tool"><button name="join" class="btn-floating-sml waves-effect waves-light right hoverable green><i class="material-icons">leak_add</i></button></div>`,
|
|
132
142
|
card = `<div id="${id}" class="device">
|
|
133
143
|
<div class="card hoverable">
|
|
134
144
|
<div class="card-content zcard">
|
|
135
145
|
<span class="top right small" style="border-radius: 50%">
|
|
136
146
|
${lq}
|
|
137
147
|
${status}
|
|
148
|
+
${permitJoinBtn}
|
|
138
149
|
</span>
|
|
139
150
|
<!--/a--!>
|
|
140
151
|
<span id="dName" class="card-title truncate">${title}</span><!--${paired}--!>
|
|
@@ -142,11 +153,6 @@ function getCoordinatorCard(dev) {
|
|
|
142
153
|
${info}
|
|
143
154
|
<div class="footer right-align"></div>
|
|
144
155
|
</div>
|
|
145
|
-
<div class="card-action">
|
|
146
|
-
<div class="card-reveal-buttons">
|
|
147
|
-
${permitJoinBtn}
|
|
148
|
-
</div>
|
|
149
|
-
</div>
|
|
150
156
|
</div>
|
|
151
157
|
</div>`;
|
|
152
158
|
return card;
|
|
@@ -167,9 +173,10 @@ function getGroupCard(dev) {
|
|
|
167
173
|
}
|
|
168
174
|
}
|
|
169
175
|
devGroups[numid] = dev;
|
|
176
|
+
const roomInfo = rooms.length ? `<li><span class="labelinfo">rooms:</span><span>${rooms.join(',') || ''}</span></li>` : '';
|
|
170
177
|
const room = rooms.join(',') || ' ';
|
|
171
178
|
let memberCount = 0;
|
|
172
|
-
let info = `<div style="min-height:88px; font-size: 0.8em;
|
|
179
|
+
let info = `<div style="min-height:88px; font-size: 0.8em; overflow-y: auto" class="truncate">
|
|
173
180
|
<ul>`;
|
|
174
181
|
info = info.concat(`<li><span class="labelinfo">Group ${numid}</span></li>`);
|
|
175
182
|
if (dev.memberinfo === undefined) {
|
|
@@ -181,7 +188,7 @@ function getGroupCard(dev) {
|
|
|
181
188
|
memberCount = (dev.memberinfo.length < 8 ? dev.memberinfo.length : 7);
|
|
182
189
|
}
|
|
183
190
|
;
|
|
184
|
-
info = info.concat(`
|
|
191
|
+
info = info.concat(` ${roomInfo}</ul>
|
|
185
192
|
</div>`);
|
|
186
193
|
const image = `<img src="${dev.common.icon}" width="64px" onerror="this.onerror=null;this.src='img/unavailable.png';">`;
|
|
187
194
|
const dashCard = getDashCard(dev, dev.common.icon, memberCount > 0);
|
|
@@ -199,11 +206,11 @@ function getGroupCard(dev) {
|
|
|
199
206
|
</div>
|
|
200
207
|
<i class="left">${image}</i>
|
|
201
208
|
${info}
|
|
209
|
+
|
|
202
210
|
<div class="footer right-align"></div>
|
|
203
211
|
</div>
|
|
204
212
|
<div class="card-action">
|
|
205
213
|
<div class="card-reveal-buttons">
|
|
206
|
-
<span class="left" style="padding-top:8px">${room}</span>
|
|
207
214
|
<button name="deletegrp" class="right btn-flat btn-small">
|
|
208
215
|
<i class="material-icons icon-black">delete</i>
|
|
209
216
|
</button>
|
|
@@ -246,12 +253,13 @@ function getCard(dev) {
|
|
|
246
253
|
rooms.push(dev.rooms[r]);
|
|
247
254
|
}
|
|
248
255
|
}
|
|
249
|
-
const room = rooms.join(',') || ' ';
|
|
250
256
|
const paired = (dev.paired) ? '' : '<i class="material-icons right">leak_remove</i>';
|
|
251
257
|
const rid = id.split('.').join('_');
|
|
252
258
|
const modelUrl = (!type) ? '' : `<a href="https://www.zigbee2mqtt.io/devices/${type_url}.html" target="_blank" rel="noopener noreferrer">${type}</a>`;
|
|
259
|
+
const groupInfo = dev.groupNames ? `<li><span class="labelinfo">groups:</span><span>${dev.groupNames || ''}</span></li>` : '';
|
|
260
|
+
const roomInfo = rooms.length ? `<li><span class="labelinfo">rooms:</span><span>${rooms.join(',') || ''}</span></li>` : '';
|
|
253
261
|
const image = `<img src="${img_src}" width="80px" onerror="this.onerror=null;this.src='img/unavailable.png';">`,
|
|
254
|
-
nwk = (dev.info && dev.info.device) ? dev.info.device.
|
|
262
|
+
nwk = (dev.info && dev.info.device) ? dev.info.device.nwk : undefined,
|
|
255
263
|
battery_cls = (isActive ? getBatteryCls(dev.battery) : ''),
|
|
256
264
|
lqi_cls = getLQICls(dev.link_quality),
|
|
257
265
|
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>` : '',
|
|
@@ -264,12 +272,14 @@ function getCard(dev) {
|
|
|
264
272
|
<li><span class="labelinfo">ieee:</span><span>0x${ieee}</span></li>
|
|
265
273
|
<li><span class="labelinfo">nwk:</span><span>${(nwk) ? nwk.toString() + ' (0x' + nwk.toString(16) + ')' : ''}</span></li>
|
|
266
274
|
<li><span class="labelinfo">model:</span><span>${modelUrl}</span></li>
|
|
267
|
-
|
|
275
|
+
${groupInfo}
|
|
276
|
+
${roomInfo}
|
|
268
277
|
</ul>
|
|
269
278
|
</div>`,
|
|
270
279
|
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>`,
|
|
271
280
|
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>`,
|
|
272
281
|
infoBtn = (nwk) ? `<button name="info" class="left btn-flat btn-small"><i class="material-icons icon-blue">info</i></button>` : '';
|
|
282
|
+
|
|
273
283
|
const dashCard = getDashCard(dev);
|
|
274
284
|
const card = `<div id="${id}" class="device">
|
|
275
285
|
<div class="card hoverable flipable ${isActive ? '' : 'bg_red'}">
|
|
@@ -292,7 +302,7 @@ function getCard(dev) {
|
|
|
292
302
|
<div class="card-action">
|
|
293
303
|
<div class="card-reveal-buttons">
|
|
294
304
|
${infoBtn}
|
|
295
|
-
|
|
305
|
+
|
|
296
306
|
<span class="left fw_info"></span>
|
|
297
307
|
<button name="delete" class="right btn-flat btn-small tooltipped" title="Delete">
|
|
298
308
|
<i class="material-icons icon-red">delete</i>
|
|
@@ -377,7 +387,7 @@ function deleteConfirmation(id, name) {
|
|
|
377
387
|
$('#modaldelete a.btn[name=\'yes\']').unbind('click');
|
|
378
388
|
$('#modaldelete a.btn[name=\'yes\']').click(() => {
|
|
379
389
|
const force = $('#force').prop('checked');
|
|
380
|
-
|
|
390
|
+
deleteZigbeeDevice(id, force);
|
|
381
391
|
});
|
|
382
392
|
$('#modaldelete').modal('open');
|
|
383
393
|
Materialize.updateTextFields();
|
|
@@ -396,7 +406,8 @@ function deleteNvBackupConfirmation() {
|
|
|
396
406
|
closeWaitingDialog();
|
|
397
407
|
if (msg) {
|
|
398
408
|
if (msg.error) {
|
|
399
|
-
|
|
409
|
+
if (msg.error.includes('ENOENT')) showMessage('No nvRam backup available for deletion.', _('Error'))
|
|
410
|
+
else showMessage(msg.error, _('Error'));
|
|
400
411
|
} else {
|
|
401
412
|
getDevices();
|
|
402
413
|
}
|
|
@@ -435,29 +446,50 @@ function editName(id, name) {
|
|
|
435
446
|
|
|
436
447
|
const device_options = {};
|
|
437
448
|
const received_options = {};
|
|
449
|
+
console.warn('editName called with ' + id + ' and ' + name);
|
|
450
|
+
const dev = devices.find((d) => d._id == id);
|
|
451
|
+
$('#modaledit').find('input[id=\'d_name\']').val(name);
|
|
452
|
+
const groupables = [];
|
|
438
453
|
|
|
439
454
|
function removeOption(k) {
|
|
440
|
-
if (k && device_options.hasOwnProperty(k))
|
|
455
|
+
if (k && device_options.hasOwnProperty(k)) {
|
|
456
|
+
if (dev.info.mapped && dev.info.mapped.options && dev.info.mapped.options.includes(device_options[k].key))
|
|
457
|
+
availableOptions.push(device_options[k].key)
|
|
458
|
+
delete device_options[k];
|
|
459
|
+
}
|
|
441
460
|
}
|
|
442
461
|
|
|
443
462
|
function addOption() {
|
|
444
463
|
let idx=1;
|
|
445
464
|
let key = '';
|
|
465
|
+
const optionName = $('#option_Selector').val();
|
|
466
|
+
console.warn(`option name is ${optionName}`);
|
|
446
467
|
do {
|
|
447
468
|
key = `o${idx++}`;
|
|
448
469
|
}
|
|
449
470
|
while (device_options.hasOwnProperty(key));
|
|
450
|
-
device_options[key] = {key
|
|
471
|
+
device_options[key] = { key:optionName, value:''};
|
|
472
|
+
console.warn(`device_options: ${JSON.stringify(device_options)}`);
|
|
473
|
+
idx = availableOptions.indexOf(optionName);
|
|
474
|
+
console.warn(`idx: ${idx}, ao:${JSON.stringify(availableOptions)}, on: ${optionName}`);
|
|
475
|
+
if (idx > -1) availableOptions.splice(idx, 1);
|
|
451
476
|
}
|
|
452
477
|
|
|
453
|
-
function updateOptions() {
|
|
478
|
+
function updateOptions(candidates) {
|
|
479
|
+
if (candidates.length > 0) {
|
|
480
|
+
$('#modaledit').find('.new_options_available').removeClass('hide');
|
|
481
|
+
list2select('#option_Selector', candidates, [], (key, val) => { return val; }, (key, val) => { return val; })
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
$('#modaledit').find('.new_options_available').addClass('hide');
|
|
485
|
+
}
|
|
454
486
|
const html_options=[];
|
|
455
487
|
|
|
456
|
-
console.warn(`
|
|
488
|
+
console.warn(`option_Selector is ${JSON.stringify(device_options)}`)
|
|
457
489
|
|
|
458
490
|
for (const k in device_options) {
|
|
459
491
|
html_options.push(`<div class="row">`);
|
|
460
|
-
html_options.push(`<div class="input-field suffix col s5 m5 l5"><input id="option_key_${k}" type="text" class="value" /><label for="option_key_${k}">Option</label></div>`)
|
|
492
|
+
html_options.push(`<div class="input-field suffix col s5 m5 l5"><input disabled id="option_key_${k}" type="text" class="value" /><label for="option_key_${k}">Option</label></div>`)
|
|
461
493
|
html_options.push(`<div class="input-field suffix col s5 m5 l5"><input id="option_value_${k}" type="text" class="value" /><label for="option_value_${k}">Value</label></div>`)
|
|
462
494
|
html_options.push(`<div class="col"><a id="option_rem_${k}" class='btn' ><i class="material-icons">remove_circle</i></a></div>`);
|
|
463
495
|
html_options.push(`</div>`)
|
|
@@ -471,11 +503,11 @@ function editName(id, name) {
|
|
|
471
503
|
$(`#option_key_${k}`).val(device_options[k].key);
|
|
472
504
|
$(`#option_value_${k}`).val(device_options[k].value);
|
|
473
505
|
$(`#option_rem_${k}`).unbind('click');
|
|
474
|
-
$(`#option_rem_${k}`).click(() => { removeOption(k); updateOptions() });
|
|
506
|
+
$(`#option_rem_${k}`).click(() => { removeOption(k); updateOptions(availableOptions) });
|
|
475
507
|
}
|
|
476
508
|
}
|
|
477
509
|
else {
|
|
478
|
-
$('#modaledit').find('.options_available').addClass('hide');
|
|
510
|
+
if (candidates.length == 0) $('#modaledit').find('.options_available').addClass('hide');
|
|
479
511
|
}
|
|
480
512
|
}
|
|
481
513
|
|
|
@@ -504,18 +536,15 @@ function editName(id, name) {
|
|
|
504
536
|
|
|
505
537
|
|
|
506
538
|
|
|
507
|
-
console.warn('editName called with ' + id + ' and ' + name);
|
|
508
|
-
const dev = devices.find((d) => d._id == id);
|
|
509
|
-
$('#modaledit').find('input[id=\'d_name\']').val(name);
|
|
510
|
-
const groupables = [];
|
|
511
539
|
if (dev && dev.info && dev.info.endpoints) {
|
|
512
540
|
for (const ep of dev.info.endpoints) {
|
|
513
|
-
if (ep.
|
|
541
|
+
if (ep.input_clusters.includes(4)) {
|
|
514
542
|
groupables.push({epid: EndPointIDfromEndPoint(ep), ep: ep, memberOf: []});
|
|
515
543
|
}
|
|
516
544
|
}
|
|
517
545
|
}
|
|
518
546
|
const numEP = groupables.length;
|
|
547
|
+
const availableOptions = (dev.info.mapped ? dev.info.mapped.options.slice() || []:[]);
|
|
519
548
|
|
|
520
549
|
if (numEP > 0) {
|
|
521
550
|
$('#modaledit').find('.groups_available').removeClass('hide');
|
|
@@ -562,7 +591,7 @@ function editName(id, name) {
|
|
|
562
591
|
sendTo(namespace, 'getLocalConfigItems', { target:id, global:false, key:'options' }, function (msg) {
|
|
563
592
|
if (msg) {
|
|
564
593
|
if (msg.error) showMessage(msg.error, '_Error');
|
|
565
|
-
console.warn(`return is ${msg}`)
|
|
594
|
+
console.warn(`return is ${JSON.stringify(msg)}`)
|
|
566
595
|
Object.keys(device_options).forEach(key => delete device_options[key]);
|
|
567
596
|
Object.keys(received_options).forEach(key => delete received_options[key]);
|
|
568
597
|
if (typeof msg.options === 'object') {
|
|
@@ -570,12 +599,16 @@ function editName(id, name) {
|
|
|
570
599
|
let cnt = 1;
|
|
571
600
|
for (const key in msg.options)
|
|
572
601
|
{
|
|
602
|
+
const idx = availableOptions.indexOf(key);
|
|
603
|
+
console.warn(`key ${key} : index : ${idx}`);
|
|
604
|
+
if (idx > -1) availableOptions.splice(idx,1);
|
|
573
605
|
received_options[key]=msg.options[key];
|
|
574
606
|
device_options[`o${cnt}`] = { key:key, value:msg.options[key]}
|
|
575
607
|
cnt++;
|
|
576
608
|
}
|
|
577
609
|
}
|
|
578
|
-
|
|
610
|
+
console.warn(`avo ${JSON.stringify(availableOptions)}, mapped: ${JSON.stringify(dev.info.mapped.options)}`);
|
|
611
|
+
updateOptions(availableOptions);
|
|
579
612
|
|
|
580
613
|
} else showMessage('callback without message');
|
|
581
614
|
});
|
|
@@ -584,7 +617,7 @@ function editName(id, name) {
|
|
|
584
617
|
$('#modaledit a.btn[name=\'add_options\']').click(() => {
|
|
585
618
|
getOptionsFromUI(device_options, received_options);
|
|
586
619
|
addOption();
|
|
587
|
-
updateOptions()
|
|
620
|
+
updateOptions(availableOptions)
|
|
588
621
|
});
|
|
589
622
|
$('#modaledit a.btn[name=\'save\']').click(() => {
|
|
590
623
|
const newName = $('#modaledit').find('input[id=\'d_name\']').val();
|
|
@@ -625,8 +658,8 @@ function GenerateGroupChange(oldmembers, newmembers) {
|
|
|
625
658
|
return grpchng;
|
|
626
659
|
}
|
|
627
660
|
|
|
628
|
-
function
|
|
629
|
-
sendTo(namespace, '
|
|
661
|
+
function deleteZigbeeDevice(id, force) {
|
|
662
|
+
sendTo(namespace, 'deleteZigbeeDevice', {id: id, force: force}, function (msg) {
|
|
630
663
|
closeWaitingDialog();
|
|
631
664
|
if (msg) {
|
|
632
665
|
if (msg.error) {
|
|
@@ -671,7 +704,9 @@ function renameDevice(id, name) {
|
|
|
671
704
|
}
|
|
672
705
|
|
|
673
706
|
function showDevices() {
|
|
707
|
+
console.warn('show Devices called')
|
|
674
708
|
let html = '';
|
|
709
|
+
let hasCoordinator = false;
|
|
675
710
|
const lang = systemLang || 'en';
|
|
676
711
|
// sort by rooms
|
|
677
712
|
devices.sort((a, b) => {
|
|
@@ -703,19 +738,17 @@ function showDevices() {
|
|
|
703
738
|
});
|
|
704
739
|
for (let i = 0; i < devices.length; i++) {
|
|
705
740
|
const d = devices[i];
|
|
706
|
-
if (
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
;
|
|
714
|
-
if (d.info && d.info.device._type == 'Coordinator') {
|
|
741
|
+
if (d.common && d.common.type == 'group') {
|
|
742
|
+
const card = getGroupCard(d);
|
|
743
|
+
html += card;
|
|
744
|
+
continue;
|
|
745
|
+
};
|
|
746
|
+
if (d.info && d.info.device && d.info.device.type == 'Coordinator') {
|
|
747
|
+
hasCoordinator=true;
|
|
715
748
|
const card = getCoordinatorCard(d);
|
|
716
749
|
html += card;
|
|
717
750
|
} else {
|
|
718
|
-
//if (d.groups && d.info && d.info.device.
|
|
751
|
+
//if (d.groups && d.info && d.info.device.type == "Router") {
|
|
719
752
|
if (d.groups) {
|
|
720
753
|
//devGroups[d._id] = d.groups;
|
|
721
754
|
if (typeof d.groups.map == 'function') {
|
|
@@ -730,6 +763,8 @@ function showDevices() {
|
|
|
730
763
|
html += card;
|
|
731
764
|
}
|
|
732
765
|
}
|
|
766
|
+
if (!hasCoordinator) html += getCoordinatorCard();
|
|
767
|
+
|
|
733
768
|
$('#devices').html(html);
|
|
734
769
|
hookControls();
|
|
735
770
|
|
|
@@ -771,6 +806,7 @@ function showDevices() {
|
|
|
771
806
|
return dev_block.find('#dName').text();
|
|
772
807
|
};
|
|
773
808
|
const getDevId = function (dev_block) {
|
|
809
|
+
console.warn(`getDevId called with ${JSON.stringify(dev_block)}`)
|
|
774
810
|
return dev_block.attr('id');
|
|
775
811
|
};
|
|
776
812
|
$('.card-reveal-buttons button[name=\'delete\']').click(function () {
|
|
@@ -807,13 +843,24 @@ function showDevices() {
|
|
|
807
843
|
const name = getDevName(dev_block);
|
|
808
844
|
editGroup(id, name, false);
|
|
809
845
|
});
|
|
810
|
-
$('button
|
|
846
|
+
$('button[name=\'joinCard\']').click(function () {
|
|
811
847
|
const dev_block = $(this).parents('div.device');
|
|
812
848
|
if (!$('#pairing').hasClass('pulse')) {
|
|
813
849
|
joinProcess(getDevId(dev_block));
|
|
814
850
|
}
|
|
815
851
|
showPairingProcess();
|
|
816
852
|
});
|
|
853
|
+
$('button[name=\'deviceQuery\']').click(function () {
|
|
854
|
+
const dev_block = $(this).parents('div.device');
|
|
855
|
+
sendTo(namespace, 'setState', {id: `${getDevId(dev_block)}.device_query`, val: true}, function (data) {
|
|
856
|
+
//console.log(data);
|
|
857
|
+
}); });
|
|
858
|
+
$('#modalpairing a.btn[name=\'extendpairing\']').click(function () {
|
|
859
|
+
letsPairing();
|
|
860
|
+
});
|
|
861
|
+
$('#modalpairing a.btn[name=\'endpairing\']').click(function () {
|
|
862
|
+
stopPairing();
|
|
863
|
+
});
|
|
817
864
|
$('.card-reveal-buttons button[name=\'info\']').click(function () {
|
|
818
865
|
const dev_block = $(this).parents('div.device');
|
|
819
866
|
showDevInfo(getDevId(dev_block));
|
|
@@ -838,6 +885,14 @@ function showDevices() {
|
|
|
838
885
|
translateAll();
|
|
839
886
|
}
|
|
840
887
|
|
|
888
|
+
function downloadIcons() {
|
|
889
|
+
sendTo(namespace, 'downloadIcons', {}, function (msg) {
|
|
890
|
+
if (msg && msg.msg) {
|
|
891
|
+
showMessage(msg.msg, _('Result'));
|
|
892
|
+
}
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
|
|
841
896
|
function checkFwUpdate() {
|
|
842
897
|
const deviceCards = getDeviceCards();
|
|
843
898
|
const getFwInfoNode = function (deviceCard) {
|
|
@@ -888,7 +943,7 @@ function checkFwUpdate() {
|
|
|
888
943
|
|
|
889
944
|
function letsPairingWithCode(code) {
|
|
890
945
|
messages = [];
|
|
891
|
-
sendTo(namespace, 'letsPairing', {code: code}, function (msg) {
|
|
946
|
+
sendTo(namespace, 'letsPairing', {code: code, stop:false}, function (msg) {
|
|
892
947
|
if (msg && msg.error) {
|
|
893
948
|
showMessage(msg.error, _('Error'));
|
|
894
949
|
}
|
|
@@ -900,7 +955,16 @@ function letsPairingWithCode(code) {
|
|
|
900
955
|
|
|
901
956
|
function letsPairing() {
|
|
902
957
|
messages = [];
|
|
903
|
-
sendTo(namespace, 'letsPairing', {}, function (msg) {
|
|
958
|
+
sendTo(namespace, 'letsPairing', {stop:false}, function (msg) {
|
|
959
|
+
if (msg && msg.error) {
|
|
960
|
+
showMessage(msg.error, _('Error'));
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
function stopPairing() {
|
|
966
|
+
messages = [];
|
|
967
|
+
sendTo(namespace, 'letsPairing', {stop:true}, function (msg) {
|
|
904
968
|
if (msg && msg.error) {
|
|
905
969
|
showMessage(msg.error, _('Error'));
|
|
906
970
|
}
|
|
@@ -918,7 +982,7 @@ function touchlinkReset() {
|
|
|
918
982
|
|
|
919
983
|
function joinProcess(devId) {
|
|
920
984
|
messages = [];
|
|
921
|
-
sendTo(namespace, 'letsPairing', {id: devId}, function (msg) {
|
|
985
|
+
sendTo(namespace, 'letsPairing', {id: devId, stop:false}, function (msg) {
|
|
922
986
|
if (msg && msg.error) {
|
|
923
987
|
showMessage(msg.error, _('Error'));
|
|
924
988
|
}
|
|
@@ -926,17 +990,19 @@ function joinProcess(devId) {
|
|
|
926
990
|
}
|
|
927
991
|
|
|
928
992
|
function getCoordinatorInfo() {
|
|
993
|
+
console.warn('calling getCoordinatorInfo');
|
|
929
994
|
sendTo(namespace, 'getCoordinatorInfo', {}, function (msg) {
|
|
930
995
|
if (msg) {
|
|
996
|
+
console.warn(JSON.stringify(msg))
|
|
931
997
|
if (msg.error) {
|
|
932
998
|
errorData.push(msg.error);
|
|
999
|
+
delete msg.error;
|
|
933
1000
|
isHerdsmanRunning = false;
|
|
934
|
-
updateStartButton();
|
|
935
1001
|
} else {
|
|
936
|
-
coordinatorinfo = msg;
|
|
937
1002
|
isHerdsmanRunning = true;
|
|
938
|
-
updateStartButton()
|
|
939
1003
|
}
|
|
1004
|
+
coordinatorinfo = msg;
|
|
1005
|
+
updateStartButton()
|
|
940
1006
|
}
|
|
941
1007
|
});
|
|
942
1008
|
}
|
|
@@ -1051,6 +1117,7 @@ function HtmlFromInDebugMessages(messages, devID, filter) {
|
|
|
1051
1117
|
const Html = [];
|
|
1052
1118
|
const filterSet = new Set();
|
|
1053
1119
|
let isodd = true;
|
|
1120
|
+
const buttonList = [];
|
|
1054
1121
|
if (dbgMsghide.has('i_'+devID)) {
|
|
1055
1122
|
console.warn('in all filtered out')
|
|
1056
1123
|
Html.push(' ')
|
|
@@ -1065,8 +1132,11 @@ function HtmlFromInDebugMessages(messages, devID, filter) {
|
|
|
1065
1132
|
const redText = (item.errors && item.errors.length > 0 ? ' id="dbgred"' : '');
|
|
1066
1133
|
idx--;
|
|
1067
1134
|
const LHtml = [(`<tr id="${isodd ? 'dbgrowodd' : 'dbgroweven'}">`)];
|
|
1068
|
-
if (idx==0)
|
|
1069
|
-
|
|
1135
|
+
if (idx==0) {
|
|
1136
|
+
const msgbutton = `<a id="lx_${item.dataID}" class="btn-floating waves-effect waves-light blue tooltipped center-align hoverable translateT" title="Messages from ${new Date(item.dataID).toLocaleTimeString()}"><i class="material-icons large">speaker_notes</i></a>`
|
|
1137
|
+
buttonList.push(item.dataID)
|
|
1138
|
+
LHtml.push(`<td${rowspan}>${msgbutton}</td><td${rowspan}>${safestring(item.payload)}</td>`);
|
|
1139
|
+
}
|
|
1070
1140
|
LHtml.push(`<td></td><td${redText}>${safestring(state.payload)}</td><td${redText}>${state.id}</td><td${redText}>${state.value}</td><td${redText}>${fne(item)}</td></tr>`);
|
|
1071
1141
|
IHtml.unshift(...LHtml)
|
|
1072
1142
|
}
|
|
@@ -1079,7 +1149,7 @@ function HtmlFromInDebugMessages(messages, devID, filter) {
|
|
|
1079
1149
|
const ifbutton = `<a id="i_${devID}" class="btn-floating waves-effect waves-light blue tooltipped center-align hoverable translateT" title="Update debug messages"><i class="material-icons large">${dbgMsgfilter.has('i_'+devID) ? 'filter_list' : 'format_align_justify' }</i></a>`
|
|
1080
1150
|
const ofbutton = `<a id="hi_${devID}" class="btn-floating waves-effect waves-light blue tooltipped center-align hoverable translateT" title="Update debug messages"><i class="material-icons large">${dbgMsghide.has('i_'+devID) ? 'unfold_more' : 'unfold_less' }</i></a>`
|
|
1081
1151
|
const dataHide = dbgMsgfilter.has('hi_'+devID) ? 'Data hidden' : ' ';
|
|
1082
|
-
return
|
|
1152
|
+
return {html:`<thead id="dbgtable"><tr><td> </td><td>Incoming messages</td><td> </td><td> </td><td>${dataHide}</td><td>${ifbutton}</td><td>${ofbutton}</td></tr><tr><td>ID</td><td>Zigbee Payload</td><td> </td><td>State Payload</td><td>ID</td><td>value</td><td>Flags</td></tr></thead><tbody>${Html.join('')}</tbody>`, buttonList };
|
|
1083
1153
|
}
|
|
1084
1154
|
|
|
1085
1155
|
|
|
@@ -1087,6 +1157,7 @@ function HtmlFromOutDebugMessages(messages, devID, filter) {
|
|
|
1087
1157
|
const Html = [];
|
|
1088
1158
|
const filterSet = new Set();
|
|
1089
1159
|
let isodd=true;
|
|
1160
|
+
const buttonList = [];
|
|
1090
1161
|
if (dbgMsghide.has('o_'+devID)) {
|
|
1091
1162
|
console.warn('out all filtered out')
|
|
1092
1163
|
Html.push(' ')
|
|
@@ -1102,8 +1173,11 @@ function HtmlFromOutDebugMessages(messages, devID, filter) {
|
|
|
1102
1173
|
const redText = (item.errors && item.errors.length > 0 ? ' id="dbgred"' : '');
|
|
1103
1174
|
const LHtml = [(`<tr id="${isodd ? 'dbgrowodd' : 'dbgroweven'}">`)];
|
|
1104
1175
|
idx--;
|
|
1105
|
-
if (idx==0)
|
|
1106
|
-
|
|
1176
|
+
if (idx==0) {
|
|
1177
|
+
const msgbutton = `<a id="lx_${item.dataID}" class="btn-floating waves-effect waves-light blue tooltipped center-align hoverable translateT" title="Messages from ${new Date(item.dataID).toLocaleTimeString()}"><i class="material-icons large">speaker_notes</i></a>`
|
|
1178
|
+
LHtml.push(`<td${rowspan}>${msgbutton}</td><td${rowspan}>${safestring(item.payload)}</td>`);
|
|
1179
|
+
buttonList.push(item.dataID)
|
|
1180
|
+
}
|
|
1107
1181
|
LHtml.push(`<td${redText}>${state.ep ? state.ep : ''}</td><td${redText}>${state.id}</td><td${redText}>${safestring(state.value)}</td><td${redText}>${safestring(state.payload)}</td><td${redText}>${fne(item)}</td></tr>`);
|
|
1108
1182
|
IHtml.unshift(...LHtml);
|
|
1109
1183
|
|
|
@@ -1117,22 +1191,24 @@ function HtmlFromOutDebugMessages(messages, devID, filter) {
|
|
|
1117
1191
|
const ifbutton = `<a id="o_${devID}" class="btn-floating waves-effect waves-light blue tooltipped center-align hoverable translateT" title="Update debug messages"><i class="material-icons large">${dbgMsgfilter.has('o_'+devID) ? 'filter_list' : 'format_align_justify' }</i></a>`
|
|
1118
1192
|
const ofbutton = `<a id="ho_${devID}" class="btn-floating waves-effect waves-light blue tooltipped center-align hoverable translateT" title="Update debug messages"><i class="material-icons large">${dbgMsghide.has('o_'+devID) ? 'unfold_more' : 'unfold_less'}</i></a>`
|
|
1119
1193
|
const dataHide = dbgMsgfilter.has('ho_'+devID) ? 'Data hidden' : ' ';
|
|
1120
|
-
return
|
|
1194
|
+
return { html:`<thead id="dbgtable"><tr><td> </td><td>Outgoing messages</td><td> </td><td> </td><td>${dataHide}</td><td>${ifbutton}</td><td>${ofbutton}</td></tr><tr><td>ID</td><td>Zigbee Payload</td><td>EP</td><td>ID</td><td>value</td><td>State Payload</td><td>Flags</td></tr></thead><tbody>${Html.join('')}</tbody>`, buttonList};
|
|
1121
1195
|
}
|
|
1122
1196
|
|
|
1123
1197
|
|
|
1124
1198
|
function displayDebugMessages(msg) {
|
|
1125
1199
|
const buttonNames = [];
|
|
1200
|
+
const idButtons = [];
|
|
1126
1201
|
if (msg.byId) {
|
|
1127
1202
|
const dbgData = msg.byId;
|
|
1128
1203
|
const keys = Object.keys(dbgData);
|
|
1129
1204
|
const keylength = keys.length;
|
|
1130
1205
|
const Html = [];
|
|
1131
1206
|
const button = `<a id="e_all" class="btn-floating waves-effect waves-light green tooltipped center-align hoverable translateT" title="Update debug messages"><i class="material-icons large">sync_problem</i></a>`;
|
|
1132
|
-
const
|
|
1207
|
+
const dbutton = `<a id="d_all" class="btn-floating waves-effect waves-light red tooltipped center-align hoverable translateT" title="Update debug messages"><i class="material-icons icon-yellowlarge">delete_forever</i></a>`;
|
|
1208
|
+
const fbutton = `<a id="f_all" class="btn-floating waves-effect waves-light green tooltipped center-align hoverable translateT" title="Update debug messages"><i class="material-icons large">${dbgMsgfilter.size != 0 ? 'filter_list' : 'format_align_justify' }</i></a>`;
|
|
1133
1209
|
const hbutton = `<a id="h_all" class="btn-floating waves-effect waves-light blue tooltipped center-align hoverable translateT" title="Update debug messages"><i class="material-icons large">${dbgMsghide.size != 0 ? 'unfold_more' : 'unfold_less'}</i></a>`;
|
|
1134
1210
|
const logbutton = `<a id="l_all" class="btn-floating waves-effect waves-light ${debugInLog ? 'green' : 'red'} tooltipped center-align hoverable translateT" title="Log messages"><i class="material-icons large">${debugInLog ? 'speaker_notes' : 'speaker_notes_off'}</i></a>`;
|
|
1135
|
-
Html.push(`<li><table><thead id="dbgtable"><tr><td>${logbutton}</td><td colspan="3">Debug information by device</td><td>${fbutton}</td><td>${hbutton}</td><td>${button}</td></tr></thead><tbody>`);
|
|
1211
|
+
Html.push(`<li><table><thead id="dbgtable"><tr><td>${logbutton}</td><td colspan="3">Debug information by device</td><td>${fbutton}</td><td>${hbutton}</td><td>${button}</td><td>${dbutton}</td></tr></thead><tbody>`);
|
|
1136
1212
|
if (!keylength) {
|
|
1137
1213
|
Html.push('<tr><td></td><td>No debug data loaded - press reload to refresh</td><td></td><td> </td><td> </td><td> </td><td> </td><td> </td></tr></tbody></table></li>')
|
|
1138
1214
|
$('#dbg_data_list').html(Html.join(''));
|
|
@@ -1147,20 +1223,28 @@ function displayDebugMessages(msg) {
|
|
|
1147
1223
|
const modelUrl = (type_url === 'unknown') ? 'unknown' : `<a href="https://www.zigbee2mqtt.io/devices/${type_url}.html" target="_blank" rel="noopener noreferrer">${image}</a>`;
|
|
1148
1224
|
const devName = (dev && dev.common && dev.common.name) ? dev.common.name : 'unnamed';
|
|
1149
1225
|
const button = `<a id="e_${devID}" class="btn-floating waves-effect waves-light green tooltipped center-align hoverable translateT" title="Update debug messages"><i class="material-icons large">sync_problem</i></a>`
|
|
1226
|
+
const dbutton = `<a id="d_${devID}" class="btn-floating waves-effect waves-light red tooltipped center-align hoverable translateT" title="Update debug messages"><i class="material-icons icon-yellow large">delete_forever</i></a>`;
|
|
1150
1227
|
buttonNames.push(devID);
|
|
1151
|
-
Html.push(`<li><table><thead id="dbgtable"><tr><td colspan="4">${devName} (ID: ${devID} Model: ${dev && dev.common ? dev.common.name : 'unknown'})</td><td>${modelUrl}</td><td
|
|
1228
|
+
Html.push(`<li><table><thead id="dbgtable"><tr><td colspan="4">${devName} (ID: ${devID} Model: ${dev && dev.common ? dev.common.name : 'unknown'})</td><td>${modelUrl}</td><td>${button}</td><td>${dbutton}</td></tr></thead><tbody>`);
|
|
1152
1229
|
if (dbgData[devID].IN.length > 0) {
|
|
1153
|
-
|
|
1230
|
+
const indata = HtmlFromInDebugMessages(dbgData[devID].IN, devID, dbgMsgfilter.has('i_'+devID));
|
|
1231
|
+
Html.push(`${indata.html}`);
|
|
1232
|
+
idButtons.push(...indata.buttonList)
|
|
1154
1233
|
}
|
|
1155
1234
|
if (dbgData[devID].OUT.length > 0) {
|
|
1156
|
-
|
|
1235
|
+
const outdata = HtmlFromOutDebugMessages(dbgData[devID].OUT, devID, dbgMsgfilter.has('o_'+devID));
|
|
1236
|
+
Html.push(`${outdata.html}`);
|
|
1237
|
+
idButtons.push(...outdata.buttonList)
|
|
1157
1238
|
}
|
|
1158
1239
|
Html.push('</tbody></table></li>');
|
|
1159
1240
|
}
|
|
1160
1241
|
$('#dbg_data_list').html(Html.join(''));
|
|
1161
1242
|
}
|
|
1162
1243
|
$(`#e_all`).click(function () {
|
|
1163
|
-
getDebugMessages();
|
|
1244
|
+
getDebugMessages(false);
|
|
1245
|
+
});
|
|
1246
|
+
$(`#d_all`).click(function () {
|
|
1247
|
+
getDebugMessages(true, 'all');
|
|
1164
1248
|
});
|
|
1165
1249
|
$(`#l_all`).click(function () {
|
|
1166
1250
|
debugInLog = !debugInLog;
|
|
@@ -1192,7 +1276,10 @@ function displayDebugMessages(msg) {
|
|
|
1192
1276
|
});
|
|
1193
1277
|
for (const b of buttonNames) {
|
|
1194
1278
|
$(`#e_${b}`).click(function () {
|
|
1195
|
-
getDebugMessages();
|
|
1279
|
+
getDebugMessages(false);
|
|
1280
|
+
});
|
|
1281
|
+
$(`#d_${b}`).click(function () {
|
|
1282
|
+
getDebugMessages(true, b);
|
|
1196
1283
|
});
|
|
1197
1284
|
$(`#o_${b}`).click(function () {
|
|
1198
1285
|
if (dbgMsgfilter.has(`o_${b}`)) dbgMsgfilter.delete(`o_${b}`); else dbgMsgfilter.add(`o_${b}`);
|
|
@@ -1211,60 +1298,167 @@ function displayDebugMessages(msg) {
|
|
|
1211
1298
|
displayDebugMessages(debugMessages);
|
|
1212
1299
|
});
|
|
1213
1300
|
}
|
|
1301
|
+
for (const b of idButtons) {
|
|
1302
|
+
console.warn(`trying to add link to button ${b}`);
|
|
1303
|
+
$(`#lx_${b}`).click(function() { showMessageList(b)});
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
function showNamedMessages(messages, title, icon, timestamp) {
|
|
1309
|
+
// noinspection JSJQueryEfficiency
|
|
1310
|
+
let $dialogMessage = $('#dialog-message');
|
|
1311
|
+
if (!$dialogMessage.length) {
|
|
1312
|
+
$('body').append(
|
|
1313
|
+
'<div class="m"><div id="dialog-message" class="modal modal-fixed-footer">' +
|
|
1314
|
+
' <div class="modal-content">' +
|
|
1315
|
+
' <h6 class="dialog-title title"></h6>' +
|
|
1316
|
+
' <p><i class="large material-icons dialog-icon"></i><span class="dialog-text"></span></p>' +
|
|
1317
|
+
' </div>' +
|
|
1318
|
+
' <div class="modal-footer">' +
|
|
1319
|
+
' <a class="modal-action modal-close waves-effect waves-green btn-flat translate">Ok</a>' +
|
|
1320
|
+
' </div>' +
|
|
1321
|
+
'</div></div>');
|
|
1322
|
+
$dialogMessage = $('#dialog-message');
|
|
1323
|
+
}
|
|
1324
|
+
if (icon) {
|
|
1325
|
+
$dialogMessage.find('.dialog-icon')
|
|
1326
|
+
.show()
|
|
1327
|
+
.html(icon);
|
|
1328
|
+
} else {
|
|
1329
|
+
$dialogMessage.find('.dialog-icon').hide();
|
|
1330
|
+
}
|
|
1331
|
+
if (title) {
|
|
1332
|
+
$dialogMessage.find('.dialog-title').html(title).show();
|
|
1333
|
+
} else {
|
|
1334
|
+
$dialogMessage.find('.dialog-title').hide();
|
|
1335
|
+
}
|
|
1336
|
+
const lihtml = ['```<br><ul>'];
|
|
1337
|
+
for (const key of Object.keys(messages)) {
|
|
1338
|
+
lihtml.push(`<li>${key}: ${messages[key]}</li>`)
|
|
1339
|
+
}
|
|
1340
|
+
lihtml.push('</ul><br>```')
|
|
1341
|
+
$dialogMessage.find('.dialog-text').html(lihtml);
|
|
1342
|
+
$dialogMessage.modal().modal('open');
|
|
1343
|
+
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
function showMessageList(msgId) {
|
|
1347
|
+
console.warn(`trying to show messages for ${msgId}`);
|
|
1348
|
+
console.warn(JSON.stringify(debugMessages));
|
|
1349
|
+
for (const devId of Object.keys(debugMessages.byId)) {
|
|
1350
|
+
for (const id of debugMessages.byId[devId].IN) {
|
|
1351
|
+
if (id.dataID == msgId) {
|
|
1352
|
+
console.warn(`showing messages for ${id.type} ${devId}`);
|
|
1353
|
+
showNamedMessages(id.messages, `Messages from ${new Date(msgId).toLocaleTimeString()} for device ${devId}`);
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
for (const id of debugMessages.byId[devId].OUT) {
|
|
1358
|
+
if (id.dataID == msgId) {
|
|
1359
|
+
console.warn(`showing messages for ${msgId}`);
|
|
1360
|
+
showNamedMessages(id.messages, `Messages from ${new Date(msgId).toLocaleTimeString()} for device ${devId}`);
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1214
1364
|
}
|
|
1365
|
+
console.warn(`nothing to show`);
|
|
1366
|
+
|
|
1367
|
+
|
|
1215
1368
|
}
|
|
1216
1369
|
|
|
1217
|
-
function getDebugMessages() {
|
|
1218
|
-
sendTo(namespace, 'getDebugMessages', { inlog: debugInLog }, function(msg) {
|
|
1370
|
+
function getDebugMessages(deleteBeforeRead, deleteSelected) {
|
|
1371
|
+
sendTo(namespace, 'getDebugMessages', { inlog: debugInLog, del:deleteBeforeRead ? deleteSelected : '' }, function(msg) {
|
|
1219
1372
|
debugMessages = msg;
|
|
1220
1373
|
if (msg) displayDebugMessages(debugMessages)
|
|
1221
1374
|
})
|
|
1222
1375
|
}
|
|
1223
1376
|
|
|
1224
|
-
|
|
1377
|
+
const lockout = {
|
|
1378
|
+
timeoutid:undefined,
|
|
1379
|
+
isActive:false,
|
|
1380
|
+
};
|
|
1225
1381
|
function getDevices() {
|
|
1226
|
-
|
|
1227
|
-
sendTo(namespace, 'getDevices', {}, function (msg) {
|
|
1228
|
-
if (msg) {
|
|
1229
|
-
devices = msg.devices ? msg.devices : [];
|
|
1230
|
-
// check if stashed error messages are sent alongside
|
|
1231
|
-
if (msg.clean)
|
|
1232
|
-
$('#state_cleanup_btn').removeClass('hide');
|
|
1233
|
-
else
|
|
1234
|
-
$('#state_cleanup_btn').addClass('hide');
|
|
1235
|
-
if (msg.errors && msg.errors.length > 0) {
|
|
1236
|
-
$('#show_errors_btn').removeClass('hide');
|
|
1237
|
-
errorData = msg.errors;
|
|
1238
|
-
}
|
|
1239
|
-
else {
|
|
1240
|
-
$('#show_errors_btn').addClass('hide');
|
|
1241
|
-
}
|
|
1382
|
+
console.warn('getDevices called')
|
|
1242
1383
|
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
updateStartButton();
|
|
1258
|
-
} else {
|
|
1259
|
-
isHerdsmanRunning = true;
|
|
1260
|
-
updateStartButton();
|
|
1261
|
-
showDevices();
|
|
1262
|
-
getDebugMessages();
|
|
1263
|
-
getExclude();
|
|
1264
|
-
getBinding();
|
|
1384
|
+
function sendForData() {
|
|
1385
|
+
sendTo(namespace, 'getCoordinatorInfo', {}, function (msg) {
|
|
1386
|
+
console.warn(`getCoordinatorInfo returned ${JSON.stringify(msg)}`)
|
|
1387
|
+
if (msg) {
|
|
1388
|
+
console.warn(JSON.stringify(msg))
|
|
1389
|
+
if (msg.error) {
|
|
1390
|
+
errorData.push(msg.error);
|
|
1391
|
+
delete msg.error;
|
|
1392
|
+
isHerdsmanRunning = false;
|
|
1393
|
+
} else {
|
|
1394
|
+
isHerdsmanRunning = true;
|
|
1395
|
+
}
|
|
1396
|
+
coordinatorinfo = msg;
|
|
1397
|
+
updateStartButton()
|
|
1265
1398
|
}
|
|
1266
|
-
|
|
1267
|
-
|
|
1399
|
+
sendTo(namespace, 'getDevices', {}, function (msg) {
|
|
1400
|
+
if (msg) {
|
|
1401
|
+
devices = msg.devices ? msg.devices : [];
|
|
1402
|
+
// check if stashed error messages are sent alongside
|
|
1403
|
+
if (msg.clean)
|
|
1404
|
+
$('#state_cleanup_btn').removeClass('hide');
|
|
1405
|
+
else
|
|
1406
|
+
$('#state_cleanup_btn').addClass('hide');
|
|
1407
|
+
if (msg.errors && msg.errors.length > 0) {
|
|
1408
|
+
$('#show_errors_btn').removeClass('hide');
|
|
1409
|
+
errorData = msg.errors;
|
|
1410
|
+
}
|
|
1411
|
+
else {
|
|
1412
|
+
$('#show_errors_btn').addClass('hide');
|
|
1413
|
+
}
|
|
1414
|
+
let newDebugMessages = false;
|
|
1415
|
+
|
|
1416
|
+
//check if debug messages are sent alongside
|
|
1417
|
+
if (msg && typeof (msg.debugDevices == 'array')) {
|
|
1418
|
+
debugDevices = msg.debugDevices;
|
|
1419
|
+
console.warn('debug devices is sent')
|
|
1420
|
+
}
|
|
1421
|
+
else
|
|
1422
|
+
debugDevices = [];
|
|
1423
|
+
if (debugMessages.byId) {
|
|
1424
|
+
newDebugMessages = true;
|
|
1425
|
+
console.warn('having debug messages');
|
|
1426
|
+
debugMessages.byId = msg;
|
|
1427
|
+
if (msg) displayDebugMessages(debugMessages)
|
|
1428
|
+
}
|
|
1429
|
+
lockout.isActive = false;
|
|
1430
|
+
if (msg.error) {
|
|
1431
|
+
errorData.push(msg.error);
|
|
1432
|
+
isHerdsmanRunning = false;
|
|
1433
|
+
updateStartButton();
|
|
1434
|
+
showDevices();
|
|
1435
|
+
} else {
|
|
1436
|
+
isHerdsmanRunning = true;
|
|
1437
|
+
updateStartButton();
|
|
1438
|
+
showDevices();
|
|
1439
|
+
if (!newDebugMessages) {
|
|
1440
|
+
console.warn('getting debug messages');
|
|
1441
|
+
getDebugMessages();
|
|
1442
|
+
}
|
|
1443
|
+
//getExclude();
|
|
1444
|
+
getBinding();
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
});
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
if (lockout.timeoutid) {
|
|
1452
|
+
clearTimeout(lockout.timeoutid);
|
|
1453
|
+
console.warn('clearing getDevices timeout')
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
setTimeout(() => {
|
|
1457
|
+
lockout.isActive = true;
|
|
1458
|
+
lockout.timeoutid = undefined;
|
|
1459
|
+
sendForData();
|
|
1460
|
+
}, 100);
|
|
1461
|
+
|
|
1268
1462
|
}
|
|
1269
1463
|
|
|
1270
1464
|
function getNamedColors() {
|
|
@@ -1286,26 +1480,29 @@ function getDeviceCard(devId) {
|
|
|
1286
1480
|
return $('#devices').find(`div[id='${namespace}.${devId}']`);
|
|
1287
1481
|
}
|
|
1288
1482
|
|
|
1289
|
-
function getMap() {
|
|
1483
|
+
function getMap(rebuild) {
|
|
1290
1484
|
$('#refresh').addClass('disabled');
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
if (msg
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1485
|
+
if (isHerdsmanRunning) {
|
|
1486
|
+
sendTo(namespace, 'getMap', { forcebuild:rebuild}, function (msg) {
|
|
1487
|
+
$('#refresh').removeClass('disabled');
|
|
1488
|
+
if (msg) {
|
|
1489
|
+
if (msg.error) {
|
|
1490
|
+
errorData.push(msg.error);
|
|
1491
|
+
isHerdsmanRunning = false;
|
|
1492
|
+
updateStartButton();
|
|
1493
|
+
} else {
|
|
1494
|
+
isHerdsmanRunning = true;
|
|
1495
|
+
updateStartButton();
|
|
1496
|
+
if (msg.errors.length > 0 && $('#errorCollectionOn').is(':checked')) {
|
|
1497
|
+
showMessage(msg.errors.join('<p>'), 'Map generation messages');
|
|
1498
|
+
}
|
|
1499
|
+
map = msg;
|
|
1500
|
+
showNetworkMap(devices, map);
|
|
1303
1501
|
}
|
|
1304
|
-
map = msg;
|
|
1305
|
-
showNetworkMap(devices, map);
|
|
1306
1502
|
}
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
else showMessage('Unable to generate map, the zigbee subsystem is inactive', 'Map generation error');
|
|
1309
1506
|
}
|
|
1310
1507
|
|
|
1311
1508
|
function getRandomExtPanID()
|
|
@@ -1328,6 +1525,7 @@ function getRandomChannel()
|
|
|
1328
1525
|
// the function loadSettings has to exist ...
|
|
1329
1526
|
|
|
1330
1527
|
function load(settings, onChange) {
|
|
1528
|
+
console.warn(JSON.stringify(settings));
|
|
1331
1529
|
if (settings.extPanID === undefined || settings.extPanID == '') {
|
|
1332
1530
|
settings.channel = getRandomChannel();
|
|
1333
1531
|
}
|
|
@@ -1355,6 +1553,7 @@ function load(settings, onChange) {
|
|
|
1355
1553
|
settings.baudRate = 115200;
|
|
1356
1554
|
}
|
|
1357
1555
|
if (settings.autostart === undefined) settings.autostart = false;
|
|
1556
|
+
if (typeof settings.pingCluster != 'string') settings.pingCluster = settings.disablePing ? 'off' : 'default';
|
|
1358
1557
|
|
|
1359
1558
|
// example: select elements with id=key and class=value and insert value
|
|
1360
1559
|
for (const key in settings) {
|
|
@@ -1428,6 +1627,9 @@ function load(settings, onChange) {
|
|
|
1428
1627
|
$('#show_errors_btn').click(function () {
|
|
1429
1628
|
showMessage(errorData.join('<br>'), 'Stashed error messages');
|
|
1430
1629
|
});
|
|
1630
|
+
$('#download_icons_btn').click(function () {
|
|
1631
|
+
showMessage(downloadIcons());
|
|
1632
|
+
});
|
|
1431
1633
|
$('#fw_check_btn').click(function () {
|
|
1432
1634
|
checkFwUpdate();
|
|
1433
1635
|
});
|
|
@@ -1439,11 +1641,16 @@ function load(settings, onChange) {
|
|
|
1439
1641
|
if (!$('#pairing').hasClass('pulse')) {
|
|
1440
1642
|
letsPairing();
|
|
1441
1643
|
}
|
|
1644
|
+
console.warn('lets pairing');
|
|
1442
1645
|
showPairingProcess();
|
|
1443
1646
|
});
|
|
1444
1647
|
|
|
1445
1648
|
$('#refresh').click(function () {
|
|
1446
|
-
getMap();
|
|
1649
|
+
getMap(false);
|
|
1650
|
+
});
|
|
1651
|
+
$('#regenerate').click(function () {
|
|
1652
|
+
getMap(true);
|
|
1653
|
+
$('#modalviewconfig').modal('close');
|
|
1447
1654
|
});
|
|
1448
1655
|
|
|
1449
1656
|
$('#reset-btn').click(function () {
|
|
@@ -1454,6 +1661,12 @@ function load(settings, onChange) {
|
|
|
1454
1661
|
deleteNvBackupConfirmation();
|
|
1455
1662
|
});
|
|
1456
1663
|
|
|
1664
|
+
$('#ErrorNotificationBtn').click(function () {
|
|
1665
|
+
if (!isHerdsmanRunning) {
|
|
1666
|
+
doTestStart(!isHerdsmanRunning, true);
|
|
1667
|
+
}
|
|
1668
|
+
})
|
|
1669
|
+
|
|
1457
1670
|
$('#viewconfig').click(function () {
|
|
1458
1671
|
showViewConfig();
|
|
1459
1672
|
});
|
|
@@ -1555,7 +1768,7 @@ function showMessages() {
|
|
|
1555
1768
|
}
|
|
1556
1769
|
|
|
1557
1770
|
function showPairingProcess() {
|
|
1558
|
-
$('#modalpairing').modal({
|
|
1771
|
+
if (isHerdsmanRunning) $('#modalpairing').modal({
|
|
1559
1772
|
startingTop: '4%',
|
|
1560
1773
|
endingTop: '10%',
|
|
1561
1774
|
dismissible: false
|
|
@@ -1565,10 +1778,10 @@ function showPairingProcess() {
|
|
|
1565
1778
|
Materialize.updateTextFields();
|
|
1566
1779
|
}
|
|
1567
1780
|
|
|
1568
|
-
function doTestStart(start) {
|
|
1781
|
+
function doTestStart(start, interactive) {
|
|
1569
1782
|
updateStartButton(true);
|
|
1570
1783
|
if (start) {
|
|
1571
|
-
const ovr = { extPanID:$('#extPanID.value').val(),
|
|
1784
|
+
const ovr = interactive ? {} : { extPanID:$('#extPanID.value').val(),
|
|
1572
1785
|
panID: $('#PanID.value').val(),
|
|
1573
1786
|
channel: $('#channel.value').val(),
|
|
1574
1787
|
port: $('#port.value').val(),
|
|
@@ -1579,12 +1792,18 @@ function doTestStart(start) {
|
|
|
1579
1792
|
};
|
|
1580
1793
|
// $('#testStartStart').addClass('disabled');
|
|
1581
1794
|
messages = [];
|
|
1795
|
+
if (interactive) showWaitingDialog('Trying to start the zigbee subsystem manually', 120);
|
|
1582
1796
|
sendTo(namespace, 'testConnect', { start:true, zigbeeOptions:ovr }, function(msg) {
|
|
1583
1797
|
if (msg) {
|
|
1798
|
+
closeWaitingDialog();
|
|
1799
|
+
isHerdsmanRunning = msg.status;
|
|
1800
|
+
updateStartButton(false);
|
|
1584
1801
|
if (msg.status)
|
|
1585
1802
|
$('#testStartStop').removeClass('disabled');
|
|
1586
|
-
else
|
|
1587
|
-
$
|
|
1803
|
+
else {
|
|
1804
|
+
//showMessage(`The zigbee subsystem is not running. Please ensure that the configuration is correct. ${msg.error ? 'Error on start-Attempt ' + msg.error.message : ''}`);
|
|
1805
|
+
$('#testStartStop').removeClass('disabled');
|
|
1806
|
+
}
|
|
1588
1807
|
}
|
|
1589
1808
|
})
|
|
1590
1809
|
}
|
|
@@ -1628,14 +1847,15 @@ function getDevId(adapterDevId) {
|
|
|
1628
1847
|
|
|
1629
1848
|
|
|
1630
1849
|
function updateStartButton(block) {
|
|
1850
|
+
console.warn(`update start button with${isHerdsmanRunning ? ' Herdsman' : 'out Herdsman'}`);
|
|
1631
1851
|
if (block) {
|
|
1632
1852
|
$('#show_test_run').addClass('disabled');
|
|
1633
1853
|
$('#reset-btn').addClass('disabled');
|
|
1634
1854
|
$('#deleteNVRam-btn').addClass('disabled');
|
|
1635
1855
|
$('#ErrorNotificationBtn').removeClass('hide')
|
|
1636
1856
|
$('#ErrorNotificationBtn').removeClass('blinking')
|
|
1637
|
-
$('#
|
|
1638
|
-
$('#
|
|
1857
|
+
$('#ErrorNotificationBtn').removeClass('red')
|
|
1858
|
+
$('#ErrorNotificationBtn').addClass('orange')
|
|
1639
1859
|
return;
|
|
1640
1860
|
}
|
|
1641
1861
|
if (isHerdsmanRunning)
|
|
@@ -1645,15 +1865,25 @@ function updateStartButton(block) {
|
|
|
1645
1865
|
$('#show_test_run').removeClass('disabled');
|
|
1646
1866
|
$('#deleteNVRam-btn').removeClass('disabled');
|
|
1647
1867
|
$('#reset-btn').removeClass('disabled');
|
|
1868
|
+
$('#fw_check_btn').removeClass('hide');
|
|
1869
|
+
$('#add_grp_btn').removeClass('hide');
|
|
1870
|
+
$('#touchlink_btn').removeClass('hide');
|
|
1871
|
+
$('#code_pairing').removeClass('hide');
|
|
1872
|
+
//$('#pairing').removeClass('hide');
|
|
1648
1873
|
}
|
|
1649
1874
|
else {
|
|
1650
|
-
$('#
|
|
1651
|
-
$('#
|
|
1875
|
+
$('#ErrorNotificationBtn').addClass('red')
|
|
1876
|
+
$('#ErrorNotificationBtn').removeClass('orange')
|
|
1652
1877
|
$('#ErrorNotificationBtn').removeClass('hide')
|
|
1653
1878
|
$('#ErrorNotificationBtn').addClass('blinking');
|
|
1654
1879
|
$('#show_test_run').removeClass('disabled');
|
|
1655
1880
|
$('#deleteNVRam-btn').removeClass('disabled');
|
|
1656
1881
|
$('#reset-btn').addClass('disabled');
|
|
1882
|
+
$('#fw_check_btn').addClass('hide');
|
|
1883
|
+
$('#add_grp_btn').addClass('hide');
|
|
1884
|
+
$('#touchlink_btn').addClass('hide');
|
|
1885
|
+
$('#code_pairing').addClass('hide');
|
|
1886
|
+
//$('#pairing').addClass('hide');
|
|
1657
1887
|
}
|
|
1658
1888
|
}
|
|
1659
1889
|
// subscribe to changes
|
|
@@ -1797,7 +2027,7 @@ function showNetworkMap(devices, map) {
|
|
|
1797
2027
|
borderWidth: 1,
|
|
1798
2028
|
borderWidthSelected: 4,
|
|
1799
2029
|
};
|
|
1800
|
-
if (dev.info && dev.info.device.
|
|
2030
|
+
if (dev.info && dev.info.device.type == 'Coordinator') {
|
|
1801
2031
|
// node.shape = 'star';
|
|
1802
2032
|
node.image = 'zigbee.png';
|
|
1803
2033
|
node.label = 'Coordinator';
|
|
@@ -1957,7 +2187,7 @@ function showNetworkMap(devices, map) {
|
|
|
1957
2187
|
|
|
1958
2188
|
if (node) {
|
|
1959
2189
|
node.font = {color: '#ff0000'};
|
|
1960
|
-
if (dev.info && dev.info.device.
|
|
2190
|
+
if (dev.info && dev.info.device && dev.info.device.type == 'Coordinator') {
|
|
1961
2191
|
node.font = {color: '#00ff00'};
|
|
1962
2192
|
}
|
|
1963
2193
|
nodesArray.push(node);
|
|
@@ -2122,35 +2352,37 @@ function loadDeveloperTab() {
|
|
|
2122
2352
|
updateSelect('#dev', devices,
|
|
2123
2353
|
function (key, device) {
|
|
2124
2354
|
if (device.hasOwnProperty('info')) {
|
|
2125
|
-
if (device.info.device.
|
|
2355
|
+
if (device.info.device && device.info.device.type === 'Coordinator') {
|
|
2126
2356
|
return null;
|
|
2127
2357
|
}
|
|
2128
|
-
|
|
2358
|
+
if (device.common.type === 'group') return null;
|
|
2359
|
+
return `${device.common.name} (${device.info.device.ieee})`;
|
|
2129
2360
|
} else { // fallback if device in list but not paired
|
|
2130
2361
|
return device.common.name + ' ' + device.native.id;
|
|
2131
2362
|
}
|
|
2132
2363
|
},
|
|
2133
2364
|
function (key, device) {
|
|
2134
|
-
return device.
|
|
2135
|
-
});
|
|
2136
|
-
// add groups to device selector
|
|
2137
|
-
const groupList = [];
|
|
2138
|
-
for (const key in groups) {
|
|
2139
|
-
groupList.push({
|
|
2140
|
-
_id: namespace + '.' + key.toString(16).padStart(16, '0'),
|
|
2141
|
-
groupId: key,
|
|
2142
|
-
groupName: groups[key]
|
|
2365
|
+
return device.native.id;
|
|
2143
2366
|
});
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2367
|
+
/*
|
|
2368
|
+
const groupList = [];
|
|
2369
|
+
for (const key in groups) {
|
|
2370
|
+
groupList.push({
|
|
2371
|
+
id: namespace + '.' + key.toString(16).padStart(16, '0'),
|
|
2372
|
+
groupId: key,
|
|
2373
|
+
groupName: groups[key]
|
|
2374
|
+
});
|
|
2375
|
+
}
|
|
2376
|
+
updateSelect('#dev', groupList,
|
|
2377
|
+
function (key, device) {
|
|
2378
|
+
return 'Group ' + device.groupId + ': ' + device.groupName;
|
|
2379
|
+
},
|
|
2380
|
+
function (key, device) {
|
|
2381
|
+
return device.id;
|
|
2382
|
+
}, true);
|
|
2152
2383
|
|
|
2153
|
-
|
|
2384
|
+
// fill cid, cmd, type selector
|
|
2385
|
+
*/
|
|
2154
2386
|
populateSelector('#cid', 'cidList');
|
|
2155
2387
|
populateSelector('#cmd', 'cmdListFoundation', this.value);
|
|
2156
2388
|
populateSelector('#type', 'typeList', this.value);
|
|
@@ -2231,10 +2463,11 @@ function loadDeveloperTab() {
|
|
|
2231
2463
|
}
|
|
2232
2464
|
|
|
2233
2465
|
const device = devices.find(obj => {
|
|
2234
|
-
return
|
|
2466
|
+
return this.value ===obj.native.id;
|
|
2235
2467
|
});
|
|
2468
|
+
console.warn(`dev selector: ${this.selectedIndex} ${this.value} ->${JSON.stringify(device)}`)
|
|
2236
2469
|
|
|
2237
|
-
const epList = device ? device.info.
|
|
2470
|
+
const epList = device ? device.info.endpoints : null;
|
|
2238
2471
|
updateSelect('#ep', epList,
|
|
2239
2472
|
function (key, ep) {
|
|
2240
2473
|
return ep.ID;
|
|
@@ -2670,14 +2903,14 @@ function prepareBindingDialog(bindObj) {
|
|
|
2670
2903
|
return 'Select source device';
|
|
2671
2904
|
}
|
|
2672
2905
|
if (device.hasOwnProperty('info')) {
|
|
2673
|
-
if (device.info.device.
|
|
2906
|
+
if (device.info.device && device.info.device.type === 'Coordinator') {
|
|
2674
2907
|
return null;
|
|
2675
2908
|
}
|
|
2676
2909
|
// check for output clusters
|
|
2677
2910
|
let allow = false;
|
|
2678
2911
|
for (const cluster of allowClusters) {
|
|
2679
|
-
for (const ep of device.info.endpoints) {
|
|
2680
|
-
if (ep.
|
|
2912
|
+
if (device.info.endpoints) for (const ep of device.info.endpoints) {
|
|
2913
|
+
if (ep.output_clusters.includes(cluster)) {
|
|
2681
2914
|
allow = true;
|
|
2682
2915
|
break;
|
|
2683
2916
|
}
|
|
@@ -2721,14 +2954,14 @@ function prepareBindingDialog(bindObj) {
|
|
|
2721
2954
|
return 'Select target device';
|
|
2722
2955
|
}
|
|
2723
2956
|
if (device.hasOwnProperty('info')) {
|
|
2724
|
-
if (device.info.device.
|
|
2957
|
+
if (device.info.device && device.info.device.type === 'Coordinator') {
|
|
2725
2958
|
return null;
|
|
2726
2959
|
}
|
|
2727
2960
|
// check for input clusters
|
|
2728
2961
|
let allow = false;
|
|
2729
2962
|
for (const cluster of allowClusters) {
|
|
2730
|
-
for (const ep of device.info.endpoints) {
|
|
2731
|
-
if (ep.
|
|
2963
|
+
if (device.info.endpoints) for (const ep of device.info.endpoints) {
|
|
2964
|
+
if (ep.input_clusters.includes(cluster)) {
|
|
2732
2965
|
allow = true;
|
|
2733
2966
|
break;
|
|
2734
2967
|
}
|
|
@@ -2772,7 +3005,7 @@ function prepareBindingDialog(bindObj) {
|
|
|
2772
3005
|
|
|
2773
3006
|
const epList = device ? device.info.endpoints : [];
|
|
2774
3007
|
const sClusterList = epList.map((ep) => {
|
|
2775
|
-
const clusters = ep.
|
|
3008
|
+
const clusters = ep.output_clusters.map((cl) => {
|
|
2776
3009
|
return allowClusters.includes(cl) ? {ID: ep.ID + '_' + cl, name: allowClustersName[cl]} : null;
|
|
2777
3010
|
}).filter((i) => {
|
|
2778
3011
|
return i != null;
|
|
@@ -2798,7 +3031,7 @@ function prepareBindingDialog(bindObj) {
|
|
|
2798
3031
|
|
|
2799
3032
|
const epList = device ? device.info.endpoints : [];
|
|
2800
3033
|
const tClusterList = epList.map((ep) => {
|
|
2801
|
-
const clusters = ep.
|
|
3034
|
+
const clusters = ep.input_clusters.map((cl) => {
|
|
2802
3035
|
return (allowClusters.includes(cl) && (!sourceCl || sourceCl == cl)) ? {
|
|
2803
3036
|
ID: ep.ID + '_' + cl,
|
|
2804
3037
|
name: allowClustersName[cl]
|
|
@@ -3031,12 +3264,13 @@ function genDevInfo(device) {
|
|
|
3031
3264
|
//console.log(device);
|
|
3032
3265
|
const dev = (device && device.info) ? device.info.device : undefined;
|
|
3033
3266
|
const mapped = (device && device.info) ? device.info.mapped : undefined;
|
|
3267
|
+
const endpoints = (device && device.info) ? device.info.endpoints : [];
|
|
3034
3268
|
if (!dev) return `<div class="truncate">No info</div>`;
|
|
3035
3269
|
const genRow = function (name, value, refresh) {
|
|
3036
3270
|
if (value === undefined) {
|
|
3037
3271
|
return '';
|
|
3038
3272
|
} else {
|
|
3039
|
-
return `<li><span class="label">${name}:</span><span>${value}</span></li>`;
|
|
3273
|
+
return `<li><span class="label">${name.replace('_',' ')}:</span><span>${value}</span></li>`;
|
|
3040
3274
|
}
|
|
3041
3275
|
};
|
|
3042
3276
|
const genRowValues = function (name, value) {
|
|
@@ -3044,66 +3278,68 @@ function genDevInfo(device) {
|
|
|
3044
3278
|
return '';
|
|
3045
3279
|
} else {
|
|
3046
3280
|
let label = `${name}:`;
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3281
|
+
try {
|
|
3282
|
+
return value.map((val) => {
|
|
3283
|
+
const row = `<li><span class="label">${label}</span><span>${val}</span></li>`;
|
|
3284
|
+
label = '';
|
|
3285
|
+
return row;
|
|
3286
|
+
}).join('');
|
|
3287
|
+
}
|
|
3288
|
+
catch {
|
|
3289
|
+
return `<li><span class="label">${label}</span><span>${JSON.stringify(value)}</span></li>`
|
|
3290
|
+
}
|
|
3052
3291
|
}
|
|
3053
3292
|
};
|
|
3054
3293
|
const modelUrl = (!mapped) ? '' : `<a href="https://www.zigbee2mqtt.io/devices/${sanitizeModelParameter(mapped.model)}.html" target="_blank" rel="noopener noreferrer">${mapped.model}</a>`;
|
|
3055
|
-
const mappedInfo =
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3294
|
+
const mappedInfo = [];
|
|
3295
|
+
if (mapped) {
|
|
3296
|
+
mappedInfo.push(
|
|
3297
|
+
`<div style="font-size: 0.9em">
|
|
3298
|
+
<ul>`);
|
|
3299
|
+
for (const item in mapped) {
|
|
3300
|
+
if (item == 'model')
|
|
3301
|
+
mappedInfo.push(genRow(item,modelUrl));
|
|
3302
|
+
else
|
|
3303
|
+
mappedInfo.push(genRow(item,mapped[item]));
|
|
3304
|
+
}
|
|
3305
|
+
mappedInfo.push(
|
|
3306
|
+
` </ul>
|
|
3307
|
+
</div>`);
|
|
3308
|
+
}
|
|
3063
3309
|
let epInfo = '';
|
|
3064
|
-
for (const epind in
|
|
3065
|
-
const ep =
|
|
3310
|
+
for (const epind in endpoints) {
|
|
3311
|
+
const ep = endpoints[epind];
|
|
3312
|
+
console.warn(JSON.stringify(ep));
|
|
3066
3313
|
epInfo +=
|
|
3067
3314
|
`<div style="font-size: 0.9em" class="truncate">
|
|
3068
3315
|
<ul>
|
|
3069
3316
|
${genRow('endpoint', ep.ID)}
|
|
3070
|
-
${genRow('profile', ep.
|
|
3071
|
-
${genRowValues('input clusters', ep.
|
|
3072
|
-
${genRowValues('output clusters', ep.
|
|
3317
|
+
${genRow('profile', ep.profile)}
|
|
3318
|
+
${genRowValues('input clusters', ep.input_clusters ? ep.input_clusters.map(findClName) : 'none')}
|
|
3319
|
+
${genRowValues('output clusters', ep.output_clusters ? ep.output_clusters.map(findClName): 'none')}
|
|
3073
3320
|
</ul>
|
|
3074
3321
|
</div>`;
|
|
3075
3322
|
}
|
|
3076
3323
|
const imgSrc = device.icon || device.common.icon;
|
|
3077
3324
|
const imgInfo = (imgSrc) ? `<img src=${imgSrc} width='150px' onerror="this.onerror=null;this.src='img/unavailable.png';"><div class="divider"></div>` : '';
|
|
3078
|
-
const info =
|
|
3325
|
+
const info =[
|
|
3079
3326
|
`<div class="col s12 m6 l6 xl6">
|
|
3080
3327
|
${imgInfo}
|
|
3081
|
-
${mappedInfo}
|
|
3328
|
+
${mappedInfo.join('')}
|
|
3082
3329
|
<div class="divider"></div>
|
|
3083
3330
|
<div style="font-size: 0.9em" class="truncate">
|
|
3084
|
-
<ul
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
${genRow('manuf id', dev._manufacturerID)}
|
|
3090
|
-
${genRow('manufacturer', dev._manufacturerName)}
|
|
3091
|
-
${genRow('power', dev._powerSource)}
|
|
3092
|
-
${genRow('app version', dev._applicationVersion)}
|
|
3093
|
-
${genRow('hard version', dev._hardwareVersion)}
|
|
3094
|
-
${genRow('zcl version', dev._zclVersion)}
|
|
3095
|
-
${genRow('stack version', dev._stackVersion)}
|
|
3096
|
-
${genRow('date code', dev._dateCode)}
|
|
3097
|
-
${genRow('build', dev._softwareBuildID)}
|
|
3098
|
-
${genRow('interviewed', dev._interviewCompleted)}
|
|
3099
|
-
${genRow('configured', (device.isConfigured), true)}
|
|
3331
|
+
<ul>`];
|
|
3332
|
+
for (const item in dev) {
|
|
3333
|
+
info.push(genRow(item, dev[item]));
|
|
3334
|
+
}
|
|
3335
|
+
info.push(` ${genRow('configured', (device.isConfigured), true)}
|
|
3100
3336
|
</ul>
|
|
3101
3337
|
</div>
|
|
3102
3338
|
</div>
|
|
3103
3339
|
<div class="col s12 m6 l6 xl6">
|
|
3104
3340
|
${epInfo}
|
|
3105
|
-
</div
|
|
3106
|
-
return info;
|
|
3341
|
+
</div>`);
|
|
3342
|
+
return info.join('');
|
|
3107
3343
|
}
|
|
3108
3344
|
|
|
3109
3345
|
function showDevInfo(id) {
|
|
@@ -3211,7 +3447,7 @@ function prepareExcludeDialog(excludeObj) {
|
|
|
3211
3447
|
return 'Select model';
|
|
3212
3448
|
}
|
|
3213
3449
|
if (device.hasOwnProperty('info')) {
|
|
3214
|
-
if (device.info.device.
|
|
3450
|
+
if (device.info.device && device.info.device.type == 'Coordinator') {
|
|
3215
3451
|
return null;
|
|
3216
3452
|
}
|
|
3217
3453
|
return device.common.type;
|
|
@@ -3442,17 +3678,18 @@ function getDashCard(dev, groupImage, groupstatus) {
|
|
|
3442
3678
|
rooms = [],
|
|
3443
3679
|
lang = systemLang || 'en';
|
|
3444
3680
|
const paired = (dev.paired) ? '' : '<i class="material-icons right">leak_remove</i>';
|
|
3681
|
+
const permitJoinBtn = dev.battery || dev.common.type == 'group' ? '' : `<div class="col tool"><button name="joinCard" class="waves-effect btn-small btn-flat right hoverable green"><i class="material-icons icon-green">leak_add</i></button></div>`;
|
|
3682
|
+
const device_queryBtn = dev.battery || dev.common.type == 'group' ? '' : `<div class="col tool"><button name="deviceQuery" class="waves-effect btn-small btn-flat right hoverable green"><i class="material-icons icon-green">play_for_work</i></button></div>`;
|
|
3445
3683
|
const rid = id.split('.').join('_');
|
|
3446
3684
|
const modelUrl = (!type) ? '' : `<a href="https://www.zigbee2mqtt.io/devices/${type}.html" target="_blank" rel="noopener noreferrer">${type}</a>`;
|
|
3447
3685
|
const image = `<img src="${img_src}" width="64px" onerror="this.onerror=null;this.src='img/unavailable.png';">`,
|
|
3448
|
-
nwk = (dev.info && dev.info.device) ? dev.info.device.
|
|
3686
|
+
nwk = (dev.info && dev.info.device) ? dev.info.device.nwk : undefined,
|
|
3449
3687
|
battery_cls = getBatteryCls(dev.battery),
|
|
3450
3688
|
lqi_cls = getLQICls(dev.link_quality),
|
|
3451
3689
|
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>'),
|
|
3452
3690
|
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>` : '',
|
|
3453
3691
|
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 : ''),
|
|
3454
3692
|
//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>`),
|
|
3455
|
-
//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>' : '',
|
|
3456
3693
|
//infoBtn = (nwk) ? `<button name="info" class="left btn-flat btn-small"><i class="material-icons icon-blue">info</i></button>` : '',
|
|
3457
3694
|
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>` : '';
|
|
3458
3695
|
const info = (dev.statesDef) ? dev.statesDef.map((stateDef) => {
|
|
@@ -3502,13 +3739,19 @@ function getDashCard(dev, groupImage, groupstatus) {
|
|
|
3502
3739
|
}).join('') : '';
|
|
3503
3740
|
const dashCard = `
|
|
3504
3741
|
<div class="card-content zcard ${isActive ? '' : 'bg_red'}">
|
|
3505
|
-
<div
|
|
3742
|
+
<div style="cursor: pointer">
|
|
3743
|
+
<span class="top right small" style="border-radius: 50%">
|
|
3744
|
+
${device_queryBtn}
|
|
3745
|
+
${permitJoinBtn}
|
|
3746
|
+
</span>
|
|
3747
|
+
<div class="flip">
|
|
3506
3748
|
<span class="top right small" style="border-radius: 50%">
|
|
3507
3749
|
${idleTime}
|
|
3508
3750
|
${battery}
|
|
3509
3751
|
${lq}
|
|
3510
3752
|
</span>
|
|
3511
|
-
|
|
3753
|
+
<span class="card-title truncate">${title}</span>
|
|
3754
|
+
</div>
|
|
3512
3755
|
</div>
|
|
3513
3756
|
<i class="left">${image}</i>
|
|
3514
3757
|
<div style="min-height:88px; font-size: 0.8em; height: 130px; overflow-y: auto" class="truncate">
|
|
@@ -3643,7 +3886,7 @@ function reconfigureDevice(id) {
|
|
|
3643
3886
|
}
|
|
3644
3887
|
}
|
|
3645
3888
|
});
|
|
3646
|
-
showWaitingDialog('Device is being
|
|
3889
|
+
showWaitingDialog('Device is being reconfigured', 30);
|
|
3647
3890
|
}
|
|
3648
3891
|
|
|
3649
3892
|
const warnLevel = {
|
|
@@ -3656,34 +3899,34 @@ function validateConfigData(key, val) {
|
|
|
3656
3899
|
if (validatableKeys.indexOf(key) < 0 || !val) return;
|
|
3657
3900
|
if (warnLevel[key]) {
|
|
3658
3901
|
if (warnLevel[key](val)) {
|
|
3659
|
-
console.warn(`warning set for ${key} (${val})`)
|
|
3902
|
+
//console.warn(`warning set for ${key} (${val})`)
|
|
3660
3903
|
$(`#${key}_ALERT`).removeClass('hide')
|
|
3661
3904
|
} else $(`#${key}_ALERT`).addClass('hide')
|
|
3662
3905
|
}
|
|
3663
3906
|
if (nvRamBackup[key]) {
|
|
3664
|
-
console.warn(`value of ${key} is ${val} (${nvRamBackup[key]})`);
|
|
3907
|
+
//console.warn(`value of ${key} is ${val} (${nvRamBackup[key]})`);
|
|
3665
3908
|
if ((typeof val == 'string' && typeof nvRamBackup[key] == 'string' && val.toLowerCase == nvRamBackup[key].toLowerCase) || val == nvRamBackup[key])
|
|
3666
3909
|
{
|
|
3667
|
-
console.warn(`ok set for ${key} (${val})`)
|
|
3910
|
+
//console.warn(`ok set for ${key} (${val})`)
|
|
3668
3911
|
$(`#${key}_OK`).removeClass('hide')
|
|
3669
3912
|
$(`#${key}_NOK`).addClass('hide')
|
|
3670
3913
|
}
|
|
3671
3914
|
else
|
|
3672
3915
|
{
|
|
3673
|
-
console.warn(`nok set for ${key} (${val})`)
|
|
3916
|
+
//console.warn(`nok set for ${key} (${val})`)
|
|
3674
3917
|
$(`#${key}_OK`).addClass('hide')
|
|
3675
3918
|
$(`#${key}_NOK`).removeClass('hide')
|
|
3676
3919
|
}
|
|
3677
3920
|
}
|
|
3678
3921
|
else {
|
|
3679
|
-
console.warn(`noval set for ${key} (${val})`)
|
|
3922
|
+
//console.warn(`noval set for ${key} (${val})`)
|
|
3680
3923
|
$(`#${key}_OK`).addClass('hide')
|
|
3681
3924
|
$(`#${key}_NOK`).addClass('hide')
|
|
3682
3925
|
}
|
|
3683
3926
|
}
|
|
3684
3927
|
|
|
3685
3928
|
function validateNVRamBackup(update, src) {
|
|
3686
|
-
console.warn('validateNVRam');
|
|
3929
|
+
//console.warn('validateNVRam');
|
|
3687
3930
|
const validatedKeys = src ? [src] : validatableKeys;
|
|
3688
3931
|
const validator = {};
|
|
3689
3932
|
for (const key of validatedKeys) {
|
|
@@ -3703,9 +3946,11 @@ function validateNVRamBackup(update, src) {
|
|
|
3703
3946
|
function readNVRamBackup(update) {
|
|
3704
3947
|
console.warn('read nvRam')
|
|
3705
3948
|
sendTo(namespace, 'readNVRam', {}, function(msg) {
|
|
3949
|
+
console.warn(JSON.stringify(msg));
|
|
3706
3950
|
if (msg) {
|
|
3707
3951
|
if (msg.error && update) {
|
|
3708
|
-
|
|
3952
|
+
if (msg.error.includes('ENOENT')) showMessage('Unable to read nvRam backup - no backup available.',_('Error'))
|
|
3953
|
+
else showMessage(msg.error, _('Error'));
|
|
3709
3954
|
delete msg.error;
|
|
3710
3955
|
}
|
|
3711
3956
|
nvRamBackup = msg;
|