iobroker.zigbee 3.1.5 → 3.1.6

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 CHANGED
@@ -152,6 +152,10 @@ You can thank the authors by these links:
152
152
 
153
153
  -----------------------------------------------------------------------------------------------------
154
154
  ## Changelog
155
+ ### 3.1.6 (2025-10-21)
156
+ * (asgothian) Bugfixes
157
+ *
158
+
155
159
  ### 3.1.5 (2025-10-04)
156
160
  * (asgothian) Bugfixes
157
161
  * (asgothian) ZHC25.36.0
package/admin/admin.js CHANGED
@@ -9,6 +9,7 @@ const Materialize = (typeof M !== 'undefined') ? M : Materialize,
9
9
  namespace = 'zigbee.' + instance,
10
10
  namespaceLen = namespace.length;
11
11
  let devices = [],
12
+ models = [],
12
13
  debugDevices = [],
13
14
  messages = [],
14
15
  map = {},
@@ -17,6 +18,7 @@ let devices = [],
17
18
  network,
18
19
  networkEvents,
19
20
  responseCodes = false,
21
+ localConfigData = {},
20
22
  groups = {},
21
23
  devGroups = {}, // eslint-disable-line prefer-const
22
24
  binding = [],
@@ -180,7 +182,11 @@ function getLQICls(value) {
180
182
 
181
183
  function sanitizeModelParameter(parameter) {
182
184
  const replaceByUnderscore = /[\s/]/g;
183
- return parameter.replace(replaceByUnderscore, '_');
185
+ try {
186
+ return parameter.replace(replaceByUnderscore, '_');
187
+ }
188
+ catch {}
189
+ return parameter;
184
190
  }
185
191
 
186
192
  /////
@@ -189,88 +195,156 @@ function sanitizeModelParameter(parameter) {
189
195
  //
190
196
  ////
191
197
 
198
+ const LocalDataDisplayValues = {
199
+ unfoldedModels : {}, // { plug01: {devices: true/false, options: true/false}}
200
+ unfoldedDevices : {}, // { 0xdeadbeefdeadbeef: true/false}
201
+ buttonSet: new Set(),
202
+ showModels: true,
203
+ }
192
204
 
193
- function getModelData(data) {
194
- console.warn(JSON.stringify(data));
195
- const devicesByModel = {};
196
- for (const dev of data) {
197
- const modelID = dev.info?.mapped?.model || dev.info.device.modelZigbee || dev.info.device.name || 'unknown';
198
- if (devicesByModel[modelID])
199
- devicesByModel[modelID].devices.push(dev);
200
- else devicesByModel[modelID] = {devices:[dev], icon:dev.common.icon};
201
- }
202
- console.warn(JSON.stringify(devicesByModel));
205
+
206
+ function getModelData(data, models) {
203
207
  const Html = [];
204
208
  // Html.push(`<ul class="collapsible">`);
205
- Html.push(`<ul class="collection">`)
206
- for (const key of Object.keys(devicesByModel)) {
207
- const model = devicesByModel[key];
208
- Html.push(`<li class="collection-item avatar>`);
209
- //Html.push(`<li>`)
210
- //Html.push(`<div class="collapsible-header"><img src=${model.iccon} alt="" class="circle" width="40" height="auto">&nbsp;Paired Models</div>`);
211
- //Html.push(`<div class="collapsile-body"<span>${getDeviceData(model.devices)}</span></div>`);
212
- Html.push(`<img src = ${model.iccon} alt="" class="circle" width="40" height="auto">`);
213
- Html.push(`<span class=title></p>`);
214
- Html.push(getDeviceData(model.devices).join('<br>'))
215
- Html.push(`</p><a href="#!" class="secondary-content"><i class="material-icons">grade</i></a></li>`)
216
- }
217
- Html.push('</ul>');
209
+ const s = new Set();
210
+ for (const k of Object.keys(models)) {
211
+ const model = models[k];
212
+ const key = model.model.model;
213
+ console.warn(`getmodeldata: model is ${key}, sO: ${JSON.stringify(model.setOptions)}`);
214
+ const numOptions = Object.keys(model.setOptions).length;
215
+ const foldData = LocalDataDisplayValues.unfoldedModels[k] || { devices:false, options:false};
216
+ let numrows = 1;
217
+ if (foldData.devices) numrows += model.devices.length;
218
+ if (numOptions > 0) numrows += 1;
219
+ if (foldData.options) numrows += numOptions;
220
+ //const numrows = (foldData.devices ? model.devices.length : 0) + (foldData.options ? numOptions : 0) + numOptions > 0 ? 2 : 1;
221
+ console.warn(`numrows is ${numrows} with ${model.devices.length} ${foldData.devices ? 'shown' : 'hidden'} devices and ${numOptions} options ${foldData.options ? 'shown' : 'hidden'}`);
222
+ const d_btn_name = `d_toggle_${k}`;
223
+ const e_btn_name = `m_edit_${k}`;
224
+ const d_btn_tip = `fold / unfold devices of ${key}`;
225
+ const e_btn_tip = `edit model ${key}`;
226
+ const d_btn = btnParam(d_btn_name, d_btn_tip, foldData.devices ? 'expand_less' : 'expand_more', false);
227
+ const e_btn = btnParam(e_btn_name, e_btn_tip, 'edit', 'green', false)
228
+ LocalDataDisplayValues.buttonSet.add(d_btn_name);
229
+ LocalDataDisplayValues.buttonSet.add(e_btn_name);
230
+ Html.push(`<tr id="datarowodd"><td rowspan="${numrows}"><img src = ${model.icon} alt="" width="80" height="auto"></td><td colspan="2">Devices of Model ${key}</td><td>${d_btn}&nbsp;${e_btn}</td></tr>`)
231
+ let cnt = 0;
232
+ if (foldData.devices) {
233
+ for (const dev of model.devices) {
234
+ let devieee = dev._id.replace(`${namespace}.`, '');
235
+
236
+ if (devieee == undefined) devieee = 'unknown' + cnt++;
237
+ const bn = `d_edit_${devieee}`
238
+ Html.push(`<tr id="datarowopt"><td>${devieee}</td><td>${dev.common.name}</td><td>${btnParam(bn, 'edit '+ devieee, 'edit', 'lime', true)}</td></tr>`)
239
+ }
240
+ }
241
+ if (numOptions > 0) {
242
+ const o_btn_name = `o_toggle_${k}`;
243
+ const o_btn_tip = `fold / unfold options for Model ${key}`;
244
+ LocalDataDisplayValues.buttonSet.add(o_btn_name);
245
+ Html.push(`<tr id="dataroweven"></td><td colspan="2">Options for ${key}</td><td>${btnParam(o_btn_name, o_btn_tip, foldData.options ? 'expand_less' : 'expand_more')}</td></tr>`)
246
+ if (foldData.options) {
247
+ for (const key of Object.keys(model.setOptions)) {
248
+ Html.push(`<tr id="dataroweven"><td>${key}</td><td ${model.setOptions[key] === undefined ? 'id="datared">"not set on model"' : '>'+model.setOptions[key]}</td><td>&nbsp;</td></tr>`)
249
+ }
250
+ }
251
+ }
252
+
253
+ }
218
254
  return Html;
219
255
  }
256
+
257
+ function btnParam(id, tooltip, icon, color, disabled) {
258
+ return `<a id="${id}" class="btn-floating waves-effect waves-light right ${color ? color : 'blue'} ${disabled ? 'disabled ' : ''}tooltipped center-align hoverable translateT" title="${tooltip}"><i class="material-icons large">${icon}</i></a>`;
259
+ }
260
+
261
+
220
262
  function getDeviceData(deviceList, withIcon) {
221
- const Html = [`<div class="container">`];
263
+ const Html = [];
222
264
  for (const dev of deviceList) {
223
- const iconLink = `<img src=${dev.common.icon} class="circle" width="40" height="auto">`;
224
- Html.push(`<div="row"><div class="col s4">${withIcon ? iconLink : ''}<br>${dev.info.device.ieee}<br>connectedInfo</div>`)
225
- Html.push(`<div class=col s4>Device Name:${dev.common.name}</div><div class=col s4>Connected: true</div></div>`);
226
- if (dev.options) {
227
- Html.push(`<div="row"><div class="col s3">Options</div>`)
265
+ const rowspan = dev.options ? Object.keys(dev.options).length + 2 : 2;
266
+ const iconLink = `<img src=${dev.common.icon} class="dev_list">`;
267
+ const devieee = dev._id.replace(`${namespace}.`, '');
268
+ const o_btn_name = `do_toggle_${devieee}`;
269
+ const o_btn_tip = `fold / unfold options for ${devieee}`;
270
+ LocalDataDisplayValues.buttonSet.add(o_btn_name);
271
+ const bn = `f_edit_${devieee}`
272
+ LocalDataDisplayValues.buttonSet.add(bn);
273
+
274
+ Html.push(`<tr id="datarowodd"><td rowspan="${rowspan}">${iconLink}</td><td colspan="2">${dev.common.name} (${devieee})</td><td>${btnParam(o_btn_name, o_btn_tip, LocalDataDisplayValues.unfoldedDevices ? 'do_not_disturb' : 'add_circle')}</td></tr>`);
275
+ Html.push(`<tr id="dataroweven"><td colspan="2">Device flags</td><td>${btnParam(bn, 'edit flags','edit')}</td></tr>`);
276
+ //console.warn(`dev is ${JSON.stringify(dev)}`);
277
+ if (dev.options && LocalDataDisplayValues.unfoldedDevices[devieee]) {
228
278
  for (const o of dev.options) {
229
- Html.push(`<div class=col s4>${o.key}</div><div class=col s4>${o.value}</div><div>`);
279
+ const bn = `o_edit_${devieee}.${o.key}`
280
+ LocalDataDisplayValues.buttonSet.add(bn);
281
+ Html.push(`<tr id="datarowopt"><td>${o.key}></td><td>${o.value}</td><td>${btnParam(bn, 'edit flags','edit')}</td></tr>`);
230
282
  }
231
- Html.push(`</div>`);
232
283
  }
233
- Html.push(`</div>`)
234
284
  }
235
- Html.push(`</div>`)
236
285
  return Html;
237
286
  }
238
- function getGlobalOptionData() {
239
- return ['No Data Yet'];
240
- }
241
287
 
242
288
  function showLocalData() {
243
- return;
244
- /*
245
- const Html = [];
289
+ LocalDataDisplayValues.buttonSet.clear();
290
+ const ModelHtml = getModelData(devices, models);
291
+ const DeviceHtml = getDeviceData(devices);
292
+ const sm = LocalDataDisplayValues.showModels;
293
+ const dmtoggle = btnParam('t_all_models', sm ? 'fold Models / show Devices' : 'fold Devices / show Models', !sm ? 'developer_board' : 'devices_other')
246
294
 
247
- Html.push(`<ul class="collapsible">`);
248
- Html.push('<li>')
249
- Html.push (`<li class="active"><div class="collapsible-header">
250
- Paired Models
251
- </div>`);
252
- Html.push (`<div class="collapsible-body">
253
- <span>${getModelData(devices).join('')}</span>
254
- </div>`);
255
- Html.push ('</li><li>')
256
- Html.push (`<div class="collapsible-header">
257
- Paired Devices
258
- </div>`);
259
- Html.push (`<div class="collapsible-body">
260
- <span>${getDeviceData(devices, true).join('')}</span>
261
- </div>`);
262
- Html.push ('</li><li>')
263
- Html.push (`<div class="collapsible-header">
264
- Global Options
265
- </div>`);
266
- Html.push (`<div class="collapsible-body">
267
- <span>${getGlobalOptionData(devices).join('')}</span>
268
- </div>`);
269
- Html.push ('</li>')
270
- Html.push (`</ul>`);
295
+ const RowSpan = sm ? ModelHtml.length +2 : DeviceHtml.length + 2;
296
+ const Html = [];
297
+ if (sm) {
298
+ Html.push(`<table style="width:100%"><tr id="datatable"><th rowspan="${RowSpan}">&nbsp;</th><th colspan=3>Model Data</th><th>${dmtoggle}</th><th rowspan="${RowSpan}">&nbsp;</th></tr>`)
299
+ Html.push(ModelHtml.join(''));
300
+ }
301
+ else {
302
+ Html.push(`<table style="width:100%"><tr id="datatable"><th rowspan="${RowSpan}">&nbsp;</th><th colspan=3>Device Data</th><th>${dmtoggle}</th><th rowspan="${RowSpan}">&nbsp;</th></tr>`)
303
+ Html.push(DeviceHtml.join(''));
304
+ }
305
+ Html.push(`<tr id="datatable"><td colspan="4">Statistics</td></tr>`)
306
+ Html.push('</table>');
271
307
  $('#tab-overrides').html(Html.join(''));
272
- $('.collapsible').collapsible();
273
- */
308
+
309
+ $('#t_all_models').click(function () {
310
+ LocalDataDisplayValues.showModels = !LocalDataDisplayValues.showModels;
311
+ showLocalData();
312
+ });
313
+
314
+ console.warn(`lddv is ${JSON.stringify(LocalDataDisplayValues)}`)
315
+ for (const item of LocalDataDisplayValues.buttonSet) {
316
+ console.warn(`adding click to ${item}`)
317
+ if (item.startsWith('d_toggle_')) $(`#${item}`).click(function () {
318
+ const key = item.substring(9);
319
+ console.warn(`clicked ${item}`);
320
+ if (LocalDataDisplayValues.unfoldedModels.hasOwnProperty(key))
321
+ LocalDataDisplayValues.unfoldedModels[key].devices =! LocalDataDisplayValues.unfoldedModels[key].devices;
322
+ else
323
+ LocalDataDisplayValues.unfoldedModels[key] = { devices:true, options: false };
324
+ showLocalData();
325
+ });
326
+ if (item.startsWith('o_toggle_')) $(`#${item}`).click(function () {
327
+ console.warn(`clicked ${item}`);
328
+ const key = item.substring(9);
329
+ if (LocalDataDisplayValues.unfoldedModels.hasOwnProperty(key))
330
+ LocalDataDisplayValues.unfoldedModels[key].options = !LocalDataDisplayValues.unfoldedModels[key].options;
331
+ else
332
+ LocalDataDisplayValues.unfoldedModels[key] = { devices:false, options: true };
333
+ showLocalData();
334
+ })
335
+ if (item.startsWith('do_toggle_')) $(`#${item}`).click(function () {
336
+ console.warn(`clicked ${item}`);
337
+ const key = item.substring(10);
338
+ if (LocalDataDisplayValues.unfoldedDevices.hasOwnProperty(key))
339
+ LocalDataDisplayValues.unfoldedDevices[key] =! LocalDataDisplayValues.unfoldedDevices[key];
340
+ else
341
+ LocalDataDisplayValues.unfoldedDevices[key] = true;
342
+ showLocalData();
343
+ })
344
+
345
+ }
346
+
347
+
274
348
  }
275
349
 
276
350
  /////
@@ -966,6 +1040,7 @@ function showDevices() {
966
1040
  return room;
967
1041
  }
968
1042
  }).filter((item) => item != undefined));
1043
+ console.warn(`rooms is ${JSON.stringify(allRooms)}`);
969
1044
  const roomSelector = $('#room-filter');
970
1045
  roomSelector.empty();
971
1046
  roomSelector.append(`<li class="device-order-item" data-type="All" tabindex="0"><a class="translate" data-lang="All">All</a></li>`);
@@ -988,12 +1063,14 @@ function showDevices() {
988
1063
 
989
1064
  const element = $('#devices');
990
1065
 
991
- if (element) {
1066
+ if ($('tab-main')) try {
992
1067
  shuffleInstance = devices && devices.length ? new Shuffle(element, {
993
1068
  itemSelector: '.device',
994
1069
  sizer: '.js-shuffle-sizer',
995
1070
  }) : undefined;
996
1071
  doFilter();
1072
+ } catch {
1073
+ // empty.
997
1074
  }
998
1075
 
999
1076
  const getDevName = function (dev_block) {
@@ -1692,55 +1769,31 @@ function getDevices() {
1692
1769
  coordinatorinfo = msg;
1693
1770
  updateStartButton()
1694
1771
  }
1695
- sendToWrapper(namespace, 'getDevices', {}, function (msg) {
1696
- if (msg) {
1697
- devices = msg.devices ? msg.devices : [];
1698
- // check if stashed error messages are sent alongside
1699
- if (msg.clean)
1700
- $('#state_cleanup_btn').removeClass('hide');
1701
- else
1702
- $('#state_cleanup_btn').addClass('hide');
1703
- if (msg.errors && msg.errors.length > 0) {
1704
- $('#show_errors_btn').removeClass('hide');
1705
- errorData = msg.errors;
1706
- }
1707
- else {
1708
- $('#show_errors_btn').addClass('hide');
1709
- }
1710
- let newDebugMessages = false;
1711
-
1712
- //check if debug messages are sent alongside
1713
- if (msg && typeof (msg.debugDevices == 'array')) {
1714
- debugDevices = msg.debugDevices;
1715
- }
1716
- else
1717
- debugDevices = [];
1718
- if (debugMessages.byId) {
1719
- newDebugMessages = true;
1720
- debugMessages.byId = msg;
1721
- if (msg) displayDebugMessages(debugMessages)
1722
- }
1723
- lockout.isActive = false;
1724
- if (msg.error) {
1725
- errorData.push(msg.error);
1726
- isHerdsmanRunning = false;
1727
- } else {
1728
- isHerdsmanRunning = true;
1729
- if (!newDebugMessages) {
1730
- getDebugMessages();
1731
- }
1732
- //getExclude();
1733
- getBinding();
1734
- }
1735
- updateStartButton();
1736
- showDevices();
1737
- showLocalData();
1738
- UpdateAdapterAlive(true)
1772
+ });
1773
+ sendToWrapper(namespace, 'getLocalConfigItems', {getAllData:true}, function(msg) {
1774
+ if (msg.hasOwnProperty('by_id') && msg.hasOwnProperty('by_model'))
1775
+ localConfigData = msg;
1776
+ })
1777
+ sendToWrapper(namespace, 'getDevices', {}, function (msg) {
1778
+ if (msg) {
1779
+ extractDevicesData(msg);
1780
+ if (msg.error) {
1781
+ errorData.push(msg.error);
1782
+ isHerdsmanRunning = false;
1783
+ } else {
1784
+ isHerdsmanRunning = true;
1785
+ getBinding();
1739
1786
  }
1740
- });
1787
+ updateStartButton();
1788
+ showDevices();
1789
+ showLocalData();
1790
+ UpdateAdapterAlive(true)
1791
+ }
1741
1792
  });
1742
1793
  }
1743
1794
 
1795
+
1796
+
1744
1797
  if (lockout.timeoutid) {
1745
1798
  clearTimeout(lockout.timeoutid);
1746
1799
  }
@@ -1753,6 +1806,37 @@ function getDevices() {
1753
1806
 
1754
1807
  }
1755
1808
 
1809
+ function extractDevicesData(msg) {
1810
+ devices = msg.devices ? msg.devices : [];
1811
+ // check if stashed error messages are sent alongside
1812
+ if (msg.clean)
1813
+ $('#state_cleanup_btn').removeClass('hide');
1814
+ else
1815
+ $('#state_cleanup_btn').addClass('hide');
1816
+ if (msg.errors && msg.errors.length > 0) {
1817
+ $('#show_errors_btn').removeClass('hide');
1818
+ errorData = msg.errors;
1819
+ }
1820
+ else {
1821
+ $('#show_errors_btn').addClass('hide');
1822
+ }
1823
+ //check if debug messages are sent alongside
1824
+ if (msg && typeof (msg.debugDevices == 'array')) {
1825
+ debugDevices = msg.debugDevices;
1826
+ }
1827
+ else
1828
+ debugDevices = [];
1829
+ if (debugMessages.byId) {
1830
+ debugMessages.byId = msg;
1831
+ if (msg) displayDebugMessages(debugMessages);
1832
+ }
1833
+ if (msg.models) models = msg.models;
1834
+ lockout.isActive = false;
1835
+
1836
+ }
1837
+
1838
+
1839
+
1756
1840
  function getNamedColors() {
1757
1841
  sendToWrapper(namespace, 'getNamedColors', {}, function(msg) {
1758
1842
  if (msg && typeof msg.colors) {
@@ -3951,20 +4035,22 @@ function sortByTitle(element) {
3951
4035
 
3952
4036
 
3953
4037
  function updateDevice(id) {
3954
- sendToWrapper(namespace, 'getDevice', {id: id}, function (msg) {
3955
- if (msg) {
3956
- const devs = msg.devices;
3957
- if (devs) {
3958
- if (devs.error) {
3959
- showMessage(devs.error, _('Error'));
3960
- } else {
3961
- removeDevice(id);
3962
- devs.forEach(dev => devices.push(dev));
3963
- showDevices();
4038
+ if (devices.length > 0)
4039
+ sendToWrapper(namespace, 'getDevice', {id: id}, function (msg) {
4040
+ if (msg) {
4041
+ const devs = msg.devices;
4042
+ if (devs) {
4043
+ if (devs.error) {
4044
+ showMessage(devs.error, _('Error'));
4045
+ } else {
4046
+ removeDevice(id);
4047
+ devs.forEach(dev => devices.push(dev));
4048
+ showDevices();
4049
+ }
3964
4050
  }
3965
4051
  }
3966
- }
3967
- });
4052
+ });
4053
+ else sendToWrapper(namespace, 'getDevices', {}, extractDevicesData)
3968
4054
  }
3969
4055
 
3970
4056
  function removeDevice(id) {
File without changes
@@ -326,6 +326,19 @@
326
326
  #map {
327
327
  margin: 0px;
328
328
  }
329
+ .dev_list {
330
+ display: block;
331
+ margin-left: auto;
332
+ margin-right: auto;
333
+ width: 80px;
334
+ }
335
+
336
+ #dataroweven { background-color: #909090; color: #c0c0c0 !important; }
337
+ #datarowodd { background-color: #c0c0c0; color: #202020 !important; }
338
+ #datarowopt { background-color: #707070; color: #c0c0c0 !important; }
339
+ #datatable { background-color: #3090c0; color: #202020 !important; }
340
+ #datared { color: #C00000 !important;}
341
+ #datalime { background-color: #cddc31; color: #c00000 !important;}
329
342
 
330
343
  #tab-main .main-toolbar-table .filter-input {
331
344
  display: inline-table;
@@ -633,6 +646,7 @@
633
646
 
634
647
  }
635
648
 
649
+
636
650
  .move-label-up {
637
651
  position: absolute !important;
638
652
  top: -60px !important;
File without changes
File without changes
File without changes
package/io-package.json CHANGED
@@ -1,8 +1,21 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "zigbee",
4
- "version": "3.1.5",
4
+ "version": "3.1.6",
5
5
  "news": {
6
+ "3.1.6": {
7
+ "en": "Bugfixes\n",
8
+ "de": "Bugfixes\n",
9
+ "ru": "Багфиксы\n",
10
+ "pt": "Correcções de Erros\n",
11
+ "nl": "Bugfixes\n",
12
+ "fr": "Fixes de bogue\n",
13
+ "it": "Bugfix\n",
14
+ "es": "Bugfixes\n",
15
+ "pl": "Korekty błędów\n",
16
+ "uk": "Помилки\n",
17
+ "zh-cn": "错误修正\n"
18
+ },
6
19
  "3.1.5": {
7
20
  "en": "Bugfixes\nZHC25.36.0\nreduced stopTimeout to 5s",
8
21
  "de": "Bugfixes\nZHC25.36.0\nreduzierter StopTimeout auf 5s",
@@ -80,19 +93,6 @@
80
93
  "pl": "poprawianie obrazów",
81
94
  "uk": "фіксувати зображення",
82
95
  "zh-cn": "修正图像"
83
- },
84
- "3.0.1": {
85
- "en": "Fix for Ikea SOMRIG configuration raising 'definition.endpoint is not a function' error.\nAccess to 'zigbee2mqtt options as settings in zigbee adapter (ALPHA Stage !)\nFix for 'error: zigbee.0 (1118300) zigbee.0 already running' at adapter start (Alpha Stage)\nUpdated hardware configuration panel - exchanged text buttons for buttons with icons.\nLimited states on device tiles to states which are read only or which can be modified sensibly via the device tile.\n",
86
- "de": "Fix für Ikea SOMRIG Konfiguration erhöhen 'Definition. Endpoint ist kein Funktionsfehler.\nZugriff auf 'zigbee2mqtt Optionen als Einstellungen im Zickbee Adapter (ALPHA Stage!)\nFix für 'error: zigbee.0 (1118300) zigbee.0 bereits läuft' bei Adapterstart (Alpha Stage)\nAktualisiertes Hardware-Konfigurationsfeld - ausgetauschte Texttasten für Tasten mit Symbolen.\nBegrenzte Zustände auf Gerätefliesen zu Zuständen, die nur gelesen werden oder über die Gerätefliese sensibel modifiziert werden können.\n",
87
- "ru": "Исправьте конфигурацию IKEA SOMRIG, повысив «определение». Конечная точка не является ошибкой функции.\nДоступ к опциям Zigbee2mqtt в качестве настроек в адаптере Zigbee (стадия ALPHA!)\nИсправьте ошибку: zigbee.0 (1118300) zigbee.0 уже работает на старте адаптера\nОбновленная аппаратная панель конфигурации - обмен текстовыми кнопками на кнопки с иконками.\nОграниченные состояния на плитках устройства к состояниям, которые читаются только или которые могут быть изменены чувственно через плитку устройства.\n",
88
- "pt": "Corrigir para configuração Ikea SOMRIG elevando 'definição. endpoint não é um erro de função.\nAcesso às opções \"zigbee2mqttt como configurações no adaptador zigbee (Estação LAPHA!)\nFix for 'error: zigbee.0 (1118300) zigbee.0 já em execução' no início do adaptador (Alpha Stage)\nPainel de configuração de hardware atualizado - botões de texto trocados para botões com ícones.\nEstados limitados em telhas de dispositivo para estados que são lidos apenas ou que podem ser modificados sensivelmente através da telha do dispositivo.\n",
89
- "nl": "Fix voor Ikea SOMRIG configuratie verhogen 'definitie. eindpunt is geen functiefout.\nToegang tot 'zigbee2mqtt opties als instellingen in zigbee adapter (ALPHA Stage !)\nFix voor 'fout: zigbee.0 (1118300) zigbee.0 al actief' bij adapterstart (Alpha Stage)\nBijgewerkt hardware configuratiepaneel - uitgewisselde tekstknoppen voor knoppen met pictogrammen.\nBeperkte toestanden op apparaattegels naar toestanden die alleen worden gelezen of die verstandig kunnen worden gewijzigd via de apparaattegel.\n",
90
- "fr": "Correction pour la configuration Ikea SOMRIG augmentant la définition. le paramètre n'est pas une erreur de fonction.\nAccès aux options 'zigbee2mqtt comme réglages dans l'adaptateur zigbee (ALPHA Stage !)\nCorrection pour 'erreur: zigbee.0 (1118300) zigbee.0 déjà en cours d'exécution' au démarrage de l'adaptateur (Alpha Stage)\nPanneau de configuration du matériel mis à jour - boutons texte échangés pour les boutons avec des icônes.\nLes états limités sur les tuiles de l'appareil aux états qui sont lus seulement ou qui peuvent être modifiés de façon sensible via la tuile de l'appareil.\n",
91
- "it": "Fissare per Ikea SOMRIG configurazione aumentando 'definizione. endpoint non è un errore di funzione.\nAccesso alle opzioni 'zigbee2mqtt come impostazioni nell'adattatore zigbee (ALPHA Stage !)\nCorrezione per 'error: zigbee.0 (1118300) zigbee.0 già in esecuzione' all'inizio dell'adattatore (Alpha Stage)\nPannello di configurazione hardware aggiornato - pulsanti di testo scambiati per pulsanti con icone.\nStati limitati su piastrelle di dispositivo a stati che sono letti solo o che possono essere modificati sensibilmente tramite la piastrella del dispositivo.\n",
92
- "es": "Arregla para la configuración de Ikea SOMRIG criando 'definición. endpoint no es un error de función.\nAcceso a las opciones 'zigbee2mqtt como configuración en el adaptador de zigbee (ALPHA Stage !)\nFijación para 'error: zigbee.0 (1118300) zigbee.0 ya funcionando en el inicio del adaptador (Alpha Stage)\nPanel de configuración de hardware actualizado - botones de texto intercambiados para botones con iconos.\nEstados limitados en fichas de dispositivo a estados que se leen solamente o que pueden ser modificados de forma sensata a través de la ficha del dispositivo.\n",
93
- "pl": "Napraw dla definicji podnoszenie konfiguracji Ikea SOMRIG. Punkt końcowy nie jest błędem funkcji.\nDostęp do opcji 'zigbee2mqtt jako ustawień w adapterze zigbee (ALPHA Stage!)\nFix for 'error: zigbee.0 (1118300) zigbee.0 already running' at adapter start (Alpha Stage)\nAktualizacja panelu konfiguracji sprzętowej - wymieniono przyciski tekstowe na przyciski z ikonami.\nOgraniczone stany na płytkach urządzenia do stanów, które są tylko odczytywane lub które mogą być modyfikowane w sposób rozsądny za pomocą płytki urządzenia.\n",
94
- "uk": "Виправлення для налаштування Ikea SOMRIG 'Визначення. кінцева точка не є помилкою функції.\nДоступ до опцій Zigbee2mqtt як налаштування адаптера Zigbee (ALPHA Stage !)\nВиправлення для 'error: zigbee.0 (1118300) zigbee.0 вже запущений' при запуску адаптера (Alpha Stage)\nОновлена панель конфігурації обладнання - обмінні текстові кнопки для гудзиків з іконками.\nОбмежені стани на плитці пристрою для станів, які читаються тільки або які можуть бути змінені, швидко через плитку пристрою.\n",
95
- "zh-cn": "修复Ikea SOMRIG 配置提升定义 。 结束点不是一个函数'错误.\n访问 'zigbee2mqtt 选项作为 Zigbee 适配器的设置( ALPHA stage !) \n在适配器启动( Alpha Stage)时为 'error: zigbee. 0 (1118300) zigbee. 0 已经运行' 进行修复\n更新的硬件配置面板 - 用图标交换文本按钮作为按钮.\n将设备瓦片的状态限制在只读或通过设备瓦片可敏感修改的状态.\n"
96
96
  }
97
97
  },
98
98
  "titleLang": {
package/lib/commands.js CHANGED
@@ -339,10 +339,6 @@ class Commands {
339
339
  }
340
340
  }
341
341
 
342
-
343
- async handleDeviceforInfo(device, states) {
344
- }
345
-
346
342
  async handleGroupforInfo(group, groups) {
347
343
  group.icon = 'img/group.png';
348
344
  group.vendor = 'ioBroker';
@@ -379,7 +375,7 @@ class Commands {
379
375
  }
380
376
  }
381
377
 
382
- async fillInfo(device, device_stateDefs, all_states) {
378
+ async fillInfo(device, device_stateDefs, all_states, models) {
383
379
  device.statesDef = (device_stateDefs || []).filter(stateDef => {
384
380
  const sid = stateDef._id.replace(this.adapter.namespace + '.', '');
385
381
  const names = sid.split('.');
@@ -403,7 +399,23 @@ class Commands {
403
399
  });
404
400
 
405
401
  const id = getZbId(device._id);
406
- device.info = this.buildDeviceInfo(await this.zbController.resolveEntity(id));
402
+ const entity = await this.zbController.resolveEntity(id)
403
+
404
+ device.info = this.buildDeviceInfo(entity);
405
+
406
+ const UID = models.UIDbyModel[device.info?.mapped?.model || 'unknown'] || `m_${Object.keys(models.UIDbyModel).length}`;
407
+ if (models.byUID.hasOwnProperty(UID)) {
408
+ models.byUID[UID].devices.push(device);
409
+ }
410
+ else {
411
+ models.byUID[UID] = {
412
+ model:device.info.mapped,
413
+ availableOptions : [...device.info?.mapped?.options || [], ...['use_legacy_model']],
414
+ setOptions: this.adapter.stController.localConfig.getByModel(device.info?.mapped?.model || 'unknown') || [],
415
+ devices: [device],
416
+ }
417
+ models.UIDbyModel[device.info?.mapped?.model || 'unknown'] = UID;
418
+ }
407
419
  // check configuration
408
420
  try {
409
421
  if (device.info) {
@@ -412,13 +424,11 @@ class Commands {
412
424
  [device.info.device, device.info.mapped],
413
425
  );
414
426
  if (result.length > 0) device.isConfigured = !result[0];
415
- }
427
+ device.paired = true;
428
+ } else device.paired = false;
416
429
  } catch (error) {
417
430
  this.warn('error calling shouldConfigure: ' + error && error.message ? error.message : 'no error message');
418
431
  }
419
- device.paired = !!device.info;
420
-
421
-
422
432
  }
423
433
 
424
434
  buildDeviceInfo(device) {
@@ -427,11 +437,11 @@ class Commands {
427
437
  rv.device = {
428
438
  modelZigbee:device.device.modelID,
429
439
  type:device.device.type,
430
- ieee:device.device.ieeeAddr,
431
- nwk:device.device.networkAddress,
440
+ ieee:device.device.ieeeAddr || device.device.groupID,
441
+ nwk:device.device.networkAddress || 0,
432
442
  manuf_id:device.device.maufacturerID,
433
443
  manuf_name:device.device.manufacturerName,
434
- manufacturer:device.mapped ? device.mapped.vendor : '',
444
+ manufacturer:device.mapped?.vendor,
435
445
  power:device.device.powerSource,
436
446
  app_version:device.device.applicationVersion,
437
447
  hard_version:device.device.hardwareVersion,
@@ -462,10 +472,10 @@ class Commands {
462
472
  options:[],
463
473
  }
464
474
  if (device.mapped.options && typeof (device.mapped.options == 'object')) {
465
- const optionDesc = [];
466
475
  for (const option of device.mapped.options) {
467
- if (option.name)
476
+ if (option.name) {
468
477
  rv.mapped.options.push(option.name);
478
+ }
469
479
  }
470
480
  }
471
481
  }
@@ -501,7 +511,7 @@ class Commands {
501
511
  paired: true,
502
512
  info: this.buildDeviceInfo(device),
503
513
  native: { id: device.device.ieeeAddr.substring(2) },
504
- mapped : {},
514
+ mapped : { model:'Coordinator' },
505
515
  statesDev: [],
506
516
  }
507
517
  if (device.device.name === 'Coordinator') {
@@ -513,7 +523,6 @@ class Commands {
513
523
  }
514
524
  devices.push(coordinatorData);
515
525
  }
516
-
517
526
  }
518
527
 
519
528
  async getDevices(from, command, id, callback) {
@@ -522,13 +531,14 @@ class Commands {
522
531
  this.adapter.sendTo(from, command, {error: 'No active connection to Zigbee Hardware!'}, callback);
523
532
  return;
524
533
  }
525
- const rooms = await this.adapter.getEnumsAsync('enum.rooms') || {};
534
+ const roomsEnum = await this.adapter.getEnumsAsync('enum.rooms') || {};
526
535
  const deviceObjects = (id ? [await this.adapter.getObjectAsync(id)] : await this.adapter.getDevicesAsync());
527
536
  const all_states = id ? await this.adapter.getStatesAsync(id + '.*') : await this.adapter.getStatesAsync('*');
528
537
  const all_stateDefs = id ? await this.adapter.getStatesOfAsync(id) : await this.adapter.getStatesOfAsync();
529
538
  const illegalDevices = [];
530
539
  const groups = {};
531
540
  const PromiseChain = [];
541
+ const models = { byUID : {}, UIDbyModel: {} };
532
542
  for (const devInfo of deviceObjects) {
533
543
  if (devInfo._id.indexOf('group') > -1) {
534
544
  PromiseChain.push(this.handleGroupforInfo(devInfo, groups));
@@ -544,22 +554,23 @@ class Commands {
544
554
  devInfo.link_quality_lc = lq_state ? lq_state.lc : undefined;
545
555
  const battery_state = all_states[`${devInfo._id}.battery`];
546
556
  devInfo.battery = battery_state ? battery_state.val : undefined;
547
- devInfo.rooms = [];
548
- for (const room in rooms) {
549
- if (!rooms.hasOwnProperty(room) ||
550
- !rooms[room] ||
551
- !rooms[room].common ||
552
- !rooms[room].common.members
553
- ) {
554
- continue;
555
- }
556
- if (rooms[room].common.members.includes(devInfo._id)) {
557
- devInfo.rooms.push(rooms[room].common.name);
558
- }
559
- }
560
557
 
561
558
  }
562
- PromiseChain.push(this.fillInfo(devInfo, all_stateDefs.filter(item => item._id.startsWith(devInfo._id)),all_states));
559
+ devInfo.rooms = [];
560
+ const rooms = roomsEnum['enum.rooms'] || {};
561
+ for (const room of Object.keys(rooms)) {
562
+ if (!rooms.hasOwnProperty(room) ||
563
+ !rooms[room] ||
564
+ !rooms[room].common ||
565
+ !rooms[room].common.members
566
+ ) {
567
+ continue;
568
+ }
569
+ if (rooms[room].common.members.includes(devInfo._id)) {
570
+ devInfo.rooms.push(rooms[room].common.name);
571
+ }
572
+ }
573
+ PromiseChain.push(this.fillInfo(devInfo, all_stateDefs.filter(item => item._id.startsWith(devInfo._id)),all_states, models));
563
574
  }
564
575
  if (!id) {
565
576
  for (const client of this.zbController.getClientIterator(true)) {
@@ -580,7 +591,12 @@ class Commands {
580
591
 
581
592
  this.debug(`getDevices contains ${deviceObjects.length} Devices`);
582
593
  const rv = { devices:deviceObjects, inLog:this.adapter.deviceDebug.logStatus, }
583
- if (!id) rv.byId = this.adapter.deviceDebug.collectDebugData();
594
+ if (!id) {
595
+ rv.deviceDebugData = this.adapter.deviceDebug.collectDebugData();
596
+ rv.localOverrides = this.adapter.stController.localConfig.localData;
597
+ rv.models = models.byUID;
598
+ }
599
+
584
600
  if (this.stController) {
585
601
  rv.clean = this.stController.CleanupRequired();
586
602
  rv.errors = this.stController.getStashedErrors();
@@ -875,6 +891,9 @@ class Commands {
875
891
  //const targetModel = msg.model ? msg.model : '';
876
892
  }
877
893
  else {
894
+ if (msg.getAllData) {
895
+ this.adapter.sendTo(from, command, this.stController.localConfig.localData, callback);
896
+ }
878
897
  rv.error = `missing data in message ${JSON.stringify(msg)}`;
879
898
  }
880
899
  }
package/lib/developer.js CHANGED
File without changes
package/lib/exposes.js CHANGED
@@ -801,7 +801,7 @@ function createFromExposes(model, def, device, log) {
801
801
 
802
802
  case 'climate':
803
803
  for (const prop of expose.features) {
804
- switch (prop.name) {
804
+ /* switch (prop.name) {
805
805
  case 'away_mode':
806
806
  pushToStates(statesDefs.climate_away_mode, prop.access);
807
807
  break;
@@ -814,7 +814,8 @@ function createFromExposes(model, def, device, log) {
814
814
  default:
815
815
  pushToStates(genState(prop), prop.access);
816
816
  break;
817
- }
817
+ }*/
818
+ pushToStates(genState(prop), prop.access);
818
819
  }
819
820
  break;
820
821
 
@@ -329,6 +329,14 @@ class localConfig extends EventEmitter {
329
329
  return rv;
330
330
  }
331
331
 
332
+ getByModel(id) {
333
+ return this.localData.by_model[id] || {};
334
+ }
335
+
336
+ getByDevice(id) {
337
+ return this.localData.by_id[id] || {};
338
+ }
339
+
332
340
  }
333
341
 
334
342
  module.exports = localConfig;
package/lib/ota.js CHANGED
File without changes
File without changes
@@ -618,6 +618,7 @@ class ZigbeeController extends EventEmitter {
618
618
  device: coordinator,
619
619
  endpoint: coordinator.getEndpoint(1),
620
620
  name: 'Coordinator',
621
+ mapped: { model: 'Coordinator'},
621
622
  options:{}
622
623
  };
623
624
  }
@@ -657,6 +658,7 @@ class ZigbeeController extends EventEmitter {
657
658
  return {
658
659
  type: 'device',
659
660
  device: device,
661
+ mapped: { model: 'Coordinator'},
660
662
  endpoint: device.getEndpoint(1),
661
663
  name: 'Coordinator',
662
664
  };
@@ -736,6 +738,7 @@ class ZigbeeController extends EventEmitter {
736
738
  await this.herdsman.stop();
737
739
  this.herdsmanStarted = false;
738
740
  this.info('zigbecontroller stopped successfully');
741
+ return;
739
742
  }
740
743
  else this.info('zigbecontroller stopped successfully - ZH was not running');
741
744
  } catch (error) {
@@ -759,6 +762,7 @@ class ZigbeeController extends EventEmitter {
759
762
 
760
763
  // Permit join
761
764
  async permitJoin(permitTime, devid) {
765
+ if (!this.herdsmanStarted) return false;
762
766
  try {
763
767
  this._permitJoinTime = permitTime;
764
768
  await this.herdsman.permitJoin(permitTime);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.zigbee",
3
- "version": "3.1.5",
3
+ "version": "3.1.6",
4
4
  "author": {
5
5
  "name": "Kirov Ilya",
6
6
  "email": "kirovilya@gmail.com"
@@ -29,7 +29,7 @@
29
29
  "uri-js": "^4.4.1",
30
30
  "typescript": "^5.9.2",
31
31
  "zigbee-herdsman": "^6.0.0",
32
- "zigbee-herdsman-converters": "25.31.0"
32
+ "zigbee-herdsman-converters": "^25.37.0"
33
33
  },
34
34
  "description": "Zigbee devices",
35
35
  "devDependencies": {