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
@@ -37,6 +37,8 @@ const adapter_1 = __importDefault(require("../../adapter"));
37
37
  const Constants = __importStar(require("../constants"));
38
38
  const unpi_1 = require("../unpi");
39
39
  const znp_1 = require("../znp");
40
+ const definition_1 = __importDefault(require("../znp/definition"));
41
+ const utils_2 = require("../znp/utils");
40
42
  const manager_1 = require("./manager");
41
43
  const tstype_1 = require("./tstype");
42
44
  const NS = 'zh:zstack';
@@ -175,14 +177,23 @@ class ZStackAdapter extends adapter_1.default {
175
177
  });
176
178
  }
177
179
  async permitJoin(seconds, networkAddress) {
178
- const addrmode = networkAddress === undefined ? 0x0f : 0x02;
179
- const dstaddr = networkAddress || 0xfffc;
180
+ const clusterId = Zdo.ClusterId.PERMIT_JOINING_REQUEST;
181
+ // `authentication`: TC significance always 1 (zb specs)
182
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, seconds, 1, []);
183
+ if (networkAddress === undefined) {
184
+ await this.sendZdo(ZSpec.BLANK_EUI64, ZSpec.BroadcastAddress.DEFAULT, clusterId, zdoPayload, true);
185
+ }
186
+ else {
187
+ // NOTE: `sendZdo` takes care of adjusting the payload as appropriate based on `networkAddress === 0` or not
188
+ const result = await this.sendZdo(ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
189
+ /* istanbul ignore next */
190
+ if (!Zdo.Buffalo.checkStatus(result)) {
191
+ // TODO: will disappear once moved upstream
192
+ throw new Zdo.StatusError(result[0]);
193
+ }
194
+ }
180
195
  await this.queue.execute(async () => {
181
196
  this.checkInterpanLock();
182
- const payload = { addrmode, dstaddr, duration: seconds, tcsignificance: 0 };
183
- const permitJoinRsp = this.waitForAreqZdo('mgmtPermitJoinRsp');
184
- await this.znp.request(Subsystem.ZDO, 'mgmtPermitJoinReq', payload);
185
- await permitJoinRsp.start();
186
197
  await this.setLED(seconds == 0 ? 'off' : 'on');
187
198
  });
188
199
  }
@@ -231,10 +242,17 @@ class ZStackAdapter extends adapter_1.default {
231
242
  * this is currently not handled, the first nwkAddrRsp is taken.
232
243
  */
233
244
  logger_1.logger.debug(`Request network address of '${ieeeAddr}'`, NS);
234
- const response = this.waitForAreqZdo('nwkAddrRsp', { ieeeaddr: ieeeAddr });
235
- await this.znp.request(Subsystem.ZDO, 'nwkAddrReq', { ieeeaddr: ieeeAddr, reqtype: 0, startindex: 0 });
236
- const result = await response.start();
237
- return result.nwkAddress;
245
+ const clusterId = Zdo.ClusterId.NETWORK_ADDRESS_REQUEST;
246
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, ieeeAddr, false, 0);
247
+ const result = await this.sendZdo(ieeeAddr, ZSpec.NULL_NODE_ID, clusterId, zdoPayload, false);
248
+ /* istanbul ignore else */
249
+ if (Zdo.Buffalo.checkStatus(result)) {
250
+ return result[1].nwkAddress;
251
+ }
252
+ else {
253
+ // TODO: will disappear once moved upstream
254
+ throw new Zdo.StatusError(result[0]);
255
+ }
238
256
  }
239
257
  supportsAssocRemove() {
240
258
  return this.version.product === tstype_1.ZnpVersion.zStack3x0 && parseInt(this.version.revision) >= 20200805;
@@ -251,67 +269,141 @@ class ZStackAdapter extends adapter_1.default {
251
269
  }
252
270
  }
253
271
  async nodeDescriptor(networkAddress) {
254
- return await this.queue.execute(async () => {
255
- this.checkInterpanLock();
256
- try {
257
- const result = await this.nodeDescriptorInternal(networkAddress);
258
- return result;
259
- }
260
- catch (error) {
261
- logger_1.logger.debug(`Node descriptor request for '${networkAddress}' failed (${error}), retry`, NS);
262
- // Doing a route discovery after simple descriptor request fails makes it succeed sometimes.
263
- // https://github.com/Koenkk/zigbee2mqtt/issues/3276
264
- await this.discoverRoute(networkAddress);
265
- const result = await this.nodeDescriptorInternal(networkAddress);
266
- return result;
267
- }
268
- }, networkAddress);
269
- }
270
- async nodeDescriptorInternal(networkAddress) {
271
- const response = this.waitForAreqZdo('nodeDescRsp', { srcaddr: networkAddress });
272
- const payload = { dstaddr: networkAddress, nwkaddrofinterest: networkAddress };
273
- await this.znp.request(Subsystem.ZDO, 'nodeDescReq', payload, response.ID);
274
- const descriptor = await response.start();
275
- let type = 'Unknown';
276
- const logicalType = descriptor.logicalType;
277
- for (const [key, value] of Object.entries(Constants.ZDO.deviceLogicalType)) {
278
- if (value === logicalType) {
279
- if (key === 'COORDINATOR')
272
+ const clusterId = Zdo.ClusterId.NODE_DESCRIPTOR_REQUEST;
273
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, networkAddress);
274
+ const result = await this.sendZdo(ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
275
+ /* istanbul ignore else */
276
+ if (Zdo.Buffalo.checkStatus(result)) {
277
+ const payload = result[1];
278
+ let type = 'Unknown';
279
+ switch (payload.logicalType) {
280
+ case 0x0:
280
281
  type = 'Coordinator';
281
- else if (key === 'ROUTER')
282
+ break;
283
+ case 0x1:
282
284
  type = 'Router';
283
- else if (key === 'ENDDEVICE')
285
+ break;
286
+ case 0x2:
284
287
  type = 'EndDevice';
285
- break;
288
+ break;
286
289
  }
290
+ return { type, manufacturerCode: payload.manufacturerCode };
291
+ }
292
+ else {
293
+ // TODO: will disappear once moved upstream
294
+ throw new Zdo.StatusError(result[0]);
287
295
  }
288
- return { manufacturerCode: descriptor.manufacturerCode, type };
289
296
  }
290
297
  async activeEndpoints(networkAddress) {
291
- return await this.queue.execute(async () => {
292
- this.checkInterpanLock();
293
- const response = this.waitForAreqZdo('activeEpRsp', { srcaddr: networkAddress });
294
- const payload = { dstaddr: networkAddress, nwkaddrofinterest: networkAddress };
295
- await this.znp.request(Subsystem.ZDO, 'activeEpReq', payload, response.ID);
296
- const activeEp = await response.start();
297
- return { endpoints: activeEp.endpointList };
298
- }, networkAddress);
298
+ const clusterId = Zdo.ClusterId.ACTIVE_ENDPOINTS_REQUEST;
299
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, networkAddress);
300
+ const result = await this.sendZdo(ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
301
+ /* istanbul ignore else */
302
+ if (Zdo.Buffalo.checkStatus(result)) {
303
+ return { endpoints: result[1].endpointList };
304
+ }
305
+ else {
306
+ // TODO: will disappear once moved upstream
307
+ throw new Zdo.StatusError(result[0]);
308
+ }
299
309
  }
300
310
  async simpleDescriptor(networkAddress, endpointID) {
301
- return await this.queue.execute(async () => {
302
- this.checkInterpanLock();
303
- const response = this.waitForAreqZdo('simpleDescRsp', { srcaddr: networkAddress });
304
- const payload = { dstaddr: networkAddress, nwkaddrofinterest: networkAddress, endpoint: endpointID };
305
- await this.znp.request(Subsystem.ZDO, 'simpleDescReq', payload, response.ID);
306
- const descriptor = await response.start();
311
+ const clusterId = Zdo.ClusterId.SIMPLE_DESCRIPTOR_REQUEST;
312
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, networkAddress, endpointID);
313
+ const result = await this.sendZdo(ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
314
+ /* istanbul ignore else */
315
+ if (Zdo.Buffalo.checkStatus(result)) {
316
+ const payload = result[1];
307
317
  return {
308
- profileID: descriptor.profileId,
309
- endpointID: descriptor.endpoint,
310
- deviceID: descriptor.deviceId,
311
- inputClusters: descriptor.inClusterList,
312
- outputClusters: descriptor.outClusterList,
318
+ profileID: payload.profileId,
319
+ endpointID: payload.endpoint,
320
+ deviceID: payload.deviceId,
321
+ inputClusters: payload.inClusterList,
322
+ outputClusters: payload.outClusterList,
313
323
  };
314
- }, networkAddress);
324
+ }
325
+ else {
326
+ // TODO: will disappear once moved upstream
327
+ throw new Zdo.StatusError(result[0]);
328
+ }
329
+ }
330
+ async sendZdo(ieeeAddress, networkAddress, clusterId, payload, disableResponse) {
331
+ return await this.queue.execute(async () => {
332
+ this.checkInterpanLock();
333
+ // stack-specific requirements
334
+ switch (clusterId) {
335
+ case Zdo.ClusterId.PERMIT_JOINING_REQUEST: {
336
+ const finalPayload = Buffer.alloc(payload.length + 3);
337
+ finalPayload.writeUInt8(ZSpec.BroadcastAddress[networkAddress] ? AddressMode.ADDR_BROADCAST : AddressMode.ADDR_16BIT, 0);
338
+ // zstack uses AddressMode.ADDR_16BIT + ZSpec.BroadcastAddress.DEFAULT to signal "coordinator-only"
339
+ finalPayload.writeUInt16LE(networkAddress === 0 ? ZSpec.BroadcastAddress.DEFAULT : networkAddress, 1);
340
+ finalPayload.set(payload, 3);
341
+ payload = finalPayload;
342
+ break;
343
+ }
344
+ case Zdo.ClusterId.NWK_UPDATE_REQUEST: {
345
+ // extra zeroes for empty nwkManagerAddr if necessary
346
+ const zeroes = 9 - payload.length - 1; /* zstack doesn't have nwkUpdateId */
347
+ const finalPayload = Buffer.alloc(payload.length + 3 + zeroes);
348
+ finalPayload.writeUInt16LE(networkAddress, 0);
349
+ finalPayload.writeUInt8(ZSpec.BroadcastAddress[networkAddress] ? AddressMode.ADDR_BROADCAST : AddressMode.ADDR_16BIT, 2);
350
+ finalPayload.set(payload, 3);
351
+ payload = finalPayload;
352
+ break;
353
+ }
354
+ case Zdo.ClusterId.BIND_REQUEST:
355
+ case Zdo.ClusterId.UNBIND_REQUEST: {
356
+ // extra zeroes for uint16 (in place of ieee when MULTICAST) and endpoint (not used when MULTICAST)
357
+ const zeroes = 21 - payload.length;
358
+ const finalPayload = Buffer.alloc(payload.length + 2 + zeroes);
359
+ finalPayload.writeUInt16LE(networkAddress, 0);
360
+ finalPayload.set(payload, 2);
361
+ payload = finalPayload;
362
+ break;
363
+ }
364
+ case Zdo.ClusterId.NETWORK_ADDRESS_REQUEST:
365
+ case Zdo.ClusterId.IEEE_ADDRESS_REQUEST: {
366
+ // no modification necessary
367
+ break;
368
+ }
369
+ default: {
370
+ const finalPayload = Buffer.alloc(payload.length + 2);
371
+ finalPayload.writeUInt16LE(networkAddress, 0);
372
+ finalPayload.set(payload, 2);
373
+ payload = finalPayload;
374
+ break;
375
+ }
376
+ }
377
+ let waiter;
378
+ if (!disableResponse) {
379
+ const responseClusterId = Zdo.Utils.getResponseClusterId(clusterId);
380
+ /* istanbul ignore else */
381
+ if (responseClusterId) {
382
+ const cmd = definition_1.default[Subsystem.ZDO].find((c) => (0, utils_2.isMtCmdAreqZdo)(c) && c.zdoClusterId === responseClusterId);
383
+ (0, assert_1.default)(cmd, `Response for ZDO cluster ID '${responseClusterId}' not supported.`);
384
+ waiter = this.znp.waitFor(unpi_1.Constants.Type.AREQ, Subsystem.ZDO, cmd.name, responseClusterId === Zdo.ClusterId.NETWORK_ADDRESS_RESPONSE ? ieeeAddress : networkAddress, undefined, undefined);
385
+ }
386
+ }
387
+ try {
388
+ await this.znp.requestZdo(clusterId, payload, waiter?.ID);
389
+ }
390
+ catch (error) {
391
+ if (clusterId === Zdo.ClusterId.NODE_DESCRIPTOR_REQUEST) {
392
+ // Discover route when node descriptor request fails
393
+ // https://github.com/Koenkk/zigbee2mqtt/issues/3276
394
+ logger_1.logger.debug(`Discover route to '${networkAddress}' because node descriptor request failed`, NS);
395
+ await this.discoverRoute(networkAddress);
396
+ await this.znp.requestZdo(clusterId, payload, waiter?.ID);
397
+ }
398
+ else {
399
+ throw error;
400
+ }
401
+ }
402
+ if (waiter) {
403
+ const response = await waiter.start().promise;
404
+ return response.payload.zdo;
405
+ }
406
+ }, networkAddress /* TODO: replace with ieeeAddress once zdo moved upstream */);
315
407
  }
316
408
  async sendZclFrameToEndpoint(ieeeAddr, networkAddress, endpoint, zclFrame, timeout, disableResponse, disableRecovery, sourceEndpoint) {
317
409
  return await this.queue.execute(async () => {
@@ -498,68 +590,70 @@ class ZStackAdapter extends adapter_1.default {
498
590
  });
499
591
  }
500
592
  async lqi(networkAddress) {
501
- return await this.queue.execute(async () => {
502
- this.checkInterpanLock();
503
- const neighbors = [];
504
- const request = async (startIndex) => {
505
- const response = this.waitForAreqZdo('mgmtLqiRsp', { srcaddr: networkAddress });
506
- await this.znp.request(Subsystem.ZDO, 'mgmtLqiReq', { dstaddr: networkAddress, startindex: startIndex }, response.ID);
507
- const result = await response.start();
508
- return result;
509
- };
510
- const add = (list) => {
511
- for (const entry of list) {
593
+ const clusterId = Zdo.ClusterId.LQI_TABLE_REQUEST;
594
+ const neighbors = [];
595
+ const request = async (startIndex) => {
596
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, startIndex);
597
+ const result = await this.sendZdo(ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
598
+ /* istanbul ignore else */
599
+ if (Zdo.Buffalo.checkStatus(result)) {
600
+ const payload = result[1];
601
+ for (const entry of payload.entryList) {
512
602
  neighbors.push({
513
- linkquality: entry.lqi,
514
- networkAddress: entry.nwkAddress,
515
603
  ieeeAddr: entry.eui64,
604
+ networkAddress: entry.nwkAddress,
605
+ linkquality: entry.lqi,
516
606
  relationship: entry.relationship,
517
607
  depth: entry.depth,
518
608
  });
519
609
  }
520
- };
521
- let response = await request(0);
522
- add(response.entryList);
523
- const size = response.neighborTableEntries;
524
- let nextStartIndex = response.entryList.length;
525
- while (neighbors.length < size) {
526
- response = await request(nextStartIndex);
527
- add(response.entryList);
528
- nextStartIndex += response.entryList.length;
529
- }
530
- return { neighbors };
531
- }, networkAddress);
610
+ return [payload.neighborTableEntries, payload.entryList.length];
611
+ }
612
+ else {
613
+ // TODO: will disappear once moved upstream
614
+ throw new Zdo.StatusError(result[0]);
615
+ }
616
+ };
617
+ let [tableEntries, entryCount] = await request(0);
618
+ const size = tableEntries;
619
+ let nextStartIndex = entryCount;
620
+ while (neighbors.length < size) {
621
+ [tableEntries, entryCount] = await request(nextStartIndex);
622
+ nextStartIndex += entryCount;
623
+ }
624
+ return { neighbors };
532
625
  }
533
626
  async routingTable(networkAddress) {
534
- return await this.queue.execute(async () => {
535
- this.checkInterpanLock();
536
- const table = [];
537
- const request = async (startIndex) => {
538
- const response = this.waitForAreqZdo('mgmtRtgRsp', { srcaddr: networkAddress });
539
- await this.znp.request(Subsystem.ZDO, 'mgmtRtgReq', { dstaddr: networkAddress, startindex: startIndex }, response.ID);
540
- const result = await response.start();
541
- return result;
542
- };
543
- const add = (list) => {
544
- for (const entry of list) {
627
+ const clusterId = Zdo.ClusterId.ROUTING_TABLE_REQUEST;
628
+ const table = [];
629
+ const request = async (startIndex) => {
630
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, startIndex);
631
+ const result = await this.sendZdo(ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
632
+ /* istanbul ignore else */
633
+ if (Zdo.Buffalo.checkStatus(result)) {
634
+ const payload = result[1];
635
+ for (const entry of payload.entryList) {
545
636
  table.push({
546
637
  destinationAddress: entry.destinationAddress,
547
638
  status: entry.status,
548
639
  nextHop: entry.nextHopAddress,
549
640
  });
550
641
  }
551
- };
552
- let response = await request(0);
553
- add(response.entryList);
554
- const size = response.routingTableEntries;
555
- let nextStartIndex = response.entryList.length;
556
- while (table.length < size) {
557
- response = await request(nextStartIndex);
558
- add(response.entryList);
559
- nextStartIndex += response.entryList.length;
560
- }
561
- return { table };
562
- }, networkAddress);
642
+ return [payload.routingTableEntries, payload.entryList.length];
643
+ }
644
+ else {
645
+ // TODO: will disappear once moved upstream
646
+ throw new Zdo.StatusError(result[0]);
647
+ }
648
+ };
649
+ let [tableEntries, entryCount] = await request(0);
650
+ const size = tableEntries;
651
+ let nextStartIndex = entryCount;
652
+ while (table.length < size) {
653
+ [tableEntries, entryCount] = await request(nextStartIndex);
654
+ nextStartIndex += entryCount;
655
+ }
656
+ return { table };
563
657
  }
564
658
  async addInstallCode(ieeeAddress, key) {
565
659
  (0, assert_1.default)(this.version.product !== tstype_1.ZnpVersion.zStack12, 'Install code is not supported for ZStack 1.2 adapter');
@@ -567,40 +661,38 @@ class ZStackAdapter extends adapter_1.default {
567
661
  await this.znp.request(Subsystem.APP_CNF, 'bdbAddInstallCode', payload);
568
662
  }
569
663
  async bind(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, destinationAddressOrGroup, type, destinationEndpoint) {
570
- await this.bindInternal('bind', destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, destinationAddressOrGroup, type, destinationEndpoint);
664
+ const clusterId = Zdo.ClusterId.BIND_REQUEST;
665
+ 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
666
+ destinationAddressOrGroup, // not used with UNICAST_BINDING
667
+ destinationEndpoint ?? 0);
668
+ const result = await this.sendZdo(ZSpec.BLANK_EUI64, destinationNetworkAddress, clusterId, zdoPayload, false);
669
+ /* istanbul ignore next */
670
+ if (!Zdo.Buffalo.checkStatus(result)) {
671
+ // TODO: will disappear once moved upstream
672
+ throw new Zdo.StatusError(result[0]);
673
+ }
571
674
  }
572
675
  async unbind(destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, destinationAddressOrGroup, type, destinationEndpoint) {
573
- await this.bindInternal('unbind', destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, destinationAddressOrGroup, type, destinationEndpoint);
574
- }
575
- async bindInternal(bindType, destinationNetworkAddress, sourceIeeeAddress, sourceEndpoint, clusterID, destinationAddressOrGroup, targetType, destinationEndpoint) {
576
- return await this.queue.execute(async () => {
577
- this.checkInterpanLock();
578
- const response = this.waitForAreqZdo(`${bindType}Rsp`, { srcaddr: destinationNetworkAddress });
579
- const payload = {
580
- dstaddr: destinationNetworkAddress,
581
- srcaddr: sourceIeeeAddress,
582
- srcendpoint: sourceEndpoint,
583
- clusterid: clusterID,
584
- dstaddrmode: targetType === 'group' ? AddressMode.ADDR_GROUP : AddressMode.ADDR_64BIT,
585
- dstaddress: this.toAddressString(destinationAddressOrGroup),
586
- dstendpoint: targetType === 'group' ? 0xff : destinationEndpoint,
587
- };
588
- await this.znp.request(Subsystem.ZDO, `${bindType}Req`, payload, response.ID);
589
- await response.start();
590
- }, destinationNetworkAddress);
676
+ const clusterId = Zdo.ClusterId.UNBIND_REQUEST;
677
+ 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
678
+ destinationAddressOrGroup, // not used with UNICAST_BINDING
679
+ destinationEndpoint ?? 0);
680
+ const result = await this.sendZdo(ZSpec.BLANK_EUI64, destinationNetworkAddress, clusterId, zdoPayload, false);
681
+ /* istanbul ignore next */
682
+ if (!Zdo.Buffalo.checkStatus(result)) {
683
+ // TODO: will disappear once moved upstream
684
+ throw new Zdo.StatusError(result[0]);
685
+ }
591
686
  }
592
- removeDevice(networkAddress, ieeeAddr) {
593
- return this.queue.execute(async () => {
594
- this.checkInterpanLock();
595
- const response = this.waitForAreqZdo('mgmtLeaveRsp', { srcaddr: networkAddress });
596
- const payload = {
597
- dstaddr: networkAddress,
598
- deviceaddress: ieeeAddr,
599
- removechildrenRejoin: 0,
600
- };
601
- await this.znp.request(Subsystem.ZDO, 'mgmtLeaveReq', payload, response.ID);
602
- await response.start();
603
- }, networkAddress);
687
+ async removeDevice(networkAddress, ieeeAddr) {
688
+ const clusterId = Zdo.ClusterId.LEAVE_REQUEST;
689
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, ieeeAddr, Zdo.LeaveRequestFlags.WITHOUT_REJOIN);
690
+ const result = await this.sendZdo(ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
691
+ /* istanbul ignore next */
692
+ if (!Zdo.Buffalo.checkStatus(result)) {
693
+ // TODO: will disappear once moved upstream
694
+ throw new Zdo.StatusError(result[0]);
695
+ }
604
696
  }
605
697
  /**
606
698
  * Event handlers
@@ -615,6 +707,9 @@ class ZStackAdapter extends adapter_1.default {
615
707
  return;
616
708
  }
617
709
  if (object.subsystem === Subsystem.ZDO) {
710
+ if ((0, utils_2.isMtCmdAreqZdo)(object.command)) {
711
+ this.emit('zdoResponse', object.command.zdoClusterId, object.payload.zdo);
712
+ }
618
713
  if (object.command.name === 'tcDeviceInd') {
619
714
  const payload = {
620
715
  networkAddress: object.payload.nwkaddr,
@@ -623,15 +718,16 @@ class ZStackAdapter extends adapter_1.default {
623
718
  this.emit('deviceJoined', payload);
624
719
  }
625
720
  else if (object.command.name === 'endDeviceAnnceInd') {
626
- const zdoResult = object.parseZdoPayload();
721
+ // TODO: better way???
627
722
  /* istanbul ignore else */
628
- if (Zdo.Buffalo.checkStatus(zdoResult)) {
723
+ if (Zdo.Buffalo.checkStatus(object.payload.zdo)) {
724
+ const zdoPayload = object.payload.zdo[1];
629
725
  const payload = {
630
- networkAddress: zdoResult[1].nwkAddress,
631
- ieeeAddr: zdoResult[1].eui64,
726
+ networkAddress: zdoPayload.nwkAddress,
727
+ ieeeAddr: zdoPayload.eui64,
632
728
  };
633
729
  // Only discover routes to end devices, if bit 1 of capabilities === 0 it's an end device.
634
- const isEndDevice = zdoResult[1].capabilities.deviceType === 0;
730
+ const isEndDevice = zdoPayload.capabilities.deviceType === 0;
635
731
  if (isEndDevice) {
636
732
  if (!this.deviceAnnounceRouteDiscoveryDebouncers.has(payload.networkAddress)) {
637
733
  // If a device announces multiple times in a very short time, it makes no sense
@@ -649,18 +745,6 @@ class ZStackAdapter extends adapter_1.default {
649
745
  (0, assert_1.default)(debouncer);
650
746
  debouncer();
651
747
  }
652
- this.emit('deviceAnnounce', payload);
653
- }
654
- }
655
- else if (object.command.name === 'nwkAddrRsp') {
656
- const zdoResult = object.parseZdoPayload();
657
- /* istanbul ignore else */
658
- if (Zdo.Buffalo.checkStatus(zdoResult)) {
659
- const payload = {
660
- networkAddress: zdoResult[1].nwkAddress,
661
- ieeeAddr: zdoResult[1].eui64,
662
- };
663
- this.emit('networkAddress', payload);
664
748
  }
665
749
  }
666
750
  else if (object.command.name === 'concentratorIndCb') {
@@ -674,11 +758,15 @@ class ZStackAdapter extends adapter_1.default {
674
758
  // mappings.
675
759
  // https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/158/4403.zstacktask.c
676
760
  // https://github.com/Koenkk/zigbee-herdsman/issues/74
677
- const payload = {
678
- networkAddress: object.payload.srcaddr,
679
- ieeeAddr: object.payload.extaddr,
680
- };
681
- this.emit('networkAddress', payload);
761
+ this.emit('zdoResponse', Zdo.ClusterId.NETWORK_ADDRESS_RESPONSE, [
762
+ Zdo.Status.SUCCESS,
763
+ {
764
+ eui64: object.payload.extaddr,
765
+ nwkAddress: object.payload.srcaddr,
766
+ startIndex: 0,
767
+ assocDevList: [],
768
+ },
769
+ ]);
682
770
  }
683
771
  else {
684
772
  /* istanbul ignore else */
@@ -774,46 +862,17 @@ class ZStackAdapter extends adapter_1.default {
774
862
  });
775
863
  }
776
864
  async changeChannel(newChannel) {
777
- return await this.queue.execute(async () => {
778
- this.checkInterpanLock();
779
- const payload = {
780
- dstaddr: 0xffff, // broadcast with sleepy
781
- dstaddrmode: AddressMode.ADDR_BROADCAST,
782
- channelmask: [newChannel].reduce((a, c) => a + (1 << c), 0),
783
- scanduration: 0xfe, // change channel
784
- scancount: 0,
785
- nwkmanageraddr: 0,
786
- };
787
- await this.znp.request(Subsystem.ZDO, 'mgmtNwkUpdateReq', payload);
788
- // wait for the broadcast to propagate and the adapter to actually change
789
- await (0, utils_1.Wait)(10000);
790
- });
865
+ const clusterId = Zdo.ClusterId.NWK_UPDATE_REQUEST;
866
+ const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, [newChannel], 0xfe, 0, undefined, 0);
867
+ await this.sendZdo(ZSpec.BLANK_EUI64, ZSpec.BroadcastAddress.SLEEPY, clusterId, zdoPayload, true /* handled below */);
868
+ // wait for the broadcast to propagate and the adapter to actually change
869
+ await (0, utils_1.Wait)(10000);
791
870
  }
792
871
  async setTransmitPower(value) {
793
872
  return await this.queue.execute(async () => {
794
873
  await this.znp.request(Subsystem.SYS, 'stackTune', { operation: 0, value });
795
874
  });
796
875
  }
797
- waitForAreqZdo(command, payload) {
798
- const result = this.znp.waitFor(unpi_1.Constants.Type.AREQ, Subsystem.ZDO, command, payload);
799
- const start = () => {
800
- const startResult = result.start();
801
- return new Promise((resolve, reject) => {
802
- startResult.promise
803
- .then((response) => {
804
- const [status, payload] = response.parseZdoPayload();
805
- if (status === Zdo.Status.SUCCESS) {
806
- resolve(payload);
807
- }
808
- else {
809
- reject(new Zdo.StatusError(status));
810
- }
811
- })
812
- .catch(reject);
813
- });
814
- };
815
- return { start, ID: result.ID };
816
- }
817
876
  waitForInternal(networkAddress, endpoint, frameType, direction, transactionSequenceNumber, clusterID, commandIdentifier, timeout) {
818
877
  const payload = {
819
878
  address: networkAddress,
@@ -837,7 +896,7 @@ class ZStackAdapter extends adapter_1.default {
837
896
  */
838
897
  async dataRequest(destinationAddress, destinationEndpoint, sourceEndpoint, clusterID, radius, data, timeout) {
839
898
  const transactionID = this.nextTransactionID();
840
- const response = this.znp.waitFor(Type.AREQ, Subsystem.AF, 'dataConfirm', { transid: transactionID }, timeout);
899
+ const response = this.znp.waitFor(Type.AREQ, Subsystem.AF, 'dataConfirm', undefined, transactionID, undefined, timeout);
841
900
  await this.znp.request(Subsystem.AF, 'dataRequest', {
842
901
  dstaddr: destinationAddress,
843
902
  destendpoint: destinationEndpoint,
@@ -861,7 +920,9 @@ class ZStackAdapter extends adapter_1.default {
861
920
  }
862
921
  async dataRequestExtended(addressMode, destinationAddressOrGroupID, destinationEndpoint, panID, sourceEndpoint, clusterID, radius, data, timeout, confirmation, attemptsLeft = 5) {
863
922
  const transactionID = this.nextTransactionID();
864
- const response = confirmation ? this.znp.waitFor(Type.AREQ, Subsystem.AF, 'dataConfirm', { transid: transactionID }, timeout) : undefined;
923
+ const response = confirmation
924
+ ? this.znp.waitFor(Type.AREQ, Subsystem.AF, 'dataConfirm', undefined, transactionID, undefined, timeout)
925
+ : undefined;
865
926
  await this.znp.request(Subsystem.AF, 'dataRequestExt', {
866
927
  dstaddrmode: addressMode,
867
928
  dstaddr: this.toAddressString(destinationAddressOrGroupID),