iobroker.zigbee 3.2.5 → 3.3.1-alpha.0
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 +16 -0
- package/admin/admin.js +376 -267
- package/admin/index_m.html +21 -32
- package/admin/tab_m.html +14 -2
- package/io-package.json +31 -31
- package/lib/commands.js +120 -76
- package/lib/exclude.js +1 -1
- package/lib/exposes.js +187 -77
- package/lib/groups.js +28 -15
- package/lib/{devices.js → legacy/devices.js} +27 -3
- package/lib/{states.js → legacy/states.js} +3 -3
- package/lib/localConfig.js +42 -0
- package/lib/models.js +615 -0
- package/lib/networkmap.js +15 -5
- package/lib/statescontroller.js +312 -297
- package/lib/utils.js +3 -4
- package/lib/zbBaseExtension.js +4 -0
- package/lib/zbDeviceAvailability.js +16 -23
- package/lib/zbDeviceConfigure.js +21 -8
- package/lib/zigbeecontroller.js +134 -88
- package/main.js +38 -42
- package/package.json +14 -15
package/admin/index_m.html
CHANGED
|
@@ -733,11 +733,17 @@
|
|
|
733
733
|
<i class="material-icons large icon-blue">feedback</i></a>
|
|
734
734
|
</li>
|
|
735
735
|
<li>
|
|
736
|
-
|
|
736
|
+
<a id="download_icons_btn"
|
|
737
737
|
class="btn-floating disabled waves-effect waves-light blue tooltipped center-align hoverable translateT"
|
|
738
738
|
title="Download missing icons">
|
|
739
739
|
<i class="material-icons large">cloud_download</i></a>
|
|
740
740
|
</li>
|
|
741
|
+
<li>
|
|
742
|
+
<a id="rebuild_states_btn"
|
|
743
|
+
class="btn-floating disabled waves-effect waves-light blue tooltipped center-align hoverable translateT"
|
|
744
|
+
title="Rebuild states">
|
|
745
|
+
<i class="material-icons large">low_priority</i></a>
|
|
746
|
+
</li>
|
|
741
747
|
<li>
|
|
742
748
|
<a id="pairing"
|
|
743
749
|
class="btn-floating disabled waves-effect waves-light green tooltipped center-align hoverable translateT"
|
|
@@ -1286,37 +1292,6 @@
|
|
|
1286
1292
|
</nav>
|
|
1287
1293
|
</div>
|
|
1288
1294
|
<div class="row">
|
|
1289
|
-
<!--
|
|
1290
|
-
<div class="col s1 l1 m1"><a id="modelnamefilter" class="btn-large blue left" ><i class="material-icons icon-blue">filter_list</i></a></div>
|
|
1291
|
-
<div class="col s5 l5 m5 input-field" style="line-height: 24px;"><input id="Filter" type="text" /><label class="translate">Search</div>
|
|
1292
|
-
<div class="col s1 l1 m1"><a id="modelsetfilter" class="btn-large blue left" ><i class="material-icons icon-blue">reorder</i></a></div>
|
|
1293
|
-
<div class="input-field suffix col s2 m2 l2">
|
|
1294
|
-
<select id="channel" class="value">
|
|
1295
|
-
<option value="function(a) { return true }" selected>All</option>
|
|
1296
|
-
<option value="function(a) { return LocalDisplayDataValues[a].type == 'group' }">Groups</option>
|
|
1297
|
-
<option value="function(a) { return LocalDisplayDataValues[a].type == 'Router' }">Routers</option>
|
|
1298
|
-
<option value="function(a) { return LocalDisplayDataValues[a].type == 'Router' }">EndDevices</option>
|
|
1299
|
-
<option value="function(a) { return LocalDisplayDataValues[a].setOptions?.length > 0 }">with Options</option>
|
|
1300
|
-
<option value="function(a) { return !(LocalDisplayDataValues[a].setOptions?.length > 0) }">without Options</option>
|
|
1301
|
-
<label class="translate">Filter</label>
|
|
1302
|
-
</select>
|
|
1303
|
-
</div>
|
|
1304
|
-
<div class="col s1 l1 m1"><a id="modelnamefilter" class="btn-large blue left" ><i class="material-icons icon-blue">sort</i></a></div>
|
|
1305
|
-
<div class="input-field suffix col s2 m2 l2">
|
|
1306
|
-
<select id="channel" class="value">
|
|
1307
|
-
<option value="function(a,b) { return 0 }" selected>noSort</option>
|
|
1308
|
-
<option value="function(a,b) { return LocalDisplayDataValues[a].type > LocalDisplayDataValues[b].type }">by type</option>
|
|
1309
|
-
<option value="function(a,b) { return LocalDisplayDataValues[a].devices?.length > LocalDisplayDataValues[b].devices?.length }">by device counttype</option>
|
|
1310
|
-
<option value="function(a,b) { return LocalDisplayDataValues[a].setOptions?.length > LocalDisplayDataValues[b].setOptions?.length }">by option count</option>
|
|
1311
|
-
<label class="translate">Sort</label>
|
|
1312
|
-
</select>
|
|
1313
|
-
</div></div>
|
|
1314
|
-
<div class="fixed-action-btn" style="margin-bottom: 100px">
|
|
1315
|
-
<a id="updateData"
|
|
1316
|
-
class="btn-floating waves-effect waves-light blue tooltipped center-align hoverable translateT"
|
|
1317
|
-
title="update Data"><i class="material-icons large">replay</i></a>
|
|
1318
|
-
</div>
|
|
1319
|
-
-->
|
|
1320
1295
|
<div id="tab-overrides-content" row>
|
|
1321
1296
|
Nothing to see yet.
|
|
1322
1297
|
</div>
|
|
@@ -1490,6 +1465,20 @@
|
|
|
1490
1465
|
<a href="#!" class="modal-action modal-close waves-effect waves-red btn-flat translate">Cancel</a>
|
|
1491
1466
|
</div>
|
|
1492
1467
|
</div>
|
|
1468
|
+
<div id="modalrebuild" class="modal">
|
|
1469
|
+
<div class="modal-content">
|
|
1470
|
+
<h3 class="translate">State rebuild confirmation</h3>
|
|
1471
|
+
<p>A bunch of text</p>
|
|
1472
|
+
</div>
|
|
1473
|
+
<div class="modal-footer">
|
|
1474
|
+
<div id="cforcediv" class="forcedelete">
|
|
1475
|
+
<input id="cforce_rebuild" type="checkbox" class="value"/>
|
|
1476
|
+
<label class="translate" for="cforce_rebuild">Force update all roles to adapter defined roles</label>
|
|
1477
|
+
</div>
|
|
1478
|
+
<a name="yes" href="#!" class="modal-action modal-close waves-effect waves-green btn green translate">Yes</a>
|
|
1479
|
+
<a href="#!" class="modal-action modal-close waves-effect waves-red btn-flat translate">Cancel</a>
|
|
1480
|
+
</div>
|
|
1481
|
+
</div>
|
|
1493
1482
|
<div id="modalreconfigure" class="modal">
|
|
1494
1483
|
<div class="modal-content">
|
|
1495
1484
|
<h3 class="translate">Reconfigure device</h3>
|
package/admin/tab_m.html
CHANGED
|
@@ -680,7 +680,7 @@
|
|
|
680
680
|
</p></div>
|
|
681
681
|
<ul id="nav-mobile" class="right">
|
|
682
682
|
<li>
|
|
683
|
-
<a id="adapterStopped_btn" class="btn-floating waves-effect waves-light red tooltipped center-align hoverable translateT hide" title="Adapter not running">
|
|
683
|
+
<a id="adapterStopped_btn" class="btn-floating waves-effect waves-light red icon-black tooltipped center-align hoverable translateT hide" title="Adapter not running">
|
|
684
684
|
<i class="material-icons large">grid_off</i></a>
|
|
685
685
|
</li>
|
|
686
686
|
<li>
|
|
@@ -697,6 +697,16 @@
|
|
|
697
697
|
<a id="show_errors_btn" class="btn-floating waves-effect waves-light red tooltipped center-align hoverable translateT hide" title="Show Errors">
|
|
698
698
|
<i class="material-icons large">feedback</i></a>
|
|
699
699
|
</li>
|
|
700
|
+
<li>
|
|
701
|
+
<a id="map_errors_btn" class="btn-floating waves-effect waves-light orange tooltipped center-align hoverable translateT hide" title="Show errors from map generation">
|
|
702
|
+
<i class="material-icons large">filter_none</i></a>
|
|
703
|
+
</li>
|
|
704
|
+
<li>
|
|
705
|
+
<li>
|
|
706
|
+
<a id="map_generating_btn" class="btn-floating waves-effect waves-light blue tooltipped center-align hoverable translateT hide" title="Map generation in progress">
|
|
707
|
+
<i class="material-icons large">filter_none</i></a>
|
|
708
|
+
</li>
|
|
709
|
+
<li>
|
|
700
710
|
<li>
|
|
701
711
|
<a id="fw_check_btn" class="btn-floating waves-effect waves-light blue tooltipped center-align hoverable translateT hide" title="Check firmware updates">
|
|
702
712
|
<i class="material-icons large">system_update</i></a>
|
|
@@ -761,6 +771,8 @@
|
|
|
761
771
|
<!--<li class="device-order-item" data-type="kind" tabindex="0"><a class="translate" data-lang="Kind">Kind</a></li>-->
|
|
762
772
|
<!--<li class="device-order-item" data-type="status" tabindex="0"><a class="translate" data-lang="Status">Status</a></li>-->
|
|
763
773
|
<li class="device-order-item" data-type="default" tabindex="0"><a class="translate" data-lang="Default">Default</a></li>
|
|
774
|
+
<li class="device-order-item" data-type="range" tabindex="0"><a class="translate" data-lang="Range">Range</a></li>
|
|
775
|
+
<li class="device-order-item" data-type="load" tabindex="0"><a class="translate" data-lang="Load">Load</a></li>
|
|
764
776
|
</ul>
|
|
765
777
|
</div>
|
|
766
778
|
</li>
|
|
@@ -1218,7 +1230,7 @@
|
|
|
1218
1230
|
</label>
|
|
1219
1231
|
</div>
|
|
1220
1232
|
<div class="input-field col s12 admin-tooltip-icon translateT" title="Regenerate Map">
|
|
1221
|
-
<br><button id="regenerate" class="waves-effect center hoverable blue"><i class="material-icons medium border:0 icon-
|
|
1233
|
+
<br><button id="regenerate" class="waves-effect center hoverable blue"><i class="material-icons medium border:0 icon-black">map</i></button>
|
|
1222
1234
|
</div>
|
|
1223
1235
|
</div>
|
|
1224
1236
|
<div class="input-field input-group col s12 m6 l6">
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "zigbee",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.3.1-alpha.0",
|
|
5
5
|
"news": {
|
|
6
|
+
"3.3.1-alpha.0": {
|
|
7
|
+
"en": "\n",
|
|
8
|
+
"de": "\n",
|
|
9
|
+
"ru": "\n",
|
|
10
|
+
"pt": "\n",
|
|
11
|
+
"nl": "\n",
|
|
12
|
+
"fr": "\n",
|
|
13
|
+
"it": "\n",
|
|
14
|
+
"es": "\n",
|
|
15
|
+
"pl": "\n",
|
|
16
|
+
"uk": "\n",
|
|
17
|
+
"zh-cn": "\n"
|
|
18
|
+
},
|
|
19
|
+
"3.3.0": {
|
|
20
|
+
"en": "Fix: dynamic model assignment when exposes is function (PTVO, BuschJaeger)\nFix: Roles\nRefactor: Legacy code moved\nRefactor: Expose creation changed.\nRefactor: Exposes no longer use states from legacy code\nFeature: Offer state rebuild function in Settings\n: Additional filters for device display\nFix: Orphaned group states detected, marked and deletable\nUpdate: ZH 7.x\nUpdate: ZHC 25.84.0",
|
|
21
|
+
"de": "Fix: Dynamische Modellzuweisung bei Belichtungen ist Funktion (PTVO, BuschJaeger)\nFix: Roles\nRefactor: Legacy-Code bewegt\nHersteller: Expose Kreation geändert.\nRefactor: Exposes verwendet nicht mehr Staaten von Legacy-Code\nFeature: Offer state rebuild Funktion in Einstellungen\n: Zusätzliche Filter für Geräteanzeige\nFix: Verwaiste Gruppenzustände erkannt, markiert und verblendet\nAktualisierung: ZH 7.x\nAktualisierung: ZHC 25.84.0",
|
|
22
|
+
"ru": "Исправление: назначение динамической модели при раскрытии функции (PTVO, BuschJaeger)\nИсполнитель: Roles\nРефактор: код Legacy перемещен\nРефактор: Создание экспозиции изменилось.\nRefactor: EXPOES больше не используют устаревший код\nФункция: Предложите функцию восстановления состояния в настройках\nДополнительные фильтры для отображения устройства\nИсправление: обнаруженные, помеченные и удаляемые состояния орфанной группы\nОбновление: ZH 7.x\nОбновление: ZHC 25.84.0",
|
|
23
|
+
"pt": "Corrigir: atribuição dinâmica do modelo quando expõe é função (PTVO, BuschJaeger)\nCorrigir: Funções\nRefactor: Código de legado movido\nRefactor: Expor a criação mudou.\nRefator: Expos não usam mais estados do código legado\nCaracterística: Ofereça a função de reconstrução do estado em Configurações\n: Filtros adicionais para exibição do dispositivo\nCorrigir: estados de grupo órfão detectados, marcados e deletáveis\nActualização: ZH 7.x\nAtualização: ZHC 25.84.0",
|
|
24
|
+
"nl": "Fix: dynamische modeltoewijzing wanneer blootgesteld is functie (PTVO, BuschJaeger)\nFix: rollen\nRefactor: Legacy code verplaatst\nRefactor: Aanmaak gewijzigd tonen.\nRefactor: Exposes gebruikt geen staten meer van legacy code\nFunctie: Aanbieden status wederopbouw functie in Instellingen\n: Extra filters voor apparaatweergave\nFix: weesgroep staten gedetecteerd, gemarkeerd en deletable\nUpdate: ZH 7.x\nUpdate: ZHC 25.84.0",
|
|
25
|
+
"fr": "Correction : attribution de modèle dynamique lorsque l'exposition est fonction (PTVO, BuschJaeger)\nCorrection : Rôles\nRefactor: Legacy code déplacé\nRefacteur: La création d'exposition a changé.\nRefactor: Les expositions n'utilisent plus les états à partir du code ancien\nCaractéristique: Offre la fonction de reconstruction de l'état dans les paramètres\n: Filtres supplémentaires pour l'affichage des appareils\nCorrection : États de groupe orphelins détectés, marqués et délaissables\nMise à jour : ZH 7.x\nMise à jour: ZHC 25.84.0",
|
|
26
|
+
"it": "Fisso: l'assegnazione dinamica del modello quando espone è funzione (PTVO, BuschJaeger)\nFisso: Roles\nRefactor: Legacy code move\nRefactor: La creazione dell'esposizione è cambiata.\nRefactor: Exposes not use stati from legacy code\nCaratteristica: Offrire la funzione di ricostruzione dello stato in Impostazioni\n: Filtri aggiuntivi per display del dispositivo\nFisso: Stati del gruppo orfano rilevati, contrassegnati e cancellabili\nAggiornamento: ZH 7.x\nAggiornamento: ZHC 25.84.0",
|
|
27
|
+
"es": "Fijación: asignación de modelos dinámicos cuando se expone es función (PTVO, BuschJaeger)\nCorrección: Papeles\nRefactor: Se movió el código de Legacy\nRefactor: La creación de la exposición cambió.\nRefactor: Los Exposes ya no utilizan estados del código hereditario\nCaracterística: Oferta función de reconstrucción estatal en Ajustes\n: Filtros adicionales para la pantalla del dispositivo\nFijación: Estados del grupo huérfano detectados, marcados y eliminables\nActualización: ZH 7.x\nActualización: ZHC 25.84.0",
|
|
28
|
+
"pl": "Fix: przypisanie modelu dynamicznego, gdy funkcja eksponuje (PTVO, BuschJaeger)\nFix: Roles\nWspółczynnik: Przesunięty kod legacy\nWspółczynnik: Odkryj, że kreacja się zmieniła.\nRefaktor: Ekspozycje nie wykorzystują już stanów z dotychczasowego kodu\nCecha: Oferta funkcji odbudowy państwa w ustawieniach\n: Dodatkowe filtry do wyświetlania urządzeń\nFix: Osierocone państwa grupowe wykryte, oznaczone i usunięte\nAktualizacja: ZH 7.x\nAktualizacja: ZHC 25.84.0",
|
|
29
|
+
"uk": "Виправлення: динамічне завдання моделі при налаштуванні функції (PTVO, BuschJaeger)\nФіксація: Ролі\nРефактор: код Legacy переїхав\nРефактор: Змінено виставку.\nРефактор: Виставки більше не використовують стани з коду спадкування\nХарактеристика: Пропозиція функції державного відновлення в налаштуваннях\n: Додаткові фільтри для відображення пристрою\nВиправлення: Виявлені орфагенти групи, позначені та видалені\nОновлення: ZH 7.x\nОновлення: ZHC 25.84.0",
|
|
30
|
+
"zh-cn": "Fix: 曝光时的动态模型任务为函数( PTVO, Busch Jaeger)\n修补:角色\n内容: 遗留代码已移动\n重构 : 展览的创作改变了.\n内容: 展览不再使用遗留代码中的状态\n特性: 在设置中提供状态重建功能\n: 设备显示的额外过滤器\n修复:发现、标记和删除孤儿群体状态\n最新情况:ZH 7.x\n最新情况:ZHC 25.84.0"
|
|
31
|
+
},
|
|
6
32
|
"3.2.5": {
|
|
7
33
|
"en": "changed setState for lasterror",
|
|
8
34
|
"de": "geändert setState für lasterror",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "fix bug # 2640\n",
|
|
68
94
|
"uk": "виправлення помилки #2640\n",
|
|
69
95
|
"zh-cn": "修复错误 # 2640\n"
|
|
70
|
-
},
|
|
71
|
-
"3.2.0": {
|
|
72
|
-
"en": "remove local overrides tab from config\nestablish local data tab in config to edit global and device level settings and options\nremove the local overrides tab\nremove the ability to set model level overrides from device tab.\nfix errors for 'polling' devices with changed poll times.\nwarning icon for devices which are not completely interviewed.\nimproved router detection for opening the network\nbugfix: open network on router\nZHC 25.x latest, ZH 6.1.3,\nrestore from in-adapter backup",
|
|
73
|
-
"de": "entfernen sie lokale overrides tab von config\nlokale daten tab erstellen, um globale und geräteebene einstellungen und optionen zu bearbeiten\nentfernen der lokalen overrides tab\nentfernen sie die fähigkeit, modellebene überschrieben von der geräte-tab.\nfehler für \"polling\"-geräte mit veränderten abfragezeiten beheben.\nwarnsymbol für geräte, die nicht vollständig interviewt werden.\nverbesserte routererkennung zum öffnen des netzwerks\nbugfix: offenes netzwerk auf router\nZHC 25.x neueste, ZH 6.1.3,\nwiederherstellung von in-adapter-backup",
|
|
74
|
-
"ru": "удалить локальную вкладку overrided из конфигураций\nустановить локальную вкладку данных в конфигурацию для редактирования глобальных настроек и параметров уровня устройства\nудалить вкладку local overrides\nудалить возможность установки переопределений уровня модели из вкладки устройства.\nисправление ошибок для «опросных» устройств с измененным временем опроса.\nиконка предупреждения для устройств, которые не были полностью опрошены.\nулучшенное обнаружение маршрутизатора для открытия сети\nbugfix: открытая сеть на маршрутизаторе\nZHC 25.x, ZH 6.1.3,\nвосстановление из in-adapter backup",
|
|
75
|
-
"pt": "remover a página de substituições locais da configuração\nestabelecer a página de dados locais na configuração para editar as configurações e opções globais e de nível do dispositivo\nremover a página de sobreposições locais\nremover a capacidade de definir os comandos de nível do modelo da aba do dispositivo.\ncorrigir erros para dispositivos de 'polling' com tempos de votação alterados.\nícone de aviso para dispositivos que não são completamente entrevistados.\ndetecção de roteador melhorada para abrir a rede\ncorreção de erros: abrir rede no roteador\nZHC 25.x mais recente, ZH 6.1.3,\nrestaurar a partir de backup no adaptador",
|
|
76
|
-
"nl": "tabblad overrides verwijderen uit config\nlokale datatabblad instellen in config om instellingen en opties voor het niveau van het apparaat en de globale instellingen te bewerken\nhet tabblad lokale overrides verwijderen\nverwijder de mogelijkheid om modelniveau overrides van apparaat tab.\nfouten te herstellen voor 'polling' apparaten met veranderde polltijden.\nwaarschuwingspictogram voor apparaten die niet volledig zijn geïnterviewd.\nverbeterde routerdetectie voor het openen van het netwerk\nbugfix: open netwerk op router\nZHC 25.x laatste, ZH 6.1.3,\nherstellen van in-adapter back-up",
|
|
77
|
-
"fr": "supprimer l'onglet local de la configuration\ncréer un onglet local de données dans la configuration pour modifier les paramètres et les options de niveau global et périphérique\nsupprimer l'onglet local de remplacement\nsupprimer la possibilité de définir les dépassements de niveau du modèle de l'onglet périphérique.\ncorriger les erreurs pour les dispositifs 'polling' avec des temps de sondage modifiés.\nicône d'avertissement pour les appareils qui ne sont pas complètement interviewés.\namélioration de la détection du routeur pour l'ouverture du réseau\nbugfix: ouvrir le réseau sur le routeur\nZHC 25.x dernier, ZH 6.1.3,\nrestaurer à partir de la sauvegarde dans l'adaptateur",
|
|
78
|
-
"it": "rimuovere la scheda override locale da config\nstabilire la scheda dati locale in configurazione per modificare le impostazioni e le opzioni del livello globale e del dispositivo\nrimuovere la scheda override locale\nrimuovere la capacità di impostare override di livello del modello dalla scheda del dispositivo.\ncorreggere gli errori per i dispositivi 'polling' con tempi di sondaggio modificati.\nicona di avviso per dispositivi che non sono completamente intervistati.\nmiglioramento del rilevamento del router per l'apertura della rete\nbugfix: aprire la rete sul router\nZHC 25.x ultimo, ZH 6.1.3,\nripristino da backup in-adapter",
|
|
79
|
-
"es": "eliminar la pestaña de anulaciones locales de config\nestablecer la ficha de datos local en config para editar ajustes y opciones a nivel global y de dispositivos\neliminar la ficha de anulación local\neliminar la capacidad de establecer el nivel de modelo anula de la pestaña dispositivo.\ncorrige errores para dispositivos 'polling' con tiempos de votación cambiados.\nicono de advertencia para dispositivos que no son entrevistados por completo.\nmejor detección de router para abrir la red\nbugfix: red abierta en router\nZHC 25.x más reciente, ZH 6.1.3,\nrestaurar de la copia de seguridad en el equipo",
|
|
80
|
-
"pl": "usuń lokalne nadjazdy z zakładki config\ntworzy lokalną kartę danych w konfigu, aby edytować globalne i na poziomie urządzenia ustawienia i opcje\nusuń kartę lokalnych nadwozi\nusuń możliwość ustawiania nadwyżek poziomu modelu z zakładki urządzenia.\nnaprawić błędy urządzeń 'sondażowych' ze zmienionymi okresami ankiety.\nikona ostrzegawcza dla urządzeń, które nie są w pełni przesłuchane.\nulepszone wykrywanie routerów w celu otwarcia sieci\nbugfix: otwarta sieć na routerze\nZHC 25.x najnowszy, ZH 6.1.3,\nprzywracanie z kopii zapasowej in- adaptera",
|
|
81
|
-
"uk": "видалити локальну вкладку overrides з налаштування\nвстановити локальну вкладку даних в конфігурацію для редагування параметрів рівня глобального та пристрою та параметрів\nвидалити локальну вкладку\nприбрати можливість встановити рівень моделі перенаряддя з вкладки пристрою.\nфіксувати помилки для пристроїв «запилення» з змінними термінами опитування.\nзначок попередження для пристроїв, які не повністю опитуються.\nполіпшення виявлення маршрутизатора для відкриття мережі\nвиправлення помилок: відкрита мережа на маршрутизаторі\nZHC 25.x останнє, ZH 6.1.3,\nвідновлення з резервної копії",
|
|
82
|
-
"zh-cn": "从配置中删除本地覆盖标签\n在配置中建立本地数据标签以编辑全局和设备级别设置和选项\n删除本地覆盖标签\n从设备标签中删除设置模型级别覆盖的能力 .\n修正“ 投票” 设备的错误, 并更改投票时间 .\n警告未完全访问设备的图标.\n为打开网络改进路由器检测\n错误修正: 在路由器上打开网络\nZHC 25.x最新版,ZH 6.1.3,\n从适应中备份恢复"
|
|
83
|
-
},
|
|
84
|
-
"3.1.6": {
|
|
85
|
-
"en": "Bugfixes\n",
|
|
86
|
-
"de": "Bugfixes\n",
|
|
87
|
-
"ru": "Багфиксы\n",
|
|
88
|
-
"pt": "Correcções de Erros\n",
|
|
89
|
-
"nl": "Bugfixes\n",
|
|
90
|
-
"fr": "Fixes de bogue\n",
|
|
91
|
-
"it": "Bugfix\n",
|
|
92
|
-
"es": "Bugfixes\n",
|
|
93
|
-
"pl": "Korekty błędów\n",
|
|
94
|
-
"uk": "Помилки\n",
|
|
95
|
-
"zh-cn": "错误修正\n"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
"tab": "materialize"
|
|
160
160
|
},
|
|
161
161
|
"messagebox": true,
|
|
162
|
-
"stopTimeout":
|
|
162
|
+
"stopTimeout": 30000,
|
|
163
163
|
"stopBeforeUpdate": true,
|
|
164
164
|
"dataFolder": "zigbee_%INSTANCE%",
|
|
165
165
|
"compact": true,
|
|
@@ -369,7 +369,7 @@
|
|
|
369
369
|
"_id": "info.lasterror",
|
|
370
370
|
"type": "state",
|
|
371
371
|
"common": {
|
|
372
|
-
"role": "
|
|
372
|
+
"role": "state",
|
|
373
373
|
"name": "Last stashed error",
|
|
374
374
|
"type": "string",
|
|
375
375
|
"read": true,
|
|
@@ -382,7 +382,7 @@
|
|
|
382
382
|
"_id": "info.pairingCountdown",
|
|
383
383
|
"type": "state",
|
|
384
384
|
"common": {
|
|
385
|
-
"role": "
|
|
385
|
+
"role": "value",
|
|
386
386
|
"name": "Pairing countdown",
|
|
387
387
|
"type": "number",
|
|
388
388
|
"read": true,
|
|
@@ -395,7 +395,7 @@
|
|
|
395
395
|
"_id": "info.pairingMessage",
|
|
396
396
|
"type": "state",
|
|
397
397
|
"common": {
|
|
398
|
-
"role": "
|
|
398
|
+
"role": "state",
|
|
399
399
|
"name": "Pairing message",
|
|
400
400
|
"type": "string",
|
|
401
401
|
"read": true,
|
package/lib/commands.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { getZbId, getNetAddress, reverseByteString, zbIdorIeeetoAdId, adIdtoZbIdorIeee } = require('./utils');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const
|
|
5
|
+
const modelDefinitions = require('./models.js');
|
|
6
6
|
const colors = require('./colors.js');
|
|
7
7
|
/* currently not needed, kept for referencce
|
|
8
8
|
const utils = require('@iobroker/adapter-core'); // Get common adapter utils
|
|
@@ -21,6 +21,7 @@ class Commands {
|
|
|
21
21
|
constructor(adapter) {
|
|
22
22
|
this.adapter = adapter;
|
|
23
23
|
this.adapter.on('message', obj => this.onMessage(obj));
|
|
24
|
+
this.devicesDeleting = new Set();
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
start(zbController, stController) {
|
|
@@ -97,9 +98,12 @@ class Commands {
|
|
|
97
98
|
this.getCoordinatorInfo(obj.from, obj.command, obj.callback);
|
|
98
99
|
}
|
|
99
100
|
break;
|
|
100
|
-
case '
|
|
101
|
+
case 'modifyDeviceStates':
|
|
101
102
|
if (obj.message && typeof obj.message === 'object') {
|
|
102
|
-
|
|
103
|
+
if (obj.message.action == 'clean')
|
|
104
|
+
return this.cleanDeviceStates(obj.from, obj.command, obj.message.force, obj.callback);
|
|
105
|
+
if (obj.message.action == 'rebuild')
|
|
106
|
+
return this.rebuildDeviceStates(obj.from, obj.command, obj.message.force, obj.callback);
|
|
103
107
|
}
|
|
104
108
|
break;
|
|
105
109
|
case 'setState':
|
|
@@ -299,6 +303,9 @@ class Commands {
|
|
|
299
303
|
|
|
300
304
|
if (await this.zbController.permitJoin(cTimer, devId)) {
|
|
301
305
|
this.adapter.setState('info.pairingMode', cTimer > 0, true);
|
|
306
|
+
if (cTimer != 0 && this.stController) {
|
|
307
|
+
this.stController.resetKnownUnknownModels();
|
|
308
|
+
}
|
|
302
309
|
//this.adapter.sendTo(from, command, cTimer ? 'Start pairing!':'Stop pairing!', callback);
|
|
303
310
|
}
|
|
304
311
|
else {
|
|
@@ -375,7 +382,7 @@ class Commands {
|
|
|
375
382
|
}
|
|
376
383
|
}
|
|
377
384
|
|
|
378
|
-
async fillInfo(device, device_stateDefs, all_states, models) {
|
|
385
|
+
async fillInfo(device, entity, device_stateDefs, all_states, models) {
|
|
379
386
|
device.statesDef = (device_stateDefs || []).filter(stateDef => {
|
|
380
387
|
const sid = stateDef._id.replace(this.adapter.namespace + '.', '');
|
|
381
388
|
const names = sid.split('.');
|
|
@@ -398,8 +405,6 @@ class Commands {
|
|
|
398
405
|
};
|
|
399
406
|
});
|
|
400
407
|
|
|
401
|
-
const id = getZbId(device._id);
|
|
402
|
-
const entity = await this.zbController.resolveEntity(id)
|
|
403
408
|
|
|
404
409
|
device.info = this.buildDeviceInfo(entity);
|
|
405
410
|
|
|
@@ -413,7 +418,7 @@ class Commands {
|
|
|
413
418
|
availableOptions : [...device.info?.mapped?.options || [], ...['use_legacy_model']],
|
|
414
419
|
setOptions: this.adapter.stController.localConfig.getByModel(device.info?.mapped?.model || 'unknown') || [],
|
|
415
420
|
devices: [device],
|
|
416
|
-
}
|
|
421
|
+
};
|
|
417
422
|
if (!models.byUID[UID].model.type)
|
|
418
423
|
models.byUID[UID].model.type = 'Group';
|
|
419
424
|
models.UIDbyModel[device.info?.mapped?.model || 'unknown'] = UID;
|
|
@@ -433,7 +438,7 @@ class Commands {
|
|
|
433
438
|
}
|
|
434
439
|
}
|
|
435
440
|
|
|
436
|
-
buildDeviceInfo(
|
|
441
|
+
buildDeviceInfo(entity) {
|
|
437
442
|
function getKey(object, value) {
|
|
438
443
|
try {
|
|
439
444
|
for (const key of Object.keys(object)) {
|
|
@@ -459,34 +464,34 @@ class Commands {
|
|
|
459
464
|
const rv = {};
|
|
460
465
|
try {
|
|
461
466
|
rv.device = {
|
|
462
|
-
modelZigbee:
|
|
463
|
-
type:
|
|
464
|
-
ieee:
|
|
465
|
-
nwk:
|
|
466
|
-
manuf_id:
|
|
467
|
-
manuf_name:
|
|
468
|
-
manufacturer:
|
|
469
|
-
power:
|
|
470
|
-
app_version:
|
|
471
|
-
hard_version:
|
|
472
|
-
zcl_version:
|
|
473
|
-
stack_version:
|
|
474
|
-
date_code:
|
|
475
|
-
build:
|
|
476
|
-
interviewstate:
|
|
467
|
+
modelZigbee:entity.device.modelID,
|
|
468
|
+
type:entity.device.type,
|
|
469
|
+
ieee:entity.device.ieeeAddr || entity.device.groupID,
|
|
470
|
+
nwk:entity.device.networkAddress || 0,
|
|
471
|
+
manuf_id:entity.device.maufacturerID,
|
|
472
|
+
manuf_name:entity.device.manufacturerName,
|
|
473
|
+
manufacturer:entity.mapped?.vendor,
|
|
474
|
+
power:entity.device.powerSource,
|
|
475
|
+
app_version:entity.device.applicationVersion,
|
|
476
|
+
hard_version:entity.device.hardwareVersion,
|
|
477
|
+
zcl_version:entity.device.zclVersion,
|
|
478
|
+
stack_version:entity.device.stack_version,
|
|
479
|
+
date_code:entity.device.dateCode,
|
|
480
|
+
build:entity.device.softwareBuildID,
|
|
481
|
+
interviewstate:entity.device.interviewState || 'UNKNOWN',
|
|
477
482
|
BindSource: false,
|
|
478
483
|
isGroupable: false,
|
|
479
484
|
}
|
|
480
485
|
rv.endpoints = [];
|
|
481
486
|
let dBindSource = false;
|
|
482
487
|
let disGroupable = false;
|
|
483
|
-
for (const ep_idx in
|
|
484
|
-
const ep =
|
|
488
|
+
for (const ep_idx in entity.endpoints) {
|
|
489
|
+
const ep = entity.endpoints[ep_idx];
|
|
485
490
|
const bindable = haveBindableClusters(ep.outputClusters);
|
|
486
491
|
dBindSource |= bindable;
|
|
487
492
|
rv.endpoints.push({
|
|
488
493
|
ID:ep.ID,
|
|
489
|
-
epName:
|
|
494
|
+
epName: entity.mapped?.endpoint ? getKey(entity.mapped?.endpoint(entity.device), ep.ID) : ep.ID,
|
|
490
495
|
profile:ep.profileID,
|
|
491
496
|
input_clusters:ep.inputClusters,
|
|
492
497
|
output_clusters:ep.outputClusters,
|
|
@@ -496,23 +501,23 @@ class Commands {
|
|
|
496
501
|
}
|
|
497
502
|
rv.device.isGroupable = Boolean(disGroupable);
|
|
498
503
|
rv.device.BindSource = Boolean(dBindSource);
|
|
499
|
-
if (
|
|
504
|
+
if (entity.mapped) {
|
|
500
505
|
rv.mapped = {
|
|
501
|
-
model:
|
|
502
|
-
type:
|
|
503
|
-
description:
|
|
504
|
-
hasLegacyDef:
|
|
506
|
+
model:entity.mapped.model,
|
|
507
|
+
type:entity.device.type,
|
|
508
|
+
description:entity.mapped.description,
|
|
509
|
+
hasLegacyDef:modelDefinitions.hasLegacyDevice(entity.mapped.model),
|
|
505
510
|
//fingerprint:JSON.stringify(device.mapped.fingerprint),
|
|
506
|
-
vendor:
|
|
507
|
-
hasOnEvent:
|
|
508
|
-
hasConfigure:
|
|
509
|
-
icon:`img/${
|
|
510
|
-
legacyIcon:
|
|
511
|
+
vendor:entity.mapped.vendor,
|
|
512
|
+
hasOnEvent:entity.mapped.onEvent != undefined,
|
|
513
|
+
hasConfigure:entity.mapped.configure != undefined,
|
|
514
|
+
icon:`img/${entity.mapped.model.replace(/\//g, '-')}.png`,
|
|
515
|
+
legacyIcon: modelDefinitions.getIconforLegacyModel(entity.mapped.model),
|
|
511
516
|
options:[],
|
|
512
517
|
}
|
|
513
|
-
if (
|
|
514
|
-
rv.mapped.optionExposes =
|
|
515
|
-
for (const option of
|
|
518
|
+
if (entity.mapped.options && typeof (entity.mapped.options == 'object')) {
|
|
519
|
+
rv.mapped.optionExposes = entity.mapped.options;
|
|
520
|
+
for (const option of entity.mapped.options) {
|
|
516
521
|
if (option.name) {
|
|
517
522
|
rv.mapped.options.push(option.name);
|
|
518
523
|
}
|
|
@@ -521,9 +526,9 @@ class Commands {
|
|
|
521
526
|
}
|
|
522
527
|
else {
|
|
523
528
|
rv.mapped = {
|
|
524
|
-
model:
|
|
525
|
-
type:
|
|
526
|
-
description:
|
|
529
|
+
model:entity.name,
|
|
530
|
+
type: entity.device.type,
|
|
531
|
+
description:entity.name,
|
|
527
532
|
vendor:'not set',
|
|
528
533
|
hasOnEvent: false,
|
|
529
534
|
hasConfigure: false,
|
|
@@ -532,34 +537,34 @@ class Commands {
|
|
|
532
537
|
}
|
|
533
538
|
}
|
|
534
539
|
catch (error) {
|
|
535
|
-
if (
|
|
536
|
-
const dev =
|
|
537
|
-
const msg =
|
|
540
|
+
if (entity && entity.name === 'Coordinator') return rv;
|
|
541
|
+
const dev = entity ? entity.device || {} : {}
|
|
542
|
+
const msg = entity ? `device ${entity.name} (${dev.ieeeAddr}, NWK ${dev.networkAddres}, ID: ${dev.ID})` : 'undefined device';
|
|
538
543
|
this.warn(`Error ${error && error.message ? error.message + ' ' : ''}building device info for ${msg}`);
|
|
539
544
|
}
|
|
540
545
|
return rv;
|
|
541
546
|
}
|
|
542
547
|
|
|
543
548
|
async appendDevicesWithoutObjects(devices, client) {
|
|
544
|
-
const
|
|
545
|
-
if (!
|
|
549
|
+
const entity = await this.zbController.resolveEntity(client.ieeeAddr);
|
|
550
|
+
if (!entity || !entity.device) {
|
|
546
551
|
return;
|
|
547
552
|
}
|
|
548
|
-
const exists = devices.find((dev) => (dev._id &&
|
|
553
|
+
const exists = devices.find((dev) => (dev._id && entity.device.ieeeAddr === getZbId(dev._id)));
|
|
549
554
|
if (!exists) {
|
|
550
555
|
const coordinatorData = {
|
|
551
|
-
_id : `${this.adapter.namespace}.${
|
|
556
|
+
_id : `${this.adapter.namespace}.${entity.device.ieeeAddr.substring(2)}`,
|
|
552
557
|
paired: true,
|
|
553
|
-
info: this.buildDeviceInfo(
|
|
554
|
-
native: { id:
|
|
558
|
+
info: this.buildDeviceInfo(entity),
|
|
559
|
+
native: { id: entity.device.ieeeAddr.substring(2) },
|
|
555
560
|
mapped : { model: client.modelID || client.type || 'NotSet' },
|
|
556
561
|
statesDev: [],
|
|
557
562
|
}
|
|
558
|
-
if (
|
|
563
|
+
if (entity.name === 'Coordinator') {
|
|
559
564
|
coordinatorData.icon = 'zigbee.png';
|
|
560
565
|
coordinatorData.common = { name: 'Coordinator', type: 'Coordinator' };
|
|
561
566
|
} else {
|
|
562
|
-
coordinatorData.common = { name:
|
|
567
|
+
coordinatorData.common = { name: entity.mapped?.model || 'unknown', type: entity.type };
|
|
563
568
|
coordinatorData.icon= 'img/unknown.png';
|
|
564
569
|
}
|
|
565
570
|
devices.push(coordinatorData);
|
|
@@ -576,27 +581,30 @@ class Commands {
|
|
|
576
581
|
const deviceObjects = (id ? [await this.adapter.getObjectAsync(id)] : await this.adapter.getDevicesAsync());
|
|
577
582
|
const all_states = id ? await this.adapter.getStatesAsync(id + '.*') : await this.adapter.getStatesAsync('*');
|
|
578
583
|
const all_stateDefs = id ? await this.adapter.getStatesOfAsync(id) : await this.adapter.getStatesOfAsync();
|
|
584
|
+
|
|
579
585
|
const illegalDevices = [];
|
|
580
586
|
const groups = {};
|
|
581
587
|
const PromiseChain = [];
|
|
582
588
|
const models = { byUID : {}, UIDbyModel: {} };
|
|
583
|
-
for (const
|
|
584
|
-
|
|
585
|
-
|
|
589
|
+
for (const deviceObject of deviceObjects) {
|
|
590
|
+
const id = getZbId(deviceObject._id);
|
|
591
|
+
const entity = await this.zbController.resolveEntity(id);
|
|
592
|
+
if (deviceObject._id.indexOf('group') > -1) {
|
|
593
|
+
PromiseChain.push(this.handleGroupforInfo(deviceObject, groups));
|
|
586
594
|
}
|
|
587
595
|
else {
|
|
588
|
-
const modelDesc =
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
const lq_state = all_states[`${
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
const battery_state = all_states[`${
|
|
596
|
-
|
|
596
|
+
const modelDesc = await modelDefinitions.findModel(deviceObject.common.type, entity?.device, deviceObject.common.UUID, entity?.mapped?.legacy);
|
|
597
|
+
deviceObject.icon = (modelDesc?.icon) ? modelDesc.icon : 'img/unknown.png';
|
|
598
|
+
if (modelDesc?.vendor) deviceObject.vendor = modelDesc.vendor;
|
|
599
|
+
deviceObject.legacyIcon = modelDefinitions.getIconforLegacyModel(deviceObject.common.type);
|
|
600
|
+
const lq_state = all_states[`${deviceObject._id}.link_quality`];
|
|
601
|
+
deviceObject.link_quality = lq_state ? lq_state.val : -1;
|
|
602
|
+
deviceObject.link_quality_lc = lq_state ? lq_state.lc : undefined;
|
|
603
|
+
const battery_state = all_states[`${deviceObject._id}.battery`];
|
|
604
|
+
deviceObject.battery = battery_state ? battery_state.val : undefined;
|
|
597
605
|
|
|
598
606
|
}
|
|
599
|
-
|
|
607
|
+
deviceObject.rooms = [];
|
|
600
608
|
const rooms = roomsEnum['enum.rooms'] || {};
|
|
601
609
|
for (const room of Object.keys(rooms)) {
|
|
602
610
|
if (!rooms.hasOwnProperty(room) ||
|
|
@@ -606,11 +614,11 @@ class Commands {
|
|
|
606
614
|
) {
|
|
607
615
|
continue;
|
|
608
616
|
}
|
|
609
|
-
if (rooms[room].common.members.includes(
|
|
610
|
-
|
|
617
|
+
if (rooms[room].common.members.includes(deviceObject._id)) {
|
|
618
|
+
deviceObject.rooms.push(rooms[room].common.name);
|
|
611
619
|
}
|
|
612
620
|
}
|
|
613
|
-
PromiseChain.push(this.fillInfo(
|
|
621
|
+
PromiseChain.push(this.fillInfo(deviceObject, entity, all_stateDefs.filter(item => item._id.startsWith(deviceObject._id)),all_states, models));
|
|
614
622
|
}
|
|
615
623
|
if (!id) {
|
|
616
624
|
for (const client of this.zbController.getClientIterator(true)) {
|
|
@@ -756,6 +764,28 @@ class Commands {
|
|
|
756
764
|
return;
|
|
757
765
|
}
|
|
758
766
|
this.info(`${force ? 'Force removing' : 'Gracefully removing '} device ${devId} from the network.`);
|
|
767
|
+
/*
|
|
768
|
+
|
|
769
|
+
// if with force, remove device and object in parallel;
|
|
770
|
+
const PromiseArr = [ this.zbController.remove(sysid, force) ]
|
|
771
|
+
if (force) PromiseArr.push( this.stController.deleteObj(devId));
|
|
772
|
+
|
|
773
|
+
const results = await Promise.all(PromiseArr);
|
|
774
|
+
const msgs = [];
|
|
775
|
+
for (const result of results) {
|
|
776
|
+
if (!result.status) msgs.push(result.message ? result.message : 'failed without message');
|
|
777
|
+
}
|
|
778
|
+
if (msgs.length == 0 && !force) {
|
|
779
|
+
const result = await this.stController.deleteObj(devId);
|
|
780
|
+
if (!result.status) msgs.push(result.message ? result.message : 'failed without message');
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
const removeResult = this.zbController.remove(sysid, force);
|
|
784
|
+
if (removeResult.status || force) {
|
|
785
|
+
this.info('Device removed from the network, deleting objects.')
|
|
786
|
+
|
|
787
|
+
}
|
|
788
|
+
*/
|
|
759
789
|
this.zbController.remove(sysid, force, async (err) => {
|
|
760
790
|
if (!err) {
|
|
761
791
|
this.info('Device removed from the network, deleting objects.')
|
|
@@ -780,9 +810,10 @@ class Commands {
|
|
|
780
810
|
}
|
|
781
811
|
}
|
|
782
812
|
|
|
783
|
-
async cleanDeviceStates(from, command,
|
|
784
|
-
this.info(`State cleanup
|
|
785
|
-
const devicesFromDB = await this.zbController.
|
|
813
|
+
async cleanDeviceStates(from, command, force, callback) {
|
|
814
|
+
this.info(`State cleanup ${force ? 'including' : 'omitting'} states with custom configuration`);
|
|
815
|
+
const devicesFromDB = await this.zbController.getClientIterator(false);
|
|
816
|
+
const groupsFromDb = await this.zbController.getGroups();
|
|
786
817
|
const messages = [];
|
|
787
818
|
this.stController.CleanupRequired(false);
|
|
788
819
|
|
|
@@ -791,14 +822,26 @@ class Commands {
|
|
|
791
822
|
|
|
792
823
|
if (entity) {
|
|
793
824
|
const model = (entity.mapped) ? entity.mapped.model : entity.device.modelID;
|
|
794
|
-
this.stController.deleteOrphanedDeviceStates(device.ieeeAddr, model,
|
|
825
|
+
this.stController.deleteOrphanedDeviceStates(device.ieeeAddr, model, force, (msg)=> { messages.push(msg)});
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
try {
|
|
829
|
+
for (const group of groupsFromDb) {
|
|
830
|
+
this.stController.deleteOrphanedDeviceStates(group.id, 'group', force, (msg)=> { messages.push(msg)});
|
|
795
831
|
}
|
|
796
832
|
}
|
|
797
|
-
|
|
798
|
-
|
|
833
|
+
catch (error) {
|
|
834
|
+
this.error(`error checking groups for deletable states: ${error?.message}`);
|
|
835
|
+
}
|
|
799
836
|
this.adapter.sendTo(from, command, {stateList: messages}, callback);
|
|
800
837
|
}
|
|
801
838
|
|
|
839
|
+
async rebuildDeviceStates(from, command, force, callback) {
|
|
840
|
+
this.info(`State cleanup ${force ? 'with' : 'without'} overriding changed roles`);
|
|
841
|
+
await this.adapter.syncAllDeviceStates(force);
|
|
842
|
+
this.adapter.sendTo(from, command, {}, callback);
|
|
843
|
+
}
|
|
844
|
+
|
|
802
845
|
async getChannels(from, command, message, callback) {
|
|
803
846
|
if (this.zbController && this.zbController.herdsmanStarted) {
|
|
804
847
|
const result = await this.zbController.getChannelsEnergy();
|
|
@@ -818,6 +861,7 @@ class Commands {
|
|
|
818
861
|
const id = msg.id;
|
|
819
862
|
const targetstate = msg.deactivated;
|
|
820
863
|
this.stController.setDeviceActivated(id, targetstate);
|
|
864
|
+
this.zbController.setDeviceEnable(id, targetstate);
|
|
821
865
|
this.adapter.sendTo(from, command, {}, callback);
|
|
822
866
|
}
|
|
823
867
|
}
|
|
@@ -901,7 +945,7 @@ class Commands {
|
|
|
901
945
|
[{'device': entity.device, 'type': 'deviceOptionsChanged', from: entity.options, to:newOptions || {}, }, entity.mapped]);
|
|
902
946
|
}
|
|
903
947
|
}
|
|
904
|
-
this.
|
|
948
|
+
this.debug(`enumerating data: ${JSON.stringify(prop)}`);
|
|
905
949
|
let val = msg.data[prop];
|
|
906
950
|
if (typeof val === 'string') {
|
|
907
951
|
val = val.trim();
|
package/lib/exclude.js
CHANGED