iobroker.zigbee 1.8.22 → 1.8.24
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 +6 -0
- package/admin/admin.js +4 -1
- package/admin/index.html +4 -0
- package/admin/index_m.html +4 -0
- package/admin/tab_m.html +4 -0
- package/io-package.json +41 -40
- package/lib/backup.js +3 -3
- package/lib/commands.js +24 -24
- package/lib/devices.js +1 -1
- package/lib/exposes.js +2 -2
- package/lib/groups.js +4 -4
- package/lib/states.js +6 -6
- package/lib/statescontroller.js +3 -3
- package/lib/utils.js +4 -4
- package/lib/zbDeviceConfigure.js +3 -1
- package/lib/zigbeecontroller.js +22 -17
- package/main.js +94 -75
- package/package.json +8 -8
- package/support/docgen.js +2 -2
package/README.md
CHANGED
|
@@ -134,6 +134,12 @@ You can thank the authors by these links:
|
|
|
134
134
|
-----------------------------------------------------------------------------------------------------
|
|
135
135
|
|
|
136
136
|
## Changelog
|
|
137
|
+
### 1.8.24 (2023-09-05)
|
|
138
|
+
* (arteck) switch to exposes tab for some Aqara Devices
|
|
139
|
+
|
|
140
|
+
### 1.8.23 (2023-08-10)
|
|
141
|
+
* (arteck) query from xiaomi is now better
|
|
142
|
+
|
|
137
143
|
### 1.8.22 (2023-08-05)
|
|
138
144
|
* (arteck) crash when meta is empty
|
|
139
145
|
|
package/admin/admin.js
CHANGED
|
@@ -31,7 +31,7 @@ const updateCardInterval = setInterval(updateCardTimer, 6000);
|
|
|
31
31
|
|
|
32
32
|
const savedSettings = [
|
|
33
33
|
'port', 'panID', 'channel', 'disableLed', 'countDown', 'groups', 'extPanID', 'precfgkey', 'transmitPower',
|
|
34
|
-
'adapterType', 'debugHerdsman', 'disableBackup', 'disablePing', 'external', 'startWithInconsistent',
|
|
34
|
+
'adapterType', 'debugHerdsman', 'disableBackup', 'disablePing', 'external', 'startWithInconsistent', 'warnOnDeviceAnnouncement'
|
|
35
35
|
];
|
|
36
36
|
|
|
37
37
|
function getDeviceByID(ID) {
|
|
@@ -799,6 +799,9 @@ function load(settings, onChange) {
|
|
|
799
799
|
if (settings.disablePing === undefined) {
|
|
800
800
|
settings.disablePing = false;
|
|
801
801
|
}
|
|
802
|
+
if (settings.warnOnDeviceAnnouncement === undefined) {
|
|
803
|
+
settings.warnOnDeviceAnnouncement = true;
|
|
804
|
+
}
|
|
802
805
|
|
|
803
806
|
// example: select elements with id=key and class=value and insert value
|
|
804
807
|
for (const key in settings) {
|
package/admin/index.html
CHANGED
|
@@ -109,6 +109,10 @@
|
|
|
109
109
|
<input id="disableQueue" type="checkbox" class="value" />
|
|
110
110
|
<label class="translate" for="disableQueue">Disable Queue</label>
|
|
111
111
|
</div>
|
|
112
|
+
<div class="input-field col s2 m2 l2">
|
|
113
|
+
<input id="warnOnDeviceAnnouncement" type="checkbox" class="value" />
|
|
114
|
+
<label class="translate" for="warnOnDeviceAnnouncement">Log warning on Zigbee device announcement</label>
|
|
115
|
+
</div>
|
|
112
116
|
</div>
|
|
113
117
|
</div>
|
|
114
118
|
</div>
|
package/admin/index_m.html
CHANGED
|
@@ -689,6 +689,10 @@
|
|
|
689
689
|
<input id="debugHerdsman" type="checkbox" class="value"/>
|
|
690
690
|
<label class="translate" for="debugHerdsman">Zigbee-herdsman debug info</label>
|
|
691
691
|
</div>
|
|
692
|
+
<div class="input-field col s12 m6 l4 col-warnOnDeviceAnnouncement">
|
|
693
|
+
<input id="warnOnDeviceAnnouncement" type="checkbox" class="value"/>
|
|
694
|
+
<label class="translate" for="warnOnDeviceAnnouncement">Log warning on Zigbee device announcement</label>
|
|
695
|
+
</div>
|
|
692
696
|
<div class="input-field col s12 m6 l4">
|
|
693
697
|
<a id="reset-btn" class="waves-effect waves-light white-text btn-large translate">Reset...</a>
|
|
694
698
|
</div>
|
package/admin/tab_m.html
CHANGED
|
@@ -605,6 +605,10 @@
|
|
|
605
605
|
<input id="disablePing" type="checkbox" class="value" />
|
|
606
606
|
<label class="translate" for="disablePing">Disable active availability check</label>
|
|
607
607
|
</div>
|
|
608
|
+
<div class="input-field col s12 m6 l4 col-warnOnDeviceAnnouncement">
|
|
609
|
+
<input id="warnOnDeviceAnnouncement" type="checkbox" class="value" />
|
|
610
|
+
<label class="translate" for="warnOnDeviceAnnouncement">Log warning on Zigbee device announcement</label>
|
|
611
|
+
</div>
|
|
608
612
|
<div class="input-field col s12 m6 l8 col-transmitPower">
|
|
609
613
|
<select id="transmitPower" class="value" >
|
|
610
614
|
<option value="" disabled selected class="translate">transmitPower</option>
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "zigbee",
|
|
4
|
-
"version": "1.8.
|
|
4
|
+
"version": "1.8.24",
|
|
5
5
|
"news": {
|
|
6
|
+
"1.8.24": {
|
|
7
|
+
"en": "switch to exposes tab for some Aqara Devices",
|
|
8
|
+
"de": "schalter, um die Registerkarte für einige Aqara-Geräte freizusetzen",
|
|
9
|
+
"ru": "перейти на вкладку exposes для некоторых устройств Aqara",
|
|
10
|
+
"pt": "mudar para expor guia para alguns dispositivos Aqara",
|
|
11
|
+
"nl": "vertaling:",
|
|
12
|
+
"fr": "commutation pour exposer l'onglet pour certains appareils Aqara",
|
|
13
|
+
"it": "interruttore per esporre la scheda per alcuni dispositivi Aqara",
|
|
14
|
+
"es": "interruptor para exponer ficha para algunos dispositivos Aqara",
|
|
15
|
+
"pl": "zamienił tablicę dla niektórych Aqara Devices",
|
|
16
|
+
"uk": "перемикач для установки для деяких пристроїв Aqara",
|
|
17
|
+
"zh-cn": "对某些Aqara Devic的表格的转换"
|
|
18
|
+
},
|
|
19
|
+
"1.8.23": {
|
|
20
|
+
"en": "query from xiaomi is now better",
|
|
21
|
+
"de": "anfrage von xiaomi ist jetzt besser",
|
|
22
|
+
"ru": "запрос от xiaomi теперь лучше",
|
|
23
|
+
"pt": "consulta de xiaomi é agora melhor",
|
|
24
|
+
"nl": "quee van xiaomi is nu beter",
|
|
25
|
+
"fr": "la question de xiaomi est maintenant mieux",
|
|
26
|
+
"it": "query da xiaomi è ora meglio",
|
|
27
|
+
"es": "la consulta de xiaomi ahora es mejor",
|
|
28
|
+
"pl": "wykorzystywanie z xiaomi jest obecnie lepsze",
|
|
29
|
+
"uk": "запиту від xiaomi тепер краще",
|
|
30
|
+
"zh-cn": "来自米亚米的询问现在更好。"
|
|
31
|
+
},
|
|
6
32
|
"1.8.22": {
|
|
7
33
|
"en": "crash when meta is empty",
|
|
8
34
|
"de": "crash, wenn meta leer ist",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "wadliwość i błąd\n",
|
|
68
94
|
"uk": "маленька фіксація відправлень і журнал помилок\n",
|
|
69
95
|
"zh-cn": "很少发送过材料和错误逻辑\n"
|
|
70
|
-
},
|
|
71
|
-
"1.8.17": {
|
|
72
|
-
"en": "sentry corr",
|
|
73
|
-
"de": "versand",
|
|
74
|
-
"ru": "сендри корр",
|
|
75
|
-
"pt": "corante de sentinela",
|
|
76
|
-
"nl": "vertaling:",
|
|
77
|
-
"fr": "corr",
|
|
78
|
-
"it": "cor",
|
|
79
|
-
"es": "centry corr",
|
|
80
|
-
"pl": "kor",
|
|
81
|
-
"uk": "кофрів",
|
|
82
|
-
"zh-cn": "发信"
|
|
83
|
-
},
|
|
84
|
-
"1.8.16": {
|
|
85
|
-
"en": "battery corr",
|
|
86
|
-
"de": "batterie korrektor",
|
|
87
|
-
"ru": "аккумулятор корр",
|
|
88
|
-
"pt": "corante da bateria",
|
|
89
|
-
"nl": "batterij corr",
|
|
90
|
-
"fr": "batterie",
|
|
91
|
-
"it": "batteria corpo",
|
|
92
|
-
"es": "batería corrido",
|
|
93
|
-
"pl": "baterie",
|
|
94
|
-
"uk": "акумулятор",
|
|
95
|
-
"zh-cn": "电池组"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
|
@@ -188,8 +188,8 @@
|
|
|
188
188
|
"condition": {
|
|
189
189
|
"operand": "and",
|
|
190
190
|
"rules": [
|
|
191
|
-
"oldVersion<=1.
|
|
192
|
-
"newVersion>=1.
|
|
191
|
+
"oldVersion<=1.8.22",
|
|
192
|
+
"newVersion>=1.8.24"
|
|
193
193
|
]
|
|
194
194
|
},
|
|
195
195
|
"title": {
|
|
@@ -205,16 +205,16 @@
|
|
|
205
205
|
"zh-cn": "重要通知!"
|
|
206
206
|
},
|
|
207
207
|
"text": {
|
|
208
|
-
"en": "This new version
|
|
209
|
-
"
|
|
210
|
-
"
|
|
211
|
-
"
|
|
212
|
-
"
|
|
213
|
-
"
|
|
214
|
-
"
|
|
215
|
-
"
|
|
216
|
-
"
|
|
217
|
-
"zh-cn": "
|
|
208
|
+
"en": "This new version use exposes for Aqara Button WXKG01LM. Plz select this device into exposes/Auschliessen tab",
|
|
209
|
+
"ru": "Эта новая версия использует экспозиции для Aqara Button WXKG01LM. Пожалуйста, выберите это устройство в exposes/Auschliessen tab",
|
|
210
|
+
"pt": "Esta nova versão usa expões para Aqara Button WXKG01LM. Por favor, selecione este dispositivo no separador exposes/Auschliessen",
|
|
211
|
+
"nl": "Deze nieuwe versie gebruikt blootstellingen voor Aqara Button WXK01LM. Kies alsjeblieft dit apparaat uit in de openbare aanklagers",
|
|
212
|
+
"fr": "Cette nouvelle version utilise pour Aqara Button WXKG01LM. Veuillez sélectionner cet appareil dans l'onglet Affichage/Auschliessen",
|
|
213
|
+
"it": "Questa nuova versione utilizza per Aqara Button WXKG01LM. Si prega di selezionare questo dispositivo per exposes/Auschliessen scheda",
|
|
214
|
+
"es": "Este nuevo uso expone para Aqara Button WXKG01LM. Por favor, seleccione este dispositivo en la pestaña exposes/Auschliessen",
|
|
215
|
+
"pl": "Nowa wersja została udostępniona dla zmian Aqary Button WXKG01LM. Prosze dodać to do exposes/Auschliessen tabsena",
|
|
216
|
+
"uk": "Ця нова версія використовується для кнопки Aqara Button WXKG01LM. Будь ласка, оберіть цей пристрій у вкладці ",
|
|
217
|
+
"zh-cn": "这一新版本用于Aqara Button WXKG01LM。 请选择这一装置暴露/Auschliessen tab"
|
|
218
218
|
},
|
|
219
219
|
"link": "https://github.com/ioBroker/ioBroker.zigbee/blob/master/README.md",
|
|
220
220
|
"level": "warn",
|
|
@@ -250,7 +250,8 @@
|
|
|
250
250
|
"disablePing": false,
|
|
251
251
|
"disableBackup": false,
|
|
252
252
|
"external": "",
|
|
253
|
-
"startWithInconsistent": false
|
|
253
|
+
"startWithInconsistent": false,
|
|
254
|
+
"warnOnDeviceAnnouncement": true
|
|
254
255
|
},
|
|
255
256
|
"instanceObjects": [
|
|
256
257
|
{
|
package/lib/backup.js
CHANGED
|
@@ -93,14 +93,14 @@ class Backup {
|
|
|
93
93
|
if (fs.existsSync(dir)) {
|
|
94
94
|
const directoryContent = fs.readdirSync(dir);
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
const files = directoryContent.filter((filename) => {
|
|
97
97
|
if (filename.indexOf('gz') > 0) {
|
|
98
98
|
return fs.statSync(`${dir}/${filename}`).isFile();
|
|
99
99
|
}
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
files.sort((a, b) => {
|
|
103
|
+
const aStat = fs.statSync(`${dir}/${a}`),
|
|
104
104
|
bStat = fs.statSync(`${dir}/${b}`);
|
|
105
105
|
|
|
106
106
|
return new Date(bStat.birthtime).getTime() - new Date(aStat.birthtime).getTime();
|
package/lib/commands.js
CHANGED
|
@@ -116,31 +116,31 @@ class Commands {
|
|
|
116
116
|
if (this.zbController) {
|
|
117
117
|
let devId = '';
|
|
118
118
|
if (message) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
119
|
+
if (message.id) devId = getZbId(message.id);
|
|
120
|
+
if (message.code) {
|
|
121
|
+
try {
|
|
122
|
+
this.debug(`letsPairing called with code ${message.code}`);
|
|
123
|
+
const success = await this.zbController.addPairingCode(message.code);
|
|
124
|
+
if (!success) {
|
|
125
|
+
this.adapter.sendTo(
|
|
126
|
+
from, command,
|
|
127
|
+
{error: 'Pairing code rejected by Coordinator!'},
|
|
128
|
+
callback
|
|
129
|
+
);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
this.error(JSON.stringify(e));
|
|
135
|
+
this.adapter.sendTo(
|
|
136
|
+
from, command,
|
|
137
|
+
{error: 'Exception when trying to add QR code'},
|
|
138
|
+
callback
|
|
139
|
+
);
|
|
140
|
+
return;
|
|
141
141
|
|
|
142
|
+
}
|
|
142
143
|
}
|
|
143
|
-
}
|
|
144
144
|
}
|
|
145
145
|
// allow devices to join the network within 60 secs
|
|
146
146
|
this.adapter.logToPairing('Pairing started ' + devId, true);
|
|
@@ -307,7 +307,7 @@ class Commands {
|
|
|
307
307
|
}
|
|
308
308
|
}
|
|
309
309
|
devInfo.paired = !!devInfo.info;
|
|
310
|
-
// devInfo.groups = groups[devInfo._id];
|
|
310
|
+
// devInfo.groups = groups[devInfo._id];
|
|
311
311
|
devices.push(devInfo);
|
|
312
312
|
}
|
|
313
313
|
return devices;
|
package/lib/devices.js
CHANGED
|
@@ -3092,7 +3092,7 @@ const groupStates = [states.brightness_step].concat(lightStatesWithColor);
|
|
|
3092
3092
|
function getByModel() {
|
|
3093
3093
|
const byModel = new Map();
|
|
3094
3094
|
for (const device of devices) {
|
|
3095
|
-
for (const model of device.models) {
|
|
3095
|
+
for (const model of device.models) {
|
|
3096
3096
|
const stripModel = model.replace(/\0.*$/g, '').trim();
|
|
3097
3097
|
byModel.set(stripModel, device);
|
|
3098
3098
|
}
|
package/lib/exposes.js
CHANGED
|
@@ -873,7 +873,7 @@ function applyExposes(mappedDevices, byModel, allExcludesObj) {
|
|
|
873
873
|
// create or update device from exposes
|
|
874
874
|
for (const deviceDef of zigbeeHerdsmanConverters.definitions) {
|
|
875
875
|
applyDeviceDef(mappedDevices, byModel, allExcludesStr, deviceDef);
|
|
876
|
-
|
|
876
|
+
|
|
877
877
|
if (deviceDef.hasOwnProperty('whiteLabel')) {
|
|
878
878
|
for (const deviceWhiteLabel of deviceDef.whiteLabel) {
|
|
879
879
|
applyDeviceDef(mappedDevices, byModel, allExcludesStr, {
|
|
@@ -881,7 +881,7 @@ function applyExposes(mappedDevices, byModel, allExcludesObj) {
|
|
|
881
881
|
model: deviceWhiteLabel.model,
|
|
882
882
|
vendor: deviceWhiteLabel.vendor,
|
|
883
883
|
description: deviceWhiteLabel.description || deviceDef.description,
|
|
884
|
-
});
|
|
884
|
+
});
|
|
885
885
|
}
|
|
886
886
|
}
|
|
887
887
|
}
|
package/lib/groups.js
CHANGED
|
@@ -123,7 +123,7 @@ class Groups {
|
|
|
123
123
|
try {
|
|
124
124
|
const groups = message && message.groups ? message.groups : {};
|
|
125
125
|
const devId = message && message.id ? message.id : undefined;
|
|
126
|
-
this.warn('updateGroupMembership called with ' + JSON.stringify(devId))
|
|
126
|
+
this.warn('updateGroupMembership called with ' + JSON.stringify(devId));
|
|
127
127
|
if (devId === undefined) {
|
|
128
128
|
this.adapter.sendTo(from, command, {error: 'No device specified'}, callback);
|
|
129
129
|
}
|
|
@@ -138,7 +138,7 @@ class Groups {
|
|
|
138
138
|
for (const gpid of groups[epid]) {
|
|
139
139
|
const gpidn = parseInt(gpid);
|
|
140
140
|
if (gpidn < 0) {
|
|
141
|
-
this.warn(`calling removeDevFromGroup with ${sysid}, ${-gpidn}, ${epid}` )
|
|
141
|
+
this.warn(`calling removeDevFromGroup with ${sysid}, ${-gpidn}, ${epid}` );
|
|
142
142
|
const response = await this.zbController.removeDevFromGroup(sysid, (-gpidn), epid);
|
|
143
143
|
if (response && response.error) {
|
|
144
144
|
errors.push(response.error);
|
|
@@ -146,7 +146,7 @@ class Groups {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
} else if (gpidn > 0) {
|
|
149
|
-
this.warn(`calling addDevToGroup with ${sysid}, ${gpidn}, ${epid}` )
|
|
149
|
+
this.warn(`calling addDevToGroup with ${sysid}, ${gpidn}, ${epid}` );
|
|
150
150
|
const response = await this.zbController.addDevToGroup(sysid, (gpidn), epid);
|
|
151
151
|
if (response && response.error) {
|
|
152
152
|
errors.push(response.error);
|
|
@@ -158,7 +158,7 @@ class Groups {
|
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
} catch (e) {
|
|
161
|
-
this.warn('caught error ' + JSON.stringify(e) + ' in updateGroupMembership')
|
|
161
|
+
this.warn('caught error ' + JSON.stringify(e) + ' in updateGroupMembership');
|
|
162
162
|
this.adapter.sendTo(from, command, {error: e}, callback);
|
|
163
163
|
return;
|
|
164
164
|
}
|
package/lib/states.js
CHANGED
|
@@ -5828,10 +5828,10 @@ const states = {
|
|
|
5828
5828
|
},
|
|
5829
5829
|
getter: (payload) => {
|
|
5830
5830
|
if (payload && payload.effect && payload.effect.hasOwnProperty('effect')) return payload.effect.effect;
|
|
5831
|
-
return
|
|
5831
|
+
return 'steady';
|
|
5832
5832
|
}
|
|
5833
5833
|
|
|
5834
|
-
|
|
5834
|
+
},
|
|
5835
5835
|
effect_json: {
|
|
5836
5836
|
id: 'effect_json',
|
|
5837
5837
|
name: 'Effect',
|
|
@@ -5958,10 +5958,10 @@ const states = {
|
|
|
5958
5958
|
getter: (payload) => {
|
|
5959
5959
|
if (payload.color) {
|
|
5960
5960
|
const c = payload.color;
|
|
5961
|
-
if (c.hasOwnProperty(
|
|
5962
|
-
|
|
5963
|
-
if (c.hasOwnProperty(
|
|
5964
|
-
|
|
5961
|
+
if (c.hasOwnProperty('h') && c.hasOwnProperty('s') && c.hasOwnProperty('b'))
|
|
5962
|
+
return rgb.hsvToRGBString(c.h, c.s, c.b * 100 / 255);
|
|
5963
|
+
if (c.hasOwnProperty('h') && c.hasOwnProperty('s') && c.hasOwnProperty('v'))
|
|
5964
|
+
return rgb.hsvToRGBString(c.h, c.s, c.v * 100);
|
|
5965
5965
|
}
|
|
5966
5966
|
},
|
|
5967
5967
|
setterOpt: (value, options) => {
|
package/lib/statescontroller.js
CHANGED
|
@@ -142,9 +142,9 @@ class StatesController extends EventEmitter {
|
|
|
142
142
|
callback(result);
|
|
143
143
|
return;
|
|
144
144
|
}
|
|
145
|
-
|
|
146
|
-
const states = devStates.states.filter(statedesc => statedesc.isOption || statedesc.inOptions);
|
|
147
|
-
if (states == null || states == undefined) {
|
|
145
|
+
|
|
146
|
+
const states = devStates.states.filter(statedesc => statedesc.isOption || statedesc.inOptions);
|
|
147
|
+
if (states == null || states == undefined) {
|
|
148
148
|
callback(result);
|
|
149
149
|
return;
|
|
150
150
|
}
|
package/lib/utils.js
CHANGED
|
@@ -138,10 +138,10 @@ function getModelRegEx( model) {
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
function getEntityInfo(entity) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
141
|
+
if (entity) {
|
|
142
|
+
return `Type: ${entity.type} Name: ${entity.name}`;
|
|
143
|
+
}
|
|
144
|
+
return `getEntityInfo: Illegal Entity ${JSON.stringify(entity)}`;
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
exports.secondsToMilliseconds = seconds => seconds * 1000;
|
package/lib/zbDeviceConfigure.js
CHANGED
|
@@ -109,7 +109,9 @@ class DeviceConfigure extends BaseExtension {
|
|
|
109
109
|
this.attempts[device.ieeeAddr] = 0;
|
|
110
110
|
}
|
|
111
111
|
try {
|
|
112
|
-
|
|
112
|
+
if (mappedDevice && device) {
|
|
113
|
+
await this.doConfigure(device, mappedDevice);
|
|
114
|
+
}
|
|
113
115
|
} catch (error) {
|
|
114
116
|
this.sendError(error);
|
|
115
117
|
this.warn(
|
package/lib/zigbeecontroller.js
CHANGED
|
@@ -83,6 +83,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
83
83
|
this.transmitPower = options.transmitPower;
|
|
84
84
|
}
|
|
85
85
|
this.disableLed = options.disableLed;
|
|
86
|
+
this.warnOnDeviceAnnouncement = options.warnOnDeviceAnnouncement;
|
|
86
87
|
|
|
87
88
|
this.debug(`Using zigbee-herdsman with settings: ${JSON.stringify(herdsmanSettings)}`);
|
|
88
89
|
this.herdsman = new ZigbeeHerdsman.Controller(herdsmanSettings, this.adapter.log);
|
|
@@ -319,7 +320,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
319
320
|
this.info(`added code ${code} for pairing`);
|
|
320
321
|
return true;
|
|
321
322
|
}
|
|
322
|
-
|
|
323
|
+
return false;
|
|
323
324
|
}
|
|
324
325
|
|
|
325
326
|
async getGroupMembersFromController(id) {
|
|
@@ -579,7 +580,11 @@ class ZigbeeController extends EventEmitter {
|
|
|
579
580
|
this.debug('handleDeviceAnnounce', message);
|
|
580
581
|
const entity = await this.resolveEntity(message.device || message.ieeeAddr);
|
|
581
582
|
const friendlyName = entity.name;
|
|
582
|
-
this.
|
|
583
|
+
if (this.warnOnDeviceAnnouncement) {
|
|
584
|
+
this.warn(`Device '${friendlyName}' announced itself`);
|
|
585
|
+
} else {
|
|
586
|
+
this.info(`Device '${friendlyName}' announced itself`);
|
|
587
|
+
}
|
|
583
588
|
|
|
584
589
|
try {
|
|
585
590
|
if (entity && entity.mapped) {
|
|
@@ -784,7 +789,7 @@ class ZigbeeController extends EventEmitter {
|
|
|
784
789
|
for (k in this) {
|
|
785
790
|
yield k;
|
|
786
791
|
}
|
|
787
|
-
}
|
|
792
|
+
};
|
|
788
793
|
}
|
|
789
794
|
let result;
|
|
790
795
|
if (cmd === 'configReport') {
|
|
@@ -812,20 +817,20 @@ class ZigbeeController extends EventEmitter {
|
|
|
812
817
|
this.debug(`addDevFromGroup - entity: ${utils.getEntityInfo(entity)}`);
|
|
813
818
|
// generate group debug info and display it
|
|
814
819
|
const members = await this.getGroupMembersFromController(groupId);
|
|
815
|
-
let memberIDs = []
|
|
816
|
-
for (
|
|
817
|
-
|
|
820
|
+
let memberIDs = [];
|
|
821
|
+
for (const member of members) {
|
|
822
|
+
memberIDs.push(member.ieee);
|
|
818
823
|
}
|
|
819
824
|
this.debug(`addDevToGroup ${groupId} with ${memberIDs.length} members ${safeJsonStringify(memberIDs)}`);
|
|
820
825
|
if (epid != undefined) {
|
|
821
826
|
for (const ep of entity.endpoints) {
|
|
822
827
|
this.debug(`checking ep ${ep.ID} of ${devId} (${epid})`);
|
|
823
828
|
if (ep.ID == epid) {
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
+
if (ep.inputClusters.includes(4) || ep.outputClusters.includes(4)) {
|
|
830
|
+
this.debug(`adding endpoint ${ep.ID} (${epid}) to group ${groupId}`);
|
|
831
|
+
await (ep.addToGroup(group.mapped));
|
|
832
|
+
}
|
|
833
|
+
else this.error(`cluster genGroups not supported for endpoint ${epid} of ${devId}`);
|
|
829
834
|
}
|
|
830
835
|
}
|
|
831
836
|
} else {
|
|
@@ -862,9 +867,9 @@ class ZigbeeController extends EventEmitter {
|
|
|
862
867
|
const group = await this.resolveEntity(groupId);
|
|
863
868
|
|
|
864
869
|
const members = await this.getGroupMembersFromController(groupId);
|
|
865
|
-
let memberIDs = []
|
|
866
|
-
for (
|
|
867
|
-
memberIDs.push(member.ieee)
|
|
870
|
+
let memberIDs = [];
|
|
871
|
+
for (const member of members) {
|
|
872
|
+
memberIDs.push(member.ieee);
|
|
868
873
|
}
|
|
869
874
|
|
|
870
875
|
this.debug(`removeDevFromGroup - entity: ${utils.getEntityInfo(entity)}`);
|
|
@@ -872,15 +877,15 @@ class ZigbeeController extends EventEmitter {
|
|
|
872
877
|
|
|
873
878
|
if (epid != undefined) {
|
|
874
879
|
for (const ep of entity.endpoints) {
|
|
875
|
-
|
|
880
|
+
this.debug(`checking ep ${ep.ID} of ${devId} (${epid})`);
|
|
876
881
|
if (ep.ID == epid && (ep.inputClusters.includes(4) || ep.outputClusters.includes(4))) {
|
|
877
882
|
await ep.removeFromGroup(group.mapped);
|
|
878
883
|
this.info(`removing endpoint ${ep.ID} of ${devId} from group ${groupId}`);
|
|
879
884
|
}
|
|
880
885
|
}
|
|
881
886
|
} else {
|
|
882
|
-
|
|
883
|
-
|
|
887
|
+
await entity.endpoint.removeFromGroup(group.mapped);
|
|
888
|
+
this.info(`removing endpoint ${entity.endpoint.ID} of ${devId} from group ${groupId}`);
|
|
884
889
|
}
|
|
885
890
|
} catch (error) {
|
|
886
891
|
this.sendError(error);
|
package/main.js
CHANGED
|
@@ -124,7 +124,7 @@ class Zigbee extends utils.Adapter {
|
|
|
124
124
|
message
|
|
125
125
|
}));
|
|
126
126
|
}
|
|
127
|
-
|
|
127
|
+
|
|
128
128
|
if (typeof error == 'string') {
|
|
129
129
|
Sentry.captureException(new Error(error));
|
|
130
130
|
} else {
|
|
@@ -134,7 +134,7 @@ class Zigbee extends utils.Adapter {
|
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
} catch (err) {
|
|
137
|
-
this.log.error(`SentryError : ${message} ${error} ${err} `);
|
|
137
|
+
this.log.error(`SentryError : ${message} ${error} ${err} `);
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
|
@@ -278,7 +278,7 @@ class Zigbee extends utils.Adapter {
|
|
|
278
278
|
delete toAdd['homeassistant'];
|
|
279
279
|
try {
|
|
280
280
|
zigbeeHerdsmanConverters.addDeviceDefinition(toAdd);
|
|
281
|
-
} catch {
|
|
281
|
+
} catch {
|
|
282
282
|
this.log.error(`unable to apply external converter ${JSON.stringfy(toAdd)}`);
|
|
283
283
|
}
|
|
284
284
|
}
|
|
@@ -465,50 +465,57 @@ class Zigbee extends utils.Adapter {
|
|
|
465
465
|
// this assigment give possibility to use iobroker logger in code of the converters, via meta.logger
|
|
466
466
|
meta.logger = this.log;
|
|
467
467
|
|
|
468
|
-
await this.checkIfModelUpdate(entity);
|
|
469
|
-
|
|
470
|
-
let
|
|
471
|
-
let
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
468
|
+
await this.checkIfModelUpdate(entity);
|
|
469
|
+
|
|
470
|
+
let _voltage = 0;
|
|
471
|
+
let _temperature = 0;
|
|
472
|
+
let _humidity = 0;
|
|
473
|
+
|
|
474
|
+
let isMessure = false;
|
|
475
|
+
let isBattKey = false;
|
|
476
|
+
|
|
477
|
+
if (mappedModel && mappedModel.meta && mappedModel.meta.battery) {
|
|
478
|
+
const isVoltage = mappedModel.meta.battery.hasOwnProperty('voltageToPercentage');
|
|
479
|
+
|
|
480
|
+
if (isVoltage) {
|
|
481
|
+
const keys = Object.keys(message.data);
|
|
482
|
+
|
|
483
|
+
for (const key of keys) {
|
|
484
|
+
const value = message.data[key];
|
|
485
|
+
|
|
486
|
+
if (value && value[1]) {
|
|
487
|
+
if (key == 65282 && value[1][1]) {
|
|
488
|
+
_voltage = value[1][1].elmVal;
|
|
489
|
+
isBattKey = true;
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
if (key == 65281) {
|
|
493
|
+
_voltage = value[1];
|
|
494
|
+
isBattKey = true;
|
|
495
|
+
_temperature = value[100];
|
|
496
|
+
_temperature = _temperature /100;
|
|
497
|
+
_humidity = value[101];
|
|
498
|
+
_humidity = _humidity / 100;
|
|
499
|
+
isMessure = true;
|
|
500
|
+
break;
|
|
498
501
|
}
|
|
499
502
|
}
|
|
500
503
|
}
|
|
501
504
|
}
|
|
502
505
|
}
|
|
503
|
-
|
|
506
|
+
|
|
504
507
|
// always publish link_quality and battery
|
|
505
508
|
if (message.linkquality) { // send battery with
|
|
506
509
|
this.publishToState(devId, model, {linkquality: message.linkquality});
|
|
507
|
-
if (
|
|
508
|
-
this.publishToState(devId, model, {voltage:
|
|
509
|
-
const battProz = zigbeeHerdsmanConvertersUtils.batteryVoltageToPercentage(
|
|
510
|
+
if (isBattKey) {
|
|
511
|
+
this.publishToState(devId, model, {voltage: _voltage});
|
|
512
|
+
const battProz = zigbeeHerdsmanConvertersUtils.batteryVoltageToPercentage(_voltage,entity.mapped.meta.battery.voltageToPercentage);
|
|
510
513
|
this.publishToState(devId, model, {battery: battProz});
|
|
511
514
|
}
|
|
515
|
+
if (isMessure) {
|
|
516
|
+
this.publishToState(devId, model, {temperature: _temperature});
|
|
517
|
+
this.publishToState(devId, model, {humidity: _humidity});
|
|
518
|
+
}
|
|
512
519
|
}
|
|
513
520
|
|
|
514
521
|
// publish raw event to "from_zigbee"
|
|
@@ -540,31 +547,43 @@ class Zigbee extends utils.Adapter {
|
|
|
540
547
|
return;
|
|
541
548
|
}
|
|
542
549
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
+
this.processConverters(converters, devId, model, mappedModel, message, meta)
|
|
551
|
+
// .then(() => {
|
|
552
|
+
//
|
|
553
|
+
// })
|
|
554
|
+
.catch((error) => {
|
|
555
|
+
this.log.error(`Error while processing converters: '${error}'`);
|
|
556
|
+
});
|
|
557
|
+
}
|
|
550
558
|
|
|
559
|
+
async processConverters(converters, devId, model, mappedModel, message, meta) {
|
|
551
560
|
for (const converter of converters) {
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
if (payload) {
|
|
557
|
-
if (Object.keys(payload).length) {
|
|
558
|
-
publish(payload);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
} catch (err) {
|
|
562
|
-
this.log.warn(`convert problem with '${model}' '${devId}' `);
|
|
561
|
+
const publish = (payload) => {
|
|
562
|
+
this.log.debug(`Publish ${safeJsonStringify(payload)} to ${safeJsonStringify(devId)}`);
|
|
563
|
+
if (payload) {
|
|
564
|
+
this.publishToState(devId, model, payload);
|
|
563
565
|
}
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
const options = await new Promise((resolve, reject) => {
|
|
569
|
+
this.stController.collectOptions(devId, model, (options) => {
|
|
570
|
+
resolve(options);
|
|
571
|
+
});
|
|
564
572
|
});
|
|
573
|
+
|
|
574
|
+
const payload = await new Promise((resolve, reject) => {
|
|
575
|
+
const payload = converter.convert(mappedModel, message, publish, options, meta);
|
|
576
|
+
if (payload) {
|
|
577
|
+
resolve(payload);
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
publish(payload);
|
|
565
582
|
}
|
|
566
583
|
}
|
|
567
584
|
|
|
585
|
+
|
|
586
|
+
|
|
568
587
|
publishToState(devId, model, payload) {
|
|
569
588
|
this.stController.publishToState(devId, model, payload);
|
|
570
589
|
}
|
|
@@ -595,20 +614,20 @@ class Zigbee extends utils.Adapter {
|
|
|
595
614
|
}
|
|
596
615
|
try {
|
|
597
616
|
const entity = await this.zbController.resolveEntity(deviceId);
|
|
598
|
-
|
|
617
|
+
|
|
599
618
|
this.log.debug(`entity: ${deviceId} ${model} ${safeJsonStringify(entity)}`);
|
|
600
|
-
|
|
601
|
-
const mappedModel = entity.mapped;
|
|
602
|
-
|
|
619
|
+
|
|
620
|
+
const mappedModel = entity.mapped;
|
|
621
|
+
|
|
603
622
|
if (!mappedModel) {
|
|
604
623
|
this.log.debug(`No mapped model for ${model}`);
|
|
605
624
|
return;
|
|
606
625
|
}
|
|
607
|
-
|
|
626
|
+
|
|
608
627
|
stateList.forEach(async changedState => {
|
|
609
628
|
const stateDesc = changedState.stateDesc;
|
|
610
629
|
const value = changedState.value;
|
|
611
|
-
|
|
630
|
+
|
|
612
631
|
if (stateDesc.id === 'send_payload') {
|
|
613
632
|
try {
|
|
614
633
|
const json_value = JSON.parse(value);
|
|
@@ -623,14 +642,14 @@ class Zigbee extends utils.Adapter {
|
|
|
623
642
|
}
|
|
624
643
|
return;
|
|
625
644
|
}
|
|
626
|
-
|
|
645
|
+
|
|
627
646
|
if (stateDesc.isOption) {
|
|
628
647
|
// acknowledge state with given value
|
|
629
648
|
this.acknowledgeState(deviceId, model, stateDesc, value);
|
|
630
649
|
// process sync state list
|
|
631
650
|
//this.processSyncStatesList(deviceId, modelId, syncStateList);
|
|
632
651
|
// if this is the device query state => trigger the device query
|
|
633
|
-
|
|
652
|
+
|
|
634
653
|
// on activation of the 'device_query' state trigger hardware query where possible
|
|
635
654
|
if (stateDesc.id === 'device_query') {
|
|
636
655
|
if (this.query_device_block.indexOf(deviceId) > -1) {
|
|
@@ -647,7 +666,7 @@ class Zigbee extends utils.Adapter {
|
|
|
647
666
|
await converter.convertGet(entity.device.endpoints[0], ckey, {});
|
|
648
667
|
} catch (error) {
|
|
649
668
|
this.log.warn(`Failed to read state '${JSON.stringify(ckey)}'of '${entity.device.ieeeAddr}' after query with '${JSON.stringify(error)}'`);
|
|
650
|
-
|
|
669
|
+
|
|
651
670
|
}
|
|
652
671
|
}
|
|
653
672
|
}
|
|
@@ -671,7 +690,7 @@ class Zigbee extends utils.Adapter {
|
|
|
671
690
|
this.sendError(`No converter available for '${model}' with key '${stateDesc.id}' `);
|
|
672
691
|
return;
|
|
673
692
|
}
|
|
674
|
-
|
|
693
|
+
|
|
675
694
|
const preparedValue = (stateDesc.setter) ? stateDesc.setter(value, options) : value;
|
|
676
695
|
const preparedOptions = (stateDesc.setterOpt) ? stateDesc.setterOpt(value, options) : {};
|
|
677
696
|
let syncStateList = [];
|
|
@@ -683,11 +702,11 @@ class Zigbee extends utils.Adapter {
|
|
|
683
702
|
}
|
|
684
703
|
});
|
|
685
704
|
}
|
|
686
|
-
|
|
705
|
+
|
|
687
706
|
const epName = stateDesc.epname !== undefined ? stateDesc.epname : (stateDesc.prop || stateDesc.id);
|
|
688
707
|
const key = stateDesc.setattr || stateDesc.prop || stateDesc.id;
|
|
689
708
|
this.log.debug(`convert ${key}, ${safeJsonStringify(preparedValue)}, ${safeJsonStringify(preparedOptions)}`);
|
|
690
|
-
|
|
709
|
+
|
|
691
710
|
let target;
|
|
692
711
|
if (model === 'group') {
|
|
693
712
|
target = entity.mapped;
|
|
@@ -695,9 +714,9 @@ class Zigbee extends utils.Adapter {
|
|
|
695
714
|
target = await this.zbController.resolveEntity(deviceId, epName);
|
|
696
715
|
target = target.endpoint;
|
|
697
716
|
}
|
|
698
|
-
|
|
717
|
+
|
|
699
718
|
this.log.debug(`target: ${safeJsonStringify(target)}`);
|
|
700
|
-
|
|
719
|
+
|
|
701
720
|
const meta = {
|
|
702
721
|
endpoint_name: epName,
|
|
703
722
|
options: preparedOptions,
|
|
@@ -707,11 +726,11 @@ class Zigbee extends utils.Adapter {
|
|
|
707
726
|
logger: this.log,
|
|
708
727
|
state: {},
|
|
709
728
|
};
|
|
710
|
-
|
|
729
|
+
|
|
711
730
|
if (preparedOptions.hasOwnProperty('state')) {
|
|
712
731
|
meta.state = preparedOptions.state;
|
|
713
732
|
}
|
|
714
|
-
|
|
733
|
+
|
|
715
734
|
try {
|
|
716
735
|
const result = await converter.convertSet(target, key, preparedValue, meta);
|
|
717
736
|
this.log.debug(`convert result ${safeJsonStringify(result)}`);
|
|
@@ -721,20 +740,20 @@ class Zigbee extends utils.Adapter {
|
|
|
721
740
|
}
|
|
722
741
|
// process sync state list
|
|
723
742
|
this.processSyncStatesList(deviceId, model, syncStateList);
|
|
724
|
-
|
|
743
|
+
|
|
725
744
|
if (isGroup) {
|
|
726
745
|
await this.callPluginMethod('queryGroupMemberState', [deviceId, stateDesc]);
|
|
727
746
|
this.acknowledgeState(deviceId, model, stateDesc, value);
|
|
728
747
|
}
|
|
729
748
|
}
|
|
730
|
-
|
|
749
|
+
|
|
731
750
|
} catch (error) {
|
|
732
751
|
this.filterError(`Error ${error.code} on send command to ${deviceId}.` +
|
|
733
752
|
` Error: ${error.stack}`, `Send command to ${deviceId} failed with`, error);
|
|
734
753
|
}
|
|
735
754
|
});
|
|
736
755
|
} catch (err) {
|
|
737
|
-
this.log.error(`No entity for ${deviceId}`);
|
|
756
|
+
this.log.error(`No entity for ${deviceId}`);
|
|
738
757
|
}
|
|
739
758
|
}
|
|
740
759
|
|
|
@@ -950,7 +969,7 @@ class Zigbee extends utils.Adapter {
|
|
|
950
969
|
}
|
|
951
970
|
|
|
952
971
|
onPairing(message, data) {
|
|
953
|
-
if (Number.isInteger(data)) {
|
|
972
|
+
if (Number.isInteger(data)) {
|
|
954
973
|
this.setState('info.pairingCountdown', data, true);
|
|
955
974
|
}
|
|
956
975
|
if (data === 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.zigbee",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.24",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Kirov Ilya",
|
|
6
6
|
"email": "kirovilya@gmail.com"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
}
|
|
16
16
|
],
|
|
17
17
|
"engines": {
|
|
18
|
-
"node": ">=
|
|
18
|
+
"node": ">=16"
|
|
19
19
|
},
|
|
20
20
|
"optionalDependencies": {
|
|
21
21
|
"serialport": "^11.0.1"
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@iobroker/adapter-core": "^3.0.3",
|
|
25
25
|
"tar": "^6.1.15",
|
|
26
|
-
"typescript": "^5.
|
|
27
|
-
"zigbee-herdsman": "0.
|
|
28
|
-
"zigbee-herdsman-converters": "15.
|
|
26
|
+
"typescript": "^5.2.2",
|
|
27
|
+
"zigbee-herdsman": "0.18.7",
|
|
28
|
+
"zigbee-herdsman-converters": "15.70.0"
|
|
29
29
|
},
|
|
30
30
|
"description": "Zigbee devices",
|
|
31
31
|
"devDependencies": {
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"@alcalzone/release-script-plugin-license": "^3.5.9",
|
|
35
35
|
"@alcalzone/release-script-plugin-manual-review": "^3.5.9",
|
|
36
36
|
"@iobroker/testing": "^4.1.0",
|
|
37
|
-
"axios": "^1.
|
|
38
|
-
"chai": "^4.3.
|
|
37
|
+
"axios": "^1.5.0",
|
|
38
|
+
"chai": "^4.3.8",
|
|
39
39
|
"chai-as-promised": "^7.1.1",
|
|
40
40
|
"eslint": "^8.46.0",
|
|
41
|
-
"eslint-config-prettier": "^
|
|
41
|
+
"eslint-config-prettier": "^9.0.0",
|
|
42
42
|
"eslint-plugin-prettier": "^5.0.0",
|
|
43
43
|
"gulp": "^4.0.2",
|
|
44
44
|
"gulp-jsdoc3": "^3.0.0",
|
package/support/docgen.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* This script generates the supported devices page.
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
let devices = [...require('zigbee-herdsman-converters').devices];
|
|
@@ -86,7 +86,7 @@ vendors.sort();
|
|
|
86
86
|
text += '| Model | Description | Picture |\n';
|
|
87
87
|
text += '| ------------- | ------------- | -------------------------- |\n';
|
|
88
88
|
vendors.forEach((vendor) => {
|
|
89
|
-
text += `| | **${vendor}** | |\n`;
|
|
89
|
+
text += `| | **${vendor}** | |\n`;
|
|
90
90
|
text += logDevices([...iobDevices.keys()].map((m) => devices.get(m)).filter((d) => d && d.vendor === vendor).map((d) => d.model));
|
|
91
91
|
});
|
|
92
92
|
|