zigbee-herdsman 1.0.0 → 1.1.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.
Files changed (132) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +14 -0
  3. package/dist/adapter/adapter.d.ts +6 -0
  4. package/dist/adapter/adapter.d.ts.map +1 -1
  5. package/dist/adapter/adapter.js.map +1 -1
  6. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +5 -3
  7. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +1 -1
  8. package/dist/adapter/deconz/adapter/deconzAdapter.js +261 -558
  9. package/dist/adapter/deconz/adapter/deconzAdapter.js.map +1 -1
  10. package/dist/adapter/deconz/driver/constants.d.ts +102 -56
  11. package/dist/adapter/deconz/driver/constants.d.ts.map +1 -1
  12. package/dist/adapter/deconz/driver/constants.js +1 -2
  13. package/dist/adapter/deconz/driver/constants.js.map +1 -1
  14. package/dist/adapter/deconz/driver/driver.d.ts.map +1 -1
  15. package/dist/adapter/deconz/driver/driver.js +46 -41
  16. package/dist/adapter/deconz/driver/driver.js.map +1 -1
  17. package/dist/adapter/deconz/driver/frameParser.d.ts.map +1 -1
  18. package/dist/adapter/deconz/driver/frameParser.js +174 -107
  19. package/dist/adapter/deconz/driver/frameParser.js.map +1 -1
  20. package/dist/adapter/ember/adapter/emberAdapter.d.ts +4 -12
  21. package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -1
  22. package/dist/adapter/ember/adapter/emberAdapter.js +215 -249
  23. package/dist/adapter/ember/adapter/emberAdapter.js.map +1 -1
  24. package/dist/adapter/ember/adapter/oneWaitress.d.ts +16 -12
  25. package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +1 -1
  26. package/dist/adapter/ember/adapter/oneWaitress.js +16 -41
  27. package/dist/adapter/ember/adapter/oneWaitress.js.map +1 -1
  28. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts +10 -8
  29. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +1 -1
  30. package/dist/adapter/ezsp/adapter/ezspAdapter.js +241 -238
  31. package/dist/adapter/ezsp/adapter/ezspAdapter.js.map +1 -1
  32. package/dist/adapter/ezsp/driver/driver.d.ts +6 -14
  33. package/dist/adapter/ezsp/driver/driver.d.ts.map +1 -1
  34. package/dist/adapter/ezsp/driver/driver.js +56 -37
  35. package/dist/adapter/ezsp/driver/driver.js.map +1 -1
  36. package/dist/adapter/ezsp/driver/ezsp.d.ts.map +1 -1
  37. package/dist/adapter/ezsp/driver/ezsp.js +3 -0
  38. package/dist/adapter/ezsp/driver/ezsp.js.map +1 -1
  39. package/dist/adapter/z-stack/adapter/manager.js +2 -2
  40. package/dist/adapter/z-stack/adapter/manager.js.map +1 -1
  41. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts +4 -3
  42. package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts.map +1 -1
  43. package/dist/adapter/z-stack/adapter/zStackAdapter.js +258 -197
  44. package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
  45. package/dist/adapter/z-stack/znp/definition.d.ts.map +1 -1
  46. package/dist/adapter/z-stack/znp/definition.js +256 -302
  47. package/dist/adapter/z-stack/znp/definition.js.map +1 -1
  48. package/dist/adapter/z-stack/znp/tstype.d.ts +8 -8
  49. package/dist/adapter/z-stack/znp/tstype.d.ts.map +1 -1
  50. package/dist/adapter/z-stack/znp/utils.d.ts +3 -2
  51. package/dist/adapter/z-stack/znp/utils.d.ts.map +1 -1
  52. package/dist/adapter/z-stack/znp/utils.js +8 -7
  53. package/dist/adapter/z-stack/znp/utils.js.map +1 -1
  54. package/dist/adapter/z-stack/znp/znp.d.ts +3 -1
  55. package/dist/adapter/z-stack/znp/znp.d.ts.map +1 -1
  56. package/dist/adapter/z-stack/znp/znp.js +31 -14
  57. package/dist/adapter/z-stack/znp/znp.js.map +1 -1
  58. package/dist/adapter/z-stack/znp/zpiObject.d.ts +5 -6
  59. package/dist/adapter/z-stack/znp/zpiObject.d.ts.map +1 -1
  60. package/dist/adapter/z-stack/znp/zpiObject.js +28 -11
  61. package/dist/adapter/z-stack/znp/zpiObject.js.map +1 -1
  62. package/dist/adapter/zboss/adapter/zbossAdapter.d.ts +7 -5
  63. package/dist/adapter/zboss/adapter/zbossAdapter.d.ts.map +1 -1
  64. package/dist/adapter/zboss/adapter/zbossAdapter.js +284 -138
  65. package/dist/adapter/zboss/adapter/zbossAdapter.js.map +1 -1
  66. package/dist/adapter/zboss/commands.d.ts +3 -0
  67. package/dist/adapter/zboss/commands.d.ts.map +1 -1
  68. package/dist/adapter/zboss/commands.js +248 -205
  69. package/dist/adapter/zboss/commands.js.map +1 -1
  70. package/dist/adapter/zboss/driver.d.ts +4 -14
  71. package/dist/adapter/zboss/driver.d.ts.map +1 -1
  72. package/dist/adapter/zboss/driver.js +63 -89
  73. package/dist/adapter/zboss/driver.js.map +1 -1
  74. package/dist/adapter/zboss/enums.d.ts +24 -2
  75. package/dist/adapter/zboss/enums.d.ts.map +1 -1
  76. package/dist/adapter/zboss/enums.js +35 -3
  77. package/dist/adapter/zboss/enums.js.map +1 -1
  78. package/dist/adapter/zboss/frame.d.ts +6 -1
  79. package/dist/adapter/zboss/frame.d.ts.map +1 -1
  80. package/dist/adapter/zboss/frame.js +56 -11
  81. package/dist/adapter/zboss/frame.js.map +1 -1
  82. package/dist/adapter/zboss/uart.d.ts +1 -0
  83. package/dist/adapter/zboss/uart.d.ts.map +1 -1
  84. package/dist/adapter/zboss/uart.js +4 -2
  85. package/dist/adapter/zboss/uart.js.map +1 -1
  86. package/dist/adapter/zigate/adapter/patchZdoBuffaloBE.d.ts +5 -0
  87. package/dist/adapter/zigate/adapter/patchZdoBuffaloBE.d.ts.map +1 -0
  88. package/dist/adapter/zigate/adapter/patchZdoBuffaloBE.js +44 -0
  89. package/dist/adapter/zigate/adapter/patchZdoBuffaloBE.js.map +1 -0
  90. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts +5 -0
  91. package/dist/adapter/zigate/adapter/zigateAdapter.d.ts.map +1 -1
  92. package/dist/adapter/zigate/adapter/zigateAdapter.js +247 -262
  93. package/dist/adapter/zigate/adapter/zigateAdapter.js.map +1 -1
  94. package/dist/adapter/zigate/driver/buffaloZiGate.d.ts.map +1 -1
  95. package/dist/adapter/zigate/driver/buffaloZiGate.js +2 -18
  96. package/dist/adapter/zigate/driver/buffaloZiGate.js.map +1 -1
  97. package/dist/adapter/zigate/driver/commandType.js +218 -218
  98. package/dist/adapter/zigate/driver/commandType.js.map +1 -1
  99. package/dist/adapter/zigate/driver/constants.d.ts +14 -8
  100. package/dist/adapter/zigate/driver/constants.d.ts.map +1 -1
  101. package/dist/adapter/zigate/driver/constants.js +36 -9
  102. package/dist/adapter/zigate/driver/constants.js.map +1 -1
  103. package/dist/adapter/zigate/driver/messageType.js +42 -42
  104. package/dist/adapter/zigate/driver/messageType.js.map +1 -1
  105. package/dist/adapter/zigate/driver/zigate.d.ts +17 -13
  106. package/dist/adapter/zigate/driver/zigate.d.ts.map +1 -1
  107. package/dist/adapter/zigate/driver/zigate.js +83 -18
  108. package/dist/adapter/zigate/driver/zigate.js.map +1 -1
  109. package/dist/controller/controller.d.ts +1 -0
  110. package/dist/controller/controller.d.ts.map +1 -1
  111. package/dist/controller/controller.js +28 -0
  112. package/dist/controller/controller.js.map +1 -1
  113. package/dist/utils/patchBigIntSerialization.d.ts +2 -0
  114. package/dist/utils/patchBigIntSerialization.d.ts.map +1 -0
  115. package/dist/utils/patchBigIntSerialization.js +9 -0
  116. package/dist/utils/patchBigIntSerialization.js.map +1 -0
  117. package/dist/zspec/zcl/zclFrame.d.ts +1 -0
  118. package/dist/zspec/zcl/zclFrame.d.ts.map +1 -1
  119. package/dist/zspec/zcl/zclFrame.js +1 -0
  120. package/dist/zspec/zcl/zclFrame.js.map +1 -1
  121. package/dist/zspec/zdo/buffaloZdo.d.ts +1 -139
  122. package/dist/zspec/zdo/buffaloZdo.d.ts.map +1 -1
  123. package/dist/zspec/zdo/buffaloZdo.js.map +1 -1
  124. package/dist/zspec/zdo/definition/tstypes.d.ts +168 -1
  125. package/dist/zspec/zdo/definition/tstypes.d.ts.map +1 -1
  126. package/dist/zspec/zdo/definition/tstypes.js +1 -0
  127. package/dist/zspec/zdo/definition/tstypes.js.map +1 -1
  128. package/dist/zspec/zdo/utils.d.ts +2 -3
  129. package/dist/zspec/zdo/utils.d.ts.map +1 -1
  130. package/dist/zspec/zdo/utils.js +3 -4
  131. package/dist/zspec/zdo/utils.js.map +1 -1
  132. package/package.json +1 -1
@@ -33,6 +33,7 @@ const device_1 = __importDefault(require("../../../controller/model/device"));
33
33
  const utils_1 = require("../../../utils");
34
34
  const logger_1 = require("../../../utils/logger");
35
35
  const Zcl = __importStar(require("../../../zspec/zcl"));
36
+ const Zdo = __importStar(require("../../../zspec/zdo"));
36
37
  const adapter_1 = __importDefault(require("../../adapter"));
37
38
  const constants_1 = __importDefault(require("../driver/constants"));
38
39
  const driver_1 = __importDefault(require("../driver/driver"));
@@ -40,18 +41,17 @@ const frameParser_1 = __importStar(require("../driver/frameParser"));
40
41
  const NS = 'zh:deconz';
41
42
  class DeconzAdapter extends adapter_1.default {
42
43
  driver;
43
- queue;
44
44
  openRequestsQueue;
45
45
  transactionID;
46
46
  frameParserEvent = frameParser_1.frameParserEvents;
47
- joinPermitted;
48
47
  fwVersion;
49
48
  waitress;
50
49
  TX_OPTIONS = 0x00; // No APS ACKS
50
+ joinPermitted = false;
51
51
  constructor(networkOptions, serialPortOptions, backupPath, adapterOptions) {
52
52
  super(networkOptions, serialPortOptions, backupPath, adapterOptions);
53
53
  this.hasZdoMessageOverhead = true;
54
- const concurrent = this.adapterOptions && this.adapterOptions.concurrent ? this.adapterOptions.concurrent : 2;
54
+ // const concurrent = this.adapterOptions && this.adapterOptions.concurrent ? this.adapterOptions.concurrent : 2;
55
55
  // TODO: https://github.com/Koenkk/zigbee2mqtt/issues/4884#issuecomment-728903121
56
56
  const delay = this.adapterOptions && typeof this.adapterOptions.delay === 'number' ? this.adapterOptions.delay : 0;
57
57
  this.waitress = new utils_1.Waitress(this.waitressValidator, this.waitressTimeoutFormatter);
@@ -63,10 +63,8 @@ class DeconzAdapter extends adapter_1.default {
63
63
  this.driver.on('rxFrame', (frame) => {
64
64
  (0, frameParser_1.default)(frame);
65
65
  });
66
- this.queue = new utils_1.Queue(concurrent);
67
66
  this.transactionID = 0;
68
67
  this.openRequestsQueue = [];
69
- this.joinPermitted = false;
70
68
  this.fwVersion = undefined;
71
69
  this.frameParserEvent.on('receivedDataPayload', (data) => {
72
70
  this.checkReceivedDataPayload(data);
@@ -160,7 +158,7 @@ class DeconzAdapter extends adapter_1.default {
160
158
  }
161
159
  try {
162
160
  await this.driver.writeParameterRequest(constants_1.default.PARAM.Network.CHANNEL_MASK, setChannelMask);
163
- await this.sleep(500);
161
+ await (0, utils_1.Wait)(500);
164
162
  changed = true;
165
163
  }
166
164
  catch (error) {
@@ -172,7 +170,7 @@ class DeconzAdapter extends adapter_1.default {
172
170
  logger_1.logger.debug('panid in configuration.yaml (' + this.networkOptions.panID + ') differs from current panid (' + panid + '). Changing panid.', NS);
173
171
  try {
174
172
  await this.driver.writeParameterRequest(constants_1.default.PARAM.Network.PAN_ID, this.networkOptions.panID);
175
- await this.sleep(500);
173
+ await (0, utils_1.Wait)(500);
176
174
  changed = true;
177
175
  }
178
176
  catch (error) {
@@ -188,7 +186,7 @@ class DeconzAdapter extends adapter_1.default {
188
186
  '). Changing extended panid.', NS);
189
187
  try {
190
188
  await this.driver.writeParameterRequest(constants_1.default.PARAM.Network.APS_EXT_PAN_ID, this.networkOptions.extendedPanID);
191
- await this.sleep(500);
189
+ await (0, utils_1.Wait)(500);
192
190
  changed = true;
193
191
  }
194
192
  catch (error) {
@@ -200,7 +198,7 @@ class DeconzAdapter extends adapter_1.default {
200
198
  logger_1.logger.debug('network key in configuration.yaml (hidden) differs from current network key (' + networkKey + '). Changing network key.', NS);
201
199
  try {
202
200
  await this.driver.writeParameterRequest(constants_1.default.PARAM.Network.NETWORK_KEY, this.networkOptions.networkKey);
203
- await this.sleep(500);
201
+ await (0, utils_1.Wait)(500);
204
202
  changed = true;
205
203
  }
206
204
  catch (error) {
@@ -209,9 +207,9 @@ class DeconzAdapter extends adapter_1.default {
209
207
  }
210
208
  if (changed) {
211
209
  await this.driver.changeNetworkStateRequest(constants_1.default.PARAM.Network.NET_OFFLINE);
212
- await this.sleep(2000);
210
+ await (0, utils_1.Wait)(2000);
213
211
  await this.driver.changeNetworkStateRequest(constants_1.default.PARAM.Network.NET_CONNECTED);
214
- await this.sleep(2000);
212
+ await (0, utils_1.Wait)(2000);
215
213
  }
216
214
  return 'resumed';
217
215
  }
@@ -245,39 +243,28 @@ class DeconzAdapter extends adapter_1.default {
245
243
  };
246
244
  }
247
245
  async permitJoin(seconds, networkAddress) {
248
- const transactionID = this.nextTransactionID();
249
- const request = {};
250
- const zdpFrame = [transactionID, seconds, 0]; // tc_significance 1 or 0 ?
251
- request.requestId = transactionID;
252
- request.destAddrMode = constants_1.default.PARAM.addressMode.NWK_ADDR;
253
- request.destAddr16 = networkAddress || 0xfffc;
254
- request.destEndpoint = 0;
255
- request.profileId = 0;
256
- request.clusterId = 0x36; // permit join
257
- request.srcEndpoint = 0;
258
- request.asduLength = 3;
259
- request.asduPayload = zdpFrame;
260
- request.txOptions = 0;
261
- request.radius = constants_1.default.PARAM.txRadius.DEFAULT_RADIUS;
262
- request.timeout = 5;
263
- try {
264
- await this.driver.enqueueSendDataRequest(request);
265
- if (seconds === 0) {
266
- this.joinPermitted = false;
246
+ const clusterId = Zdo.ClusterId.PERMIT_JOINING_REQUEST;
247
+ if (networkAddress) {
248
+ // `authentication`: TC significance always 1 (zb specs)
249
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, seconds, 1, []);
250
+ const result = await this.sendZdo(__1.ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
251
+ /* istanbul ignore next */
252
+ if (!Zdo.Buffalo.checkStatus(result)) {
253
+ // TODO: will disappear once moved upstream
254
+ throw new Zdo.StatusError(result[0]);
267
255
  }
268
- else {
269
- this.joinPermitted = true;
270
- }
271
- await this.driver.writeParameterRequest(constants_1.default.PARAM.Network.PERMIT_JOIN, seconds);
272
- logger_1.logger.debug('PERMIT_JOIN - ' + seconds + ' seconds', NS);
273
256
  }
274
- catch (error) {
275
- const msg = 'PERMIT_JOIN FAILED - ' + error;
276
- logger_1.logger.debug(msg, NS);
277
- // try again
278
- await this.permitJoin(seconds, networkAddress);
279
- //return Promise.reject(new Error(msg)); // do not reject
257
+ else {
258
+ await this.driver.writeParameterRequest(constants_1.default.PARAM.Network.PERMIT_JOIN, seconds);
259
+ logger_1.logger.debug(`Permit joining on coordinator for ${seconds} sec.`, NS);
260
+ // broadcast permit joining ZDO
261
+ if (networkAddress === undefined) {
262
+ // `authentication`: TC significance always 1 (zb specs)
263
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, seconds, 1, []);
264
+ await this.sendZdo(__1.ZSpec.BLANK_EUI64, __1.ZSpec.BroadcastAddress.DEFAULT, clusterId, zdoPayload, true);
265
+ }
280
266
  }
267
+ this.joinPermitted = seconds !== 0;
281
268
  }
282
269
  async getCoordinatorVersion() {
283
270
  // product: number; transportrev: number; majorrel: number; minorrel: number; maintrel: number; revision: string;
@@ -317,334 +304,129 @@ class DeconzAdapter extends adapter_1.default {
317
304
  return await Promise.reject(new Error('Reset is not supported'));
318
305
  }
319
306
  async lqi(networkAddress) {
307
+ const clusterId = Zdo.ClusterId.LQI_TABLE_REQUEST;
320
308
  const neighbors = [];
321
- const add = (list) => {
322
- for (const entry of list) {
323
- const relationByte = entry.readUInt8(18);
324
- const extAddr = [];
325
- for (let i = 8; i < 16; i++) {
326
- extAddr.push(entry[i]);
327
- }
328
- neighbors.push({
329
- linkquality: entry.readUInt8(21),
330
- networkAddress: entry.readUInt16LE(16),
331
- ieeeAddr: this.driver.macAddrArrayToString(extAddr),
332
- relationship: (relationByte >> 1) & ((1 << 3) - 1),
333
- depth: entry.readUInt8(20),
334
- });
335
- }
336
- };
337
309
  const request = async (startIndex) => {
338
- const transactionID = this.nextTransactionID();
339
- const req = {};
340
- req.requestId = transactionID;
341
- req.destAddrMode = constants_1.default.PARAM.addressMode.NWK_ADDR;
342
- req.destAddr16 = networkAddress;
343
- req.destEndpoint = 0;
344
- req.profileId = 0;
345
- req.clusterId = 0x31; // mgmt_lqi_request
346
- req.srcEndpoint = 0;
347
- req.asduLength = 2;
348
- req.asduPayload = [transactionID, startIndex];
349
- req.txOptions = 0;
350
- req.radius = constants_1.default.PARAM.txRadius.DEFAULT_RADIUS;
351
- this.driver
352
- .enqueueSendDataRequest(req)
353
- .then(() => { })
354
- .catch(() => { });
355
- try {
356
- const d = await this.waitForData(networkAddress, 0, 0x8031);
357
- const data = d.asduPayload;
358
- if (data[1] !== 0) {
359
- // status
360
- throw new Error(`LQI for '${networkAddress}' failed`);
361
- }
362
- const tableList = [];
363
- const response = {
364
- status: data[1],
365
- tableEntrys: data[2],
366
- startIndex: data[3],
367
- tableListCount: data[4],
368
- tableList: tableList,
369
- };
370
- let tableEntry = [];
371
- let counter = 0;
372
- for (let i = 5; i < response.tableListCount * 22 + 5; i++) {
373
- // one tableentry = 22 bytes
374
- tableEntry.push(data[i]);
375
- counter++;
376
- if (counter === 22) {
377
- response.tableList.push(Buffer.from(tableEntry));
378
- tableEntry = [];
379
- counter = 0;
380
- }
310
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, startIndex);
311
+ const result = await this.sendZdo(__1.ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
312
+ /* istanbul ignore else */
313
+ if (Zdo.Buffalo.checkStatus(result)) {
314
+ const payload = result[1];
315
+ for (const entry of payload.entryList) {
316
+ neighbors.push({
317
+ ieeeAddr: entry.eui64,
318
+ networkAddress: entry.nwkAddress,
319
+ linkquality: entry.lqi,
320
+ relationship: entry.relationship,
321
+ depth: entry.depth,
322
+ });
381
323
  }
382
- logger_1.logger.debug('LQI RESPONSE - addr: 0x' +
383
- networkAddress.toString(16) +
384
- ' status: ' +
385
- response.status +
386
- ' read ' +
387
- (response.tableListCount + response.startIndex) +
388
- '/' +
389
- response.tableEntrys +
390
- ' entrys', NS);
391
- return response;
324
+ return [payload.neighborTableEntries, payload.entryList.length];
392
325
  }
393
- catch (error) {
394
- const msg = 'LQI REQUEST FAILED - addr: 0x' + networkAddress.toString(16) + ' ' + error;
395
- logger_1.logger.debug(msg, NS);
396
- return await Promise.reject(new Error(msg));
326
+ else {
327
+ // TODO: will disappear once moved upstream
328
+ throw new Zdo.StatusError(result[0]);
397
329
  }
398
330
  };
399
- let response = await request(0);
400
- add(response.tableList);
401
- let nextStartIndex = response.tableListCount;
402
- while (neighbors.length < response.tableEntrys) {
403
- response = await request(nextStartIndex);
404
- add(response.tableList);
405
- nextStartIndex += response.tableListCount;
331
+ let [tableEntries, entryCount] = await request(0);
332
+ const size = tableEntries;
333
+ let nextStartIndex = entryCount;
334
+ while (neighbors.length < size) {
335
+ [tableEntries, entryCount] = await request(nextStartIndex);
336
+ nextStartIndex += entryCount;
406
337
  }
407
338
  return { neighbors };
408
339
  }
409
340
  async routingTable(networkAddress) {
341
+ const clusterId = Zdo.ClusterId.ROUTING_TABLE_REQUEST;
410
342
  const table = [];
411
- const statusLookup = {
412
- 0: 'ACTIVE',
413
- 1: 'DISCOVERY_UNDERWAY',
414
- 2: 'DISCOVERY_FAILED',
415
- 3: 'INACTIVE',
416
- };
417
- const add = (list) => {
418
- for (const entry of list) {
419
- const statusByte = entry.readUInt8(2);
420
- const extAddr = [];
421
- for (let i = 8; i < 16; i++) {
422
- extAddr.push(entry[i]);
423
- }
424
- table.push({
425
- destinationAddress: entry.readUInt16LE(0),
426
- status: statusLookup[(statusByte >> 5) & ((1 << 3) - 1)],
427
- nextHop: entry.readUInt16LE(3),
428
- });
429
- }
430
- };
431
343
  const request = async (startIndex) => {
432
- const transactionID = this.nextTransactionID();
433
- const req = {};
434
- req.requestId = transactionID;
435
- req.destAddrMode = constants_1.default.PARAM.addressMode.NWK_ADDR;
436
- req.destAddr16 = networkAddress;
437
- req.destEndpoint = 0;
438
- req.profileId = 0;
439
- req.clusterId = 0x32; // mgmt_rtg_request
440
- req.srcEndpoint = 0;
441
- req.asduLength = 2;
442
- req.asduPayload = [transactionID, startIndex];
443
- req.txOptions = 0;
444
- req.radius = constants_1.default.PARAM.txRadius.DEFAULT_RADIUS;
445
- req.timeout = 30;
446
- this.driver
447
- .enqueueSendDataRequest(req)
448
- .then(() => { })
449
- .catch(() => { });
450
- try {
451
- const d = await this.waitForData(networkAddress, 0, 0x8032);
452
- const data = d.asduPayload;
453
- if (data[1] !== 0) {
454
- // status
455
- throw new Error(`Routingtables for '${networkAddress}' failed`);
344
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, startIndex);
345
+ const result = await this.sendZdo(__1.ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
346
+ /* istanbul ignore else */
347
+ if (Zdo.Buffalo.checkStatus(result)) {
348
+ const payload = result[1];
349
+ for (const entry of payload.entryList) {
350
+ table.push({
351
+ destinationAddress: entry.destinationAddress,
352
+ status: entry.status,
353
+ nextHop: entry.nextHopAddress,
354
+ });
456
355
  }
457
- const tableList = [];
458
- const response = {
459
- status: data[1],
460
- tableEntrys: data[2],
461
- startIndex: data[3],
462
- tableListCount: data[4],
463
- tableList: tableList,
464
- };
465
- let tableEntry = [];
466
- let counter = 0;
467
- for (let i = 5; i < response.tableListCount * 5 + 5; i++) {
468
- // one tableentry = 5 bytes
469
- tableEntry.push(data[i]);
470
- counter++;
471
- if (counter === 5) {
472
- response.tableList.push(Buffer.from(tableEntry));
473
- tableEntry = [];
474
- counter = 0;
475
- }
476
- }
477
- logger_1.logger.debug('ROUTING_TABLE RESPONSE - addr: 0x' +
478
- networkAddress.toString(16) +
479
- ' status: ' +
480
- response.status +
481
- ' read ' +
482
- (response.tableListCount + response.startIndex) +
483
- '/' +
484
- response.tableEntrys +
485
- ' entrys', NS);
486
- return response;
356
+ return [payload.routingTableEntries, payload.entryList.length];
487
357
  }
488
- catch (error) {
489
- const msg = 'ROUTING_TABLE REQUEST FAILED - addr: 0x' + networkAddress.toString(16) + ' ' + error;
490
- logger_1.logger.debug(msg, NS);
491
- return await Promise.reject(new Error(msg));
358
+ else {
359
+ // TODO: will disappear once moved upstream
360
+ throw new Zdo.StatusError(result[0]);
492
361
  }
493
362
  };
494
- let response = await request(0);
495
- add(response.tableList);
496
- let nextStartIndex = response.tableListCount;
497
- while (table.length < response.tableEntrys) {
498
- response = await request(nextStartIndex);
499
- add(response.tableList);
500
- nextStartIndex += response.tableListCount;
363
+ let [tableEntries, entryCount] = await request(0);
364
+ const size = tableEntries;
365
+ let nextStartIndex = entryCount;
366
+ while (table.length < size) {
367
+ [tableEntries, entryCount] = await request(nextStartIndex);
368
+ nextStartIndex += entryCount;
501
369
  }
502
370
  return { table };
503
371
  }
504
372
  async nodeDescriptor(networkAddress) {
505
- const transactionID = this.nextTransactionID();
506
- const nwk1 = networkAddress & 0xff;
507
- const nwk2 = (networkAddress >> 8) & 0xff;
508
- const request = {};
509
- const zdpFrame = [transactionID, nwk1, nwk2];
510
- request.requestId = transactionID;
511
- request.destAddrMode = constants_1.default.PARAM.addressMode.NWK_ADDR;
512
- request.destAddr16 = networkAddress;
513
- request.destEndpoint = 0;
514
- request.profileId = 0;
515
- request.clusterId = 0x02; // node descriptor
516
- request.srcEndpoint = 0;
517
- request.asduLength = 3;
518
- request.asduPayload = zdpFrame;
519
- request.txOptions = 0;
520
- request.radius = constants_1.default.PARAM.txRadius.DEFAULT_RADIUS;
521
- request.timeout = 30;
522
- this.driver
523
- .enqueueSendDataRequest(request)
524
- .then(() => { })
525
- .catch(() => { });
526
- try {
527
- const d = await this.waitForData(networkAddress, 0, 0x8002);
528
- const data = d.asduPayload;
529
- const buf = Buffer.from(data);
530
- const logicaltype = data[4] & 7;
531
- const type = logicaltype === 1 ? 'Router' : logicaltype === 2 ? 'EndDevice' : logicaltype === 0 ? 'Coordinator' : 'Unknown';
532
- const manufacturer = buf.readUInt16LE(7);
533
- logger_1.logger.debug('RECEIVING NODE_DESCRIPTOR - addr: 0x' +
534
- networkAddress.toString(16) +
535
- ' type: ' +
536
- type +
537
- ' manufacturer: 0x' +
538
- manufacturer.toString(16), NS);
539
- return { manufacturerCode: manufacturer, type };
373
+ const clusterId = Zdo.ClusterId.NODE_DESCRIPTOR_REQUEST;
374
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, networkAddress);
375
+ const result = await this.sendZdo(__1.ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
376
+ /* istanbul ignore else */
377
+ if (Zdo.Buffalo.checkStatus(result)) {
378
+ const payload = result[1];
379
+ let type = 'Unknown';
380
+ switch (payload.logicalType) {
381
+ case 0x0:
382
+ type = 'Coordinator';
383
+ break;
384
+ case 0x1:
385
+ type = 'Router';
386
+ break;
387
+ case 0x2:
388
+ type = 'EndDevice';
389
+ break;
390
+ }
391
+ return { type, manufacturerCode: payload.manufacturerCode };
540
392
  }
541
- catch (error) {
542
- const msg = 'RECEIVING NODE_DESCRIPTOR FAILED - addr: 0x' + networkAddress.toString(16) + ' ' + error;
543
- logger_1.logger.debug(msg, NS);
544
- return await Promise.reject(new Error(msg));
393
+ else {
394
+ // TODO: will disappear once moved upstream
395
+ throw new Zdo.StatusError(result[0]);
545
396
  }
546
397
  }
547
398
  async activeEndpoints(networkAddress) {
548
- const transactionID = this.nextTransactionID();
549
- const nwk1 = networkAddress & 0xff;
550
- const nwk2 = (networkAddress >> 8) & 0xff;
551
- const request = {};
552
- const zdpFrame = [transactionID, nwk1, nwk2];
553
- request.requestId = transactionID;
554
- request.destAddrMode = constants_1.default.PARAM.addressMode.NWK_ADDR;
555
- request.destAddr16 = networkAddress;
556
- request.destEndpoint = 0;
557
- request.profileId = 0;
558
- request.clusterId = 0x05; // active endpoints
559
- request.srcEndpoint = 0;
560
- request.asduLength = 3;
561
- request.asduPayload = zdpFrame;
562
- request.txOptions = 0;
563
- request.radius = constants_1.default.PARAM.txRadius.DEFAULT_RADIUS;
564
- request.timeout = 30;
565
- this.driver
566
- .enqueueSendDataRequest(request)
567
- .then(() => { })
568
- .catch(() => { });
569
- try {
570
- const d = await this.waitForData(networkAddress, 0, 0x8005);
571
- const data = d.asduPayload;
572
- const buf = Buffer.from(data);
573
- const epCount = buf.readUInt8(4);
574
- const epList = [];
575
- for (let i = 5; i < epCount + 5; i++) {
576
- epList.push(buf.readUInt8(i));
577
- }
578
- logger_1.logger.debug('ACTIVE_ENDPOINTS - addr: 0x' + networkAddress.toString(16) + ' EP list: ' + epList, NS);
579
- return { endpoints: epList };
399
+ const clusterId = Zdo.ClusterId.ACTIVE_ENDPOINTS_REQUEST;
400
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, networkAddress);
401
+ const result = await this.sendZdo(__1.ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
402
+ /* istanbul ignore else */
403
+ if (Zdo.Buffalo.checkStatus(result)) {
404
+ const payload = result[1];
405
+ return { endpoints: payload.endpointList };
580
406
  }
581
- catch (error) {
582
- const msg = 'READING ACTIVE_ENDPOINTS FAILED - addr: 0x' + networkAddress.toString(16) + ' ' + error;
583
- logger_1.logger.debug(msg, NS);
584
- return await Promise.reject(new Error(msg));
407
+ else {
408
+ // TODO: will disappear once moved upstream
409
+ throw new Zdo.StatusError(result[0]);
585
410
  }
586
411
  }
587
412
  async simpleDescriptor(networkAddress, endpointID) {
588
- const transactionID = this.nextTransactionID();
589
- const nwk1 = networkAddress & 0xff;
590
- const nwk2 = (networkAddress >> 8) & 0xff;
591
- const request = {};
592
- const zdpFrame = [transactionID, nwk1, nwk2, endpointID];
593
- request.requestId = transactionID;
594
- request.destAddrMode = constants_1.default.PARAM.addressMode.NWK_ADDR;
595
- request.destAddr16 = networkAddress;
596
- request.destEndpoint = 0;
597
- request.profileId = 0;
598
- request.clusterId = 0x04; // simple descriptor
599
- request.srcEndpoint = 0;
600
- request.asduLength = 4;
601
- request.asduPayload = zdpFrame;
602
- request.txOptions = 0;
603
- request.radius = constants_1.default.PARAM.txRadius.DEFAULT_RADIUS;
604
- request.timeout = 30;
605
- this.driver
606
- .enqueueSendDataRequest(request)
607
- .then(() => { })
608
- .catch(() => { });
609
- try {
610
- const d = await this.waitForData(networkAddress, 0, 0x8004);
611
- const data = d.asduPayload;
612
- const buf = Buffer.from(data);
613
- const inCount = buf.readUInt8(11);
614
- const inClusters = [];
615
- let cIndex = 12;
616
- for (let i = 0; i < inCount; i++) {
617
- inClusters[i] = buf.readUInt16LE(cIndex);
618
- cIndex += 2;
619
- }
620
- const outCount = buf.readUInt8(12 + inCount * 2);
621
- const outClusters = [];
622
- cIndex = 13 + inCount * 2;
623
- for (let l = 0; l < outCount; l++) {
624
- outClusters[l] = buf.readUInt16LE(cIndex);
625
- cIndex += 2;
626
- }
627
- const simpleDesc = {
628
- profileID: buf.readUInt16LE(6),
629
- endpointID: buf.readUInt8(5),
630
- deviceID: buf.readUInt16LE(8),
631
- inputClusters: inClusters,
632
- outputClusters: outClusters,
413
+ const clusterId = Zdo.ClusterId.SIMPLE_DESCRIPTOR_REQUEST;
414
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, networkAddress, endpointID);
415
+ const result = await this.sendZdo(__1.ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
416
+ /* istanbul ignore else */
417
+ if (Zdo.Buffalo.checkStatus(result)) {
418
+ const payload = result[1];
419
+ return {
420
+ profileID: payload.profileId,
421
+ endpointID: payload.endpoint,
422
+ deviceID: payload.deviceId,
423
+ inputClusters: payload.inClusterList,
424
+ outputClusters: payload.outClusterList,
633
425
  };
634
- logger_1.logger.debug('RECEIVING SIMPLE_DESCRIPTOR - addr: 0x' +
635
- networkAddress.toString(16) +
636
- ' EP:' +
637
- simpleDesc.endpointID +
638
- ' inClusters: ' +
639
- inClusters +
640
- ' outClusters: ' +
641
- outClusters, NS);
642
- return simpleDesc;
643
426
  }
644
- catch (error) {
645
- const msg = 'RECEIVING SIMPLE_DESCRIPTOR FAILED - addr: 0x' + networkAddress.toString(16) + ' ' + error;
646
- logger_1.logger.debug(msg, NS);
647
- return await Promise.reject(new Error(msg));
427
+ else {
428
+ // TODO: will disappear once moved upstream
429
+ throw new Zdo.StatusError(result[0]);
648
430
  }
649
431
  }
650
432
  async checkCoordinatorSimpleDescriptor(skip) {
@@ -720,24 +502,54 @@ class DeconzAdapter extends adapter_1.default {
720
502
  const cancel = () => this.waitress.remove(waiter.ID);
721
503
  return { promise: waiter.start().promise, cancel };
722
504
  }
505
+ async sendZdo(ieeeAddress, networkAddress, clusterId, payload, disableResponse) {
506
+ const transactionID = this.nextTransactionID();
507
+ payload[0] = transactionID;
508
+ const isNwkAddrRequest = clusterId === Zdo.ClusterId.NETWORK_ADDRESS_REQUEST;
509
+ const req = {
510
+ requestId: transactionID,
511
+ destAddrMode: isNwkAddrRequest ? constants_1.default.PARAM.addressMode.IEEE_ADDR : constants_1.default.PARAM.addressMode.NWK_ADDR,
512
+ destAddr16: isNwkAddrRequest ? undefined : networkAddress,
513
+ destAddr64: isNwkAddrRequest ? ieeeAddress : undefined,
514
+ destEndpoint: Zdo.ZDO_ENDPOINT,
515
+ profileId: Zdo.ZDO_PROFILE_ID,
516
+ clusterId,
517
+ srcEndpoint: Zdo.ZDO_ENDPOINT,
518
+ asduLength: payload.length,
519
+ asduPayload: payload,
520
+ txOptions: 0,
521
+ radius: constants_1.default.PARAM.txRadius.DEFAULT_RADIUS,
522
+ timeout: 30,
523
+ };
524
+ this.driver
525
+ .enqueueSendDataRequest(req)
526
+ .then(() => { })
527
+ .catch(() => { });
528
+ if (!disableResponse) {
529
+ const responseClusterId = Zdo.Utils.getResponseClusterId(clusterId);
530
+ if (responseClusterId) {
531
+ const response = await this.waitForData(isNwkAddrRequest ? ieeeAddress : networkAddress, Zdo.ZDO_PROFILE_ID, responseClusterId);
532
+ return response.zdo;
533
+ }
534
+ }
535
+ }
723
536
  async sendZclFrameToEndpoint(ieeeAddr, networkAddress, endpoint, zclFrame, timeout, disableResponse, disableRecovery, sourceEndpoint) {
724
537
  const transactionID = this.nextTransactionID();
725
- const request = {};
726
- const pay = zclFrame.toBuffer();
727
- //logger.info("zclFramte.toBuffer:", NS);
728
- //logger.info(pay, NS);
729
- request.requestId = transactionID;
730
- request.destAddrMode = constants_1.default.PARAM.addressMode.NWK_ADDR;
731
- request.destAddr16 = networkAddress;
732
- request.destEndpoint = endpoint;
733
- request.profileId = sourceEndpoint === 242 && endpoint === 242 ? 0xa1e0 : 0x104;
734
- request.clusterId = zclFrame.cluster.ID;
735
- request.srcEndpoint = sourceEndpoint || 1;
736
- request.asduLength = pay.length;
737
- request.asduPayload = [...pay];
738
- request.txOptions = this.TX_OPTIONS; // 0x00 normal; 0x04 APS ACK
739
- request.radius = constants_1.default.PARAM.txRadius.DEFAULT_RADIUS;
740
- request.timeout = timeout;
538
+ const payload = zclFrame.toBuffer();
539
+ const request = {
540
+ requestId: transactionID,
541
+ destAddrMode: constants_1.default.PARAM.addressMode.NWK_ADDR,
542
+ destAddr16: networkAddress,
543
+ destEndpoint: endpoint,
544
+ profileId: sourceEndpoint === 242 && endpoint === 242 ? 0xa1e0 : 0x104,
545
+ clusterId: zclFrame.cluster.ID,
546
+ srcEndpoint: sourceEndpoint || 1,
547
+ asduLength: payload.length,
548
+ asduPayload: payload,
549
+ txOptions: this.TX_OPTIONS, // 0x00 normal, 0x04 APS ACK
550
+ radius: constants_1.default.PARAM.txRadius.DEFAULT_RADIUS,
551
+ timeout: timeout,
552
+ };
741
553
  const command = zclFrame.command;
742
554
  this.driver
743
555
  .enqueueSendDataRequest(request)
@@ -763,16 +575,14 @@ class DeconzAdapter extends adapter_1.default {
763
575
  try {
764
576
  let data = null;
765
577
  if ((command.response != undefined && !disableResponse) || !zclFrame.header.frameControl.disableDefaultResponse) {
766
- data = await this.waitForData(networkAddress, 0x104, zclFrame.cluster.ID, zclFrame.header.transactionSequenceNumber, request.timeout);
578
+ data = await this.waitForData(networkAddress, __1.ZSpec.HA_PROFILE_ID, zclFrame.cluster.ID, zclFrame.header.transactionSequenceNumber, request.timeout);
767
579
  }
768
580
  if (data !== null) {
769
- const asdu = data.asduPayload;
770
- const buffer = Buffer.from(asdu);
771
581
  const response = {
772
582
  address: data.srcAddr16 ?? `0x${data.srcAddr64}`,
773
- data: buffer,
583
+ data: data.asduPayload,
774
584
  clusterID: zclFrame.cluster.ID,
775
- header: Zcl.Header.fromBuffer(buffer),
585
+ header: Zcl.Header.fromBuffer(data.asduPayload),
776
586
  endpoint: data.srcEndpoint,
777
587
  linkquality: data.lqi,
778
588
  groupID: data.srcAddrMode === 0x01 ? data.srcAddr16 : 0,
@@ -792,179 +602,75 @@ class DeconzAdapter extends adapter_1.default {
792
602
  }
793
603
  async sendZclFrameToGroup(groupID, zclFrame) {
794
604
  const transactionID = this.nextTransactionID();
795
- const request = {};
796
- const pay = zclFrame.toBuffer();
797
- logger_1.logger.debug('zclFrame to group - zclFrame.payload:', NS);
798
- logger_1.logger.debug(zclFrame.payload, NS);
799
- //logger.info("zclFramte.toBuffer:", NS);
800
- //logger.info(pay, NS);
801
- request.requestId = transactionID;
802
- request.destAddrMode = constants_1.default.PARAM.addressMode.GROUP_ADDR;
803
- request.destAddr16 = groupID;
804
- request.profileId = 0x104;
805
- request.clusterId = zclFrame.cluster.ID;
806
- request.srcEndpoint = 1;
807
- request.asduLength = pay.length;
808
- request.asduPayload = [...pay];
809
- request.txOptions = 0;
810
- request.radius = constants_1.default.PARAM.txRadius.UNLIMITED;
605
+ const payload = zclFrame.toBuffer();
606
+ logger_1.logger.debug(`zclFrame to group - ${groupID}`, NS);
607
+ const request = {
608
+ requestId: transactionID,
609
+ destAddrMode: constants_1.default.PARAM.addressMode.GROUP_ADDR,
610
+ destAddr16: groupID,
611
+ profileId: 0x104,
612
+ clusterId: zclFrame.cluster.ID,
613
+ srcEndpoint: 1,
614
+ asduLength: payload.length,
615
+ asduPayload: payload,
616
+ txOptions: 0,
617
+ radius: constants_1.default.PARAM.txRadius.UNLIMITED,
618
+ };
811
619
  logger_1.logger.debug(`sendZclFrameToGroup - message send`, NS);
812
620
  return await this.driver.enqueueSendDataRequest(request);
813
621
  }
814
622
  async sendZclFrameToAll(endpoint, zclFrame, sourceEndpoint, destination) {
815
623
  const transactionID = this.nextTransactionID();
816
- const request = {};
817
- const pay = zclFrame.toBuffer();
818
- logger_1.logger.debug('zclFrame to all - zclFrame.payload:', NS);
819
- logger_1.logger.debug(zclFrame.payload, NS);
820
- request.requestId = transactionID;
821
- request.destAddrMode = constants_1.default.PARAM.addressMode.NWK_ADDR;
822
- request.destAddr16 = destination;
823
- request.destEndpoint = endpoint;
824
- request.profileId = sourceEndpoint === 242 && endpoint === 242 ? 0xa1e0 : 0x104;
825
- request.clusterId = zclFrame.cluster.ID;
826
- request.srcEndpoint = sourceEndpoint;
827
- request.asduLength = pay.length;
828
- request.asduPayload = [...pay];
829
- request.txOptions = 0;
830
- request.radius = constants_1.default.PARAM.txRadius.UNLIMITED;
624
+ const payload = zclFrame.toBuffer();
625
+ logger_1.logger.debug(`zclFrame to all - ${endpoint}`, NS);
626
+ const request = {
627
+ requestId: transactionID,
628
+ destAddrMode: constants_1.default.PARAM.addressMode.NWK_ADDR,
629
+ destAddr16: destination,
630
+ destEndpoint: endpoint,
631
+ profileId: sourceEndpoint === 242 && endpoint === 242 ? 0xa1e0 : 0x104,
632
+ clusterId: zclFrame.cluster.ID,
633
+ srcEndpoint: sourceEndpoint,
634
+ asduLength: payload.length,
635
+ asduPayload: payload,
636
+ txOptions: 0,
637
+ radius: constants_1.default.PARAM.txRadius.UNLIMITED,
638
+ };
831
639
  logger_1.logger.debug(`sendZclFrameToAll - message send`, NS);
832
640
  return await this.driver.enqueueSendDataRequest(request);
833
641
  }
834
642
  async bind(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, destinationAddressOrGroup, type, destinationEndpoint) {
835
- const transactionID = this.nextTransactionID();
836
- const clid1 = clusterID & 0xff;
837
- const clid2 = (clusterID >> 8) & 0xff;
838
- const destAddrMode = type === 'group' ? constants_1.default.PARAM.addressMode.GROUP_ADDR : constants_1.default.PARAM.addressMode.IEEE_ADDR;
839
- let destArray;
840
- if (type === 'endpoint') {
841
- (0, assert_1.default)(destinationEndpoint, 'Destination endpoint must be defined when `type === endpoint`');
842
- destArray = this.driver.macAddrStringToArray(destinationAddressOrGroup);
843
- destArray = destArray.concat([destinationEndpoint]);
844
- }
845
- else {
846
- destArray = [destinationAddressOrGroup, (destinationAddressOrGroup >> 8) & 0xff];
847
- }
848
- const request = {};
849
- const zdpFrame = [transactionID]
850
- .concat(this.driver.macAddrStringToArray(sourceIeeeAddress))
851
- .concat([sourceEndpoint, clid1, clid2, destAddrMode])
852
- .concat(destArray);
853
- request.requestId = transactionID;
854
- request.destAddrMode = constants_1.default.PARAM.addressMode.NWK_ADDR;
855
- request.destAddr16 = destinationNetworkAddress;
856
- request.destEndpoint = 0;
857
- request.profileId = 0;
858
- request.clusterId = 0x21; // bind_request
859
- request.srcEndpoint = 0;
860
- request.asduLength = zdpFrame.length;
861
- request.asduPayload = zdpFrame;
862
- request.txOptions = 0x04; // 0x04 use APS ACKS
863
- request.radius = constants_1.default.PARAM.txRadius.DEFAULT_RADIUS;
864
- request.timeout = 30;
865
- this.driver
866
- .enqueueSendDataRequest(request)
867
- .then(() => { })
868
- .catch(() => { });
869
- try {
870
- const d = await this.waitForData(destinationNetworkAddress, 0, 0x8021);
871
- const data = d.asduPayload;
872
- logger_1.logger.debug('BIND RESPONSE - addr: 0x' + destinationNetworkAddress.toString(16) + ' status: ' + data[1], NS);
873
- if (data[1] !== 0) {
874
- throw new Error('status: ' + data[1]);
875
- }
876
- }
877
- catch (error) {
878
- logger_1.logger.debug('BIND FAILED - addr: 0x' + destinationNetworkAddress.toString(16) + ' ' + error, NS);
879
- throw error;
643
+ const clusterId = Zdo.ClusterId.BIND_REQUEST;
644
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, sourceIeeeAddress, sourceEndpoint, clusterID, type === 'group' ? Zdo.MULTICAST_BINDING : Zdo.UNICAST_BINDING, destinationAddressOrGroup, // not used with MULTICAST_BINDING
645
+ destinationAddressOrGroup, // not used with UNICAST_BINDING
646
+ destinationEndpoint ?? 0);
647
+ const result = await this.sendZdo(__1.ZSpec.BLANK_EUI64, destinationNetworkAddress, clusterId, zdoPayload, false);
648
+ /* istanbul ignore next */
649
+ if (!Zdo.Buffalo.checkStatus(result)) {
650
+ // TODO: will disappear once moved upstream
651
+ throw new Zdo.StatusError(result[0]);
880
652
  }
881
653
  }
882
654
  async unbind(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, destinationAddressOrGroup, type, destinationEndpoint) {
883
- const transactionID = this.nextTransactionID();
884
- const clid1 = clusterID & 0xff;
885
- const clid2 = (clusterID >> 8) & 0xff;
886
- const destAddrMode = type === 'group' ? constants_1.default.PARAM.addressMode.GROUP_ADDR : constants_1.default.PARAM.addressMode.IEEE_ADDR;
887
- let destArray;
888
- if (type === 'endpoint') {
889
- (0, assert_1.default)(destinationEndpoint, 'Destination endpoint must be defined when `type === endpoint`');
890
- destArray = this.driver.macAddrStringToArray(destinationAddressOrGroup);
891
- destArray = destArray.concat([destinationEndpoint]);
892
- }
893
- else {
894
- destArray = [destinationAddressOrGroup, (destinationAddressOrGroup >> 8) & 0xff];
895
- }
896
- const request = {};
897
- const zdpFrame = [transactionID]
898
- .concat(this.driver.macAddrStringToArray(sourceIeeeAddress))
899
- .concat([sourceEndpoint, clid1, clid2, destAddrMode])
900
- .concat(destArray);
901
- request.requestId = transactionID;
902
- request.destAddrMode = constants_1.default.PARAM.addressMode.NWK_ADDR;
903
- request.destAddr16 = destinationNetworkAddress;
904
- request.destEndpoint = 0;
905
- request.profileId = 0;
906
- request.clusterId = 0x22; // unbind_request
907
- request.srcEndpoint = 0;
908
- request.asduLength = zdpFrame.length;
909
- request.asduPayload = zdpFrame;
910
- request.txOptions = 0x04; // 0x04 use APS ACKS
911
- request.radius = constants_1.default.PARAM.txRadius.DEFAULT_RADIUS;
912
- request.timeout = 30;
913
- this.driver
914
- .enqueueSendDataRequest(request)
915
- .then(() => { })
916
- .catch(() => { });
917
- try {
918
- const d = await this.waitForData(destinationNetworkAddress, 0, 0x8022);
919
- const data = d.asduPayload;
920
- logger_1.logger.debug('UNBIND RESPONSE - addr: 0x' + destinationNetworkAddress.toString(16) + ' status: ' + data[1], NS);
921
- if (data[1] !== 0) {
922
- throw new Error('status: ' + data[1]);
923
- }
924
- }
925
- catch (error) {
926
- logger_1.logger.debug('UNBIND FAILED - addr: 0x' + destinationNetworkAddress.toString(16) + ' ' + error, NS);
927
- throw error;
655
+ const clusterId = Zdo.ClusterId.UNBIND_REQUEST;
656
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, sourceIeeeAddress, sourceEndpoint, clusterID, type === 'group' ? Zdo.MULTICAST_BINDING : Zdo.UNICAST_BINDING, destinationAddressOrGroup, // not used with MULTICAST_BINDING
657
+ destinationAddressOrGroup, // not used with UNICAST_BINDING
658
+ destinationEndpoint ?? 0);
659
+ const result = await this.sendZdo(__1.ZSpec.BLANK_EUI64, destinationNetworkAddress, clusterId, zdoPayload, false);
660
+ /* istanbul ignore next */
661
+ if (!Zdo.Buffalo.checkStatus(result)) {
662
+ // TODO: will disappear once moved upstream
663
+ throw new Zdo.StatusError(result[0]);
928
664
  }
929
665
  }
930
666
  async removeDevice(networkAddress, ieeeAddr) {
931
- const transactionID = this.nextTransactionID();
932
- // const nwk1 = networkAddress & 0xff;
933
- // const nwk2 = (networkAddress >> 8) & 0xff;
934
- const request = {};
935
- //const zdpFrame = [transactionID].concat(this.driver.macAddrStringToArray(ieeeAddr)).concat([0]);
936
- const zdpFrame = [transactionID].concat([0, 0, 0, 0, 0, 0, 0, 0]).concat([0]);
937
- request.requestId = transactionID;
938
- request.destAddrMode = constants_1.default.PARAM.addressMode.NWK_ADDR;
939
- request.destAddr16 = networkAddress;
940
- request.destEndpoint = 0;
941
- request.profileId = 0;
942
- request.clusterId = 0x34; // mgmt_leave_request
943
- request.srcEndpoint = 0;
944
- request.asduLength = 10;
945
- request.asduPayload = zdpFrame;
946
- request.txOptions = 0;
947
- request.radius = constants_1.default.PARAM.txRadius.DEFAULT_RADIUS;
948
- this.driver
949
- .enqueueSendDataRequest(request)
950
- .then(() => { })
951
- .catch(() => { });
952
- try {
953
- const d = await this.waitForData(networkAddress, 0, 0x8034);
954
- const data = d.asduPayload;
955
- logger_1.logger.debug('REMOVE_DEVICE - addr: 0x' + networkAddress.toString(16) + ' status: ' + data[1], NS);
956
- const payload = {
957
- networkAddress: networkAddress,
958
- ieeeAddr: ieeeAddr,
959
- };
960
- if (data[1] !== 0) {
961
- throw new Error('status: ' + data[1]);
962
- }
963
- this.emit('deviceLeave', payload);
964
- }
965
- catch (error) {
966
- logger_1.logger.debug('REMOVE_DEVICE FAILED - addr: 0x' + networkAddress.toString(16) + ' ' + error, NS);
967
- throw error;
667
+ const clusterId = Zdo.ClusterId.LEAVE_REQUEST;
668
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, ieeeAddr, Zdo.LeaveRequestFlags.WITHOUT_REJOIN);
669
+ const result = await this.sendZdo(__1.ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
670
+ /* istanbul ignore next */
671
+ if (!Zdo.Buffalo.checkStatus(result)) {
672
+ // TODO: will disappear once moved upstream
673
+ throw new Zdo.StatusError(result[0]);
968
674
  }
969
675
  }
970
676
  async supportsBackup() {
@@ -1009,9 +715,11 @@ class DeconzAdapter extends adapter_1.default {
1009
715
  async setChannelInterPAN(channel) {
1010
716
  throw new Error('not supported');
1011
717
  }
1012
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1013
718
  async changeChannel(newChannel) {
1014
- throw new Error(`Channel change is not supported for 'deconz'`);
719
+ const clusterId = Zdo.ClusterId.NWK_UPDATE_REQUEST;
720
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, [newChannel], 0xfe, undefined, undefined, undefined);
721
+ await this.sendZdo(__1.ZSpec.BLANK_EUI64, __1.ZSpec.BroadcastAddress.SLEEPY, clusterId, zdoPayload, true /* handled below */);
722
+ await (0, utils_1.Wait)(12000);
1015
723
  }
1016
724
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
1017
725
  async setTransmitPower(value) {
@@ -1024,9 +732,6 @@ class DeconzAdapter extends adapter_1.default {
1024
732
  /**
1025
733
  * Private methods
1026
734
  */
1027
- sleep(ms) {
1028
- return new Promise((resolve) => setTimeout(resolve, ms));
1029
- }
1030
735
  waitForData(addr, profileId, clusterId, transactionSequenceNumber, timeout) {
1031
736
  return new Promise((resolve, reject) => {
1032
737
  const ts = Date.now();
@@ -1063,10 +768,10 @@ class DeconzAdapter extends adapter_1.default {
1063
768
  this.emit('zclPayload', payload);
1064
769
  }
1065
770
  checkReceivedDataPayload(resp) {
1066
- let srcAddr = undefined;
771
+ let srcAddr;
772
+ let srcEUI64;
1067
773
  let header;
1068
- const payBuf = resp != null ? Buffer.from(resp.asduPayload) : undefined;
1069
- if (resp != null) {
774
+ if (resp) {
1070
775
  if (resp.srcAddr16 != null) {
1071
776
  srcAddr = resp.srcAddr16;
1072
777
  }
@@ -1085,26 +790,38 @@ class DeconzAdapter extends adapter_1.default {
1085
790
  // so let's make sure they get the network address
1086
791
  resp.srcAddr16 = srcAddr; // TODO: can't be undefined
1087
792
  }
1088
- if (resp.profileId != 0x00) {
1089
- header = Zcl.Header.fromBuffer(payBuf); // valid from check
793
+ if (resp.profileId === Zdo.ZDO_PROFILE_ID) {
794
+ if (resp.clusterId === Zdo.ClusterId.NETWORK_ADDRESS_RESPONSE) {
795
+ if (Zdo.Buffalo.checkStatus(resp.zdo)) {
796
+ srcEUI64 = resp.zdo[1].eui64;
797
+ }
798
+ }
799
+ else if (resp.clusterId === Zdo.ClusterId.END_DEVICE_ANNOUNCE) {
800
+ // XXX: using same response for announce (handled by controller) or joined depending on permit join status?
801
+ if (this.joinPermitted === true && Zdo.Buffalo.checkStatus(resp.zdo)) {
802
+ const payload = resp.zdo[1];
803
+ this.emit('deviceJoined', { networkAddress: payload.nwkAddress, ieeeAddr: payload.eui64 });
804
+ }
805
+ }
806
+ this.emit('zdoResponse', resp.clusterId, resp.zdo);
807
+ }
808
+ else {
809
+ header = Zcl.Header.fromBuffer(resp.asduPayload);
1090
810
  }
1091
811
  }
1092
812
  let i = this.openRequestsQueue.length;
1093
813
  while (i--) {
1094
814
  const req = this.openRequestsQueue[i];
1095
- if (srcAddr != null && req.addr === srcAddr && req.clusterId === resp?.clusterId && req.profileId === resp?.profileId) {
1096
- if (header !== undefined && req.transactionSequenceNumber != undefined) {
1097
- if (req.transactionSequenceNumber === header.transactionSequenceNumber) {
1098
- logger_1.logger.debug('resolve data request with transSeq Nr.: ' + req.transactionSequenceNumber, NS);
1099
- this.openRequestsQueue.splice(i, 1);
1100
- req.resolve?.(resp);
1101
- }
1102
- }
1103
- else {
1104
- logger_1.logger.debug('resolve data request without a transSeq Nr.', NS);
1105
- this.openRequestsQueue.splice(i, 1);
1106
- req.resolve?.(resp);
1107
- }
815
+ if (resp &&
816
+ (req.addr === undefined ||
817
+ (typeof req.addr === 'number' ? srcAddr !== undefined && req.addr === srcAddr : srcEUI64 && req.addr === srcEUI64)) &&
818
+ req.clusterId === resp.clusterId &&
819
+ req.profileId === resp.profileId &&
820
+ (header === undefined ||
821
+ req.transactionSequenceNumber === undefined ||
822
+ req.transactionSequenceNumber === header.transactionSequenceNumber)) {
823
+ this.openRequestsQueue.splice(i, 1);
824
+ req.resolve(resp);
1108
825
  }
1109
826
  const now = Date.now();
1110
827
  // Default timeout: 60 seconds.
@@ -1113,28 +830,14 @@ class DeconzAdapter extends adapter_1.default {
1113
830
  //logger.debug("Timeout for request in openRequestsQueue addr: " + req.addr.toString(16) + " clusterId: " + req.clusterId.toString(16) + " profileId: " + req.profileId.toString(16), NS);
1114
831
  //remove from busyQueue
1115
832
  this.openRequestsQueue.splice(i, 1);
1116
- req.reject?.('waiting for response TIMEOUT');
1117
- }
1118
- }
1119
- // check unattended incomming messages
1120
- if (resp != null && resp.profileId === 0x00 && resp.clusterId === 0x13) {
1121
- // device Annce
1122
- const payload = {
1123
- networkAddress: payBuf.readUInt16LE(1), // valid from check
1124
- ieeeAddr: this.driver.macAddrArrayToString(resp.asduPayload.slice(3, 11)),
1125
- };
1126
- if (this.joinPermitted === true) {
1127
- this.emit('deviceJoined', payload);
1128
- }
1129
- else {
1130
- this.emit('deviceAnnounce', payload);
833
+ req.reject(new Error('waiting for response TIMEOUT'));
1131
834
  }
1132
835
  }
1133
- if (resp != null && resp.profileId != 0x00) {
836
+ if (resp && resp.profileId != Zdo.ZDO_PROFILE_ID) {
1134
837
  const payload = {
1135
838
  clusterID: resp.clusterId,
1136
839
  header,
1137
- data: payBuf, // valid from check
840
+ data: resp.asduPayload,
1138
841
  address: resp.destAddrMode === 0x03 ? `0x${resp.srcAddr64}` : resp.srcAddr16,
1139
842
  endpoint: resp.srcEndpoint,
1140
843
  linkquality: resp.lqi,