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.
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +14 -0
- package/dist/adapter/adapter.d.ts +6 -0
- package/dist/adapter/adapter.d.ts.map +1 -1
- package/dist/adapter/adapter.js.map +1 -1
- package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +5 -3
- package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +1 -1
- package/dist/adapter/deconz/adapter/deconzAdapter.js +261 -558
- package/dist/adapter/deconz/adapter/deconzAdapter.js.map +1 -1
- package/dist/adapter/deconz/driver/constants.d.ts +102 -56
- package/dist/adapter/deconz/driver/constants.d.ts.map +1 -1
- package/dist/adapter/deconz/driver/constants.js +1 -2
- package/dist/adapter/deconz/driver/constants.js.map +1 -1
- package/dist/adapter/deconz/driver/driver.d.ts.map +1 -1
- package/dist/adapter/deconz/driver/driver.js +46 -41
- package/dist/adapter/deconz/driver/driver.js.map +1 -1
- package/dist/adapter/deconz/driver/frameParser.d.ts.map +1 -1
- package/dist/adapter/deconz/driver/frameParser.js +174 -107
- package/dist/adapter/deconz/driver/frameParser.js.map +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.d.ts +4 -12
- package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.js +215 -249
- package/dist/adapter/ember/adapter/emberAdapter.js.map +1 -1
- package/dist/adapter/ember/adapter/oneWaitress.d.ts +16 -12
- package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/oneWaitress.js +16 -41
- package/dist/adapter/ember/adapter/oneWaitress.js.map +1 -1
- package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts +10 -8
- package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +1 -1
- package/dist/adapter/ezsp/adapter/ezspAdapter.js +241 -238
- package/dist/adapter/ezsp/adapter/ezspAdapter.js.map +1 -1
- package/dist/adapter/ezsp/driver/driver.d.ts +6 -14
- package/dist/adapter/ezsp/driver/driver.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/driver.js +56 -37
- package/dist/adapter/ezsp/driver/driver.js.map +1 -1
- package/dist/adapter/ezsp/driver/ezsp.d.ts.map +1 -1
- package/dist/adapter/ezsp/driver/ezsp.js +3 -0
- package/dist/adapter/ezsp/driver/ezsp.js.map +1 -1
- package/dist/adapter/z-stack/adapter/manager.js +2 -2
- package/dist/adapter/z-stack/adapter/manager.js.map +1 -1
- package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts +4 -3
- package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/zStackAdapter.js +258 -197
- package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
- package/dist/adapter/z-stack/znp/definition.d.ts.map +1 -1
- package/dist/adapter/z-stack/znp/definition.js +256 -302
- package/dist/adapter/z-stack/znp/definition.js.map +1 -1
- package/dist/adapter/z-stack/znp/tstype.d.ts +8 -8
- package/dist/adapter/z-stack/znp/tstype.d.ts.map +1 -1
- package/dist/adapter/z-stack/znp/utils.d.ts +3 -2
- package/dist/adapter/z-stack/znp/utils.d.ts.map +1 -1
- package/dist/adapter/z-stack/znp/utils.js +8 -7
- package/dist/adapter/z-stack/znp/utils.js.map +1 -1
- package/dist/adapter/z-stack/znp/znp.d.ts +3 -1
- package/dist/adapter/z-stack/znp/znp.d.ts.map +1 -1
- package/dist/adapter/z-stack/znp/znp.js +31 -14
- package/dist/adapter/z-stack/znp/znp.js.map +1 -1
- package/dist/adapter/z-stack/znp/zpiObject.d.ts +5 -6
- package/dist/adapter/z-stack/znp/zpiObject.d.ts.map +1 -1
- package/dist/adapter/z-stack/znp/zpiObject.js +28 -11
- package/dist/adapter/z-stack/znp/zpiObject.js.map +1 -1
- package/dist/adapter/zboss/adapter/zbossAdapter.d.ts +7 -5
- package/dist/adapter/zboss/adapter/zbossAdapter.d.ts.map +1 -1
- package/dist/adapter/zboss/adapter/zbossAdapter.js +284 -138
- package/dist/adapter/zboss/adapter/zbossAdapter.js.map +1 -1
- package/dist/adapter/zboss/commands.d.ts +3 -0
- package/dist/adapter/zboss/commands.d.ts.map +1 -1
- package/dist/adapter/zboss/commands.js +248 -205
- package/dist/adapter/zboss/commands.js.map +1 -1
- package/dist/adapter/zboss/driver.d.ts +4 -14
- package/dist/adapter/zboss/driver.d.ts.map +1 -1
- package/dist/adapter/zboss/driver.js +63 -89
- package/dist/adapter/zboss/driver.js.map +1 -1
- package/dist/adapter/zboss/enums.d.ts +24 -2
- package/dist/adapter/zboss/enums.d.ts.map +1 -1
- package/dist/adapter/zboss/enums.js +35 -3
- package/dist/adapter/zboss/enums.js.map +1 -1
- package/dist/adapter/zboss/frame.d.ts +6 -1
- package/dist/adapter/zboss/frame.d.ts.map +1 -1
- package/dist/adapter/zboss/frame.js +56 -11
- package/dist/adapter/zboss/frame.js.map +1 -1
- package/dist/adapter/zboss/uart.d.ts +1 -0
- package/dist/adapter/zboss/uart.d.ts.map +1 -1
- package/dist/adapter/zboss/uart.js +4 -2
- package/dist/adapter/zboss/uart.js.map +1 -1
- package/dist/adapter/zigate/adapter/patchZdoBuffaloBE.d.ts +5 -0
- package/dist/adapter/zigate/adapter/patchZdoBuffaloBE.d.ts.map +1 -0
- package/dist/adapter/zigate/adapter/patchZdoBuffaloBE.js +44 -0
- package/dist/adapter/zigate/adapter/patchZdoBuffaloBE.js.map +1 -0
- package/dist/adapter/zigate/adapter/zigateAdapter.d.ts +5 -0
- package/dist/adapter/zigate/adapter/zigateAdapter.d.ts.map +1 -1
- package/dist/adapter/zigate/adapter/zigateAdapter.js +247 -262
- package/dist/adapter/zigate/adapter/zigateAdapter.js.map +1 -1
- package/dist/adapter/zigate/driver/buffaloZiGate.d.ts.map +1 -1
- package/dist/adapter/zigate/driver/buffaloZiGate.js +2 -18
- package/dist/adapter/zigate/driver/buffaloZiGate.js.map +1 -1
- package/dist/adapter/zigate/driver/commandType.js +218 -218
- package/dist/adapter/zigate/driver/commandType.js.map +1 -1
- package/dist/adapter/zigate/driver/constants.d.ts +14 -8
- package/dist/adapter/zigate/driver/constants.d.ts.map +1 -1
- package/dist/adapter/zigate/driver/constants.js +36 -9
- package/dist/adapter/zigate/driver/constants.js.map +1 -1
- package/dist/adapter/zigate/driver/messageType.js +42 -42
- package/dist/adapter/zigate/driver/messageType.js.map +1 -1
- package/dist/adapter/zigate/driver/zigate.d.ts +17 -13
- package/dist/adapter/zigate/driver/zigate.d.ts.map +1 -1
- package/dist/adapter/zigate/driver/zigate.js +83 -18
- package/dist/adapter/zigate/driver/zigate.js.map +1 -1
- package/dist/controller/controller.d.ts +1 -0
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/controller/controller.js +28 -0
- package/dist/controller/controller.js.map +1 -1
- package/dist/utils/patchBigIntSerialization.d.ts +2 -0
- package/dist/utils/patchBigIntSerialization.d.ts.map +1 -0
- package/dist/utils/patchBigIntSerialization.js +9 -0
- package/dist/utils/patchBigIntSerialization.js.map +1 -0
- package/dist/zspec/zcl/zclFrame.d.ts +1 -0
- package/dist/zspec/zcl/zclFrame.d.ts.map +1 -1
- package/dist/zspec/zcl/zclFrame.js +1 -0
- package/dist/zspec/zcl/zclFrame.js.map +1 -1
- package/dist/zspec/zdo/buffaloZdo.d.ts +1 -139
- package/dist/zspec/zdo/buffaloZdo.d.ts.map +1 -1
- package/dist/zspec/zdo/buffaloZdo.js.map +1 -1
- package/dist/zspec/zdo/definition/tstypes.d.ts +168 -1
- package/dist/zspec/zdo/definition/tstypes.d.ts.map +1 -1
- package/dist/zspec/zdo/definition/tstypes.js +1 -0
- package/dist/zspec/zdo/definition/tstypes.js.map +1 -1
- package/dist/zspec/zdo/utils.d.ts +2 -3
- package/dist/zspec/zdo/utils.d.ts.map +1 -1
- package/dist/zspec/zdo/utils.js +3 -4
- package/dist/zspec/zdo/utils.js.map +1 -1
- 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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
210
|
+
await (0, utils_1.Wait)(2000);
|
|
213
211
|
await this.driver.changeNetworkStateRequest(constants_1.default.PARAM.Network.NET_CONNECTED);
|
|
214
|
-
await
|
|
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
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
-
|
|
275
|
-
|
|
276
|
-
logger_1.logger.debug(
|
|
277
|
-
//
|
|
278
|
-
|
|
279
|
-
|
|
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
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
-
|
|
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
|
-
|
|
394
|
-
|
|
395
|
-
|
|
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
|
|
400
|
-
|
|
401
|
-
let nextStartIndex =
|
|
402
|
-
while (neighbors.length <
|
|
403
|
-
|
|
404
|
-
|
|
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
|
|
433
|
-
const
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
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
|
-
|
|
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
|
-
|
|
489
|
-
|
|
490
|
-
|
|
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
|
|
495
|
-
|
|
496
|
-
let nextStartIndex =
|
|
497
|
-
while (table.length <
|
|
498
|
-
|
|
499
|
-
|
|
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
|
|
506
|
-
const
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
.
|
|
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
|
-
|
|
542
|
-
|
|
543
|
-
|
|
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
|
|
549
|
-
const
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
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
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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
|
|
589
|
-
const
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
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
|
-
|
|
645
|
-
|
|
646
|
-
|
|
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
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
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,
|
|
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:
|
|
583
|
+
data: data.asduPayload,
|
|
774
584
|
clusterID: zclFrame.cluster.ID,
|
|
775
|
-
header: Zcl.Header.fromBuffer(
|
|
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
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
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
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
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
|
|
836
|
-
const
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
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
|
|
884
|
-
const
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
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
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
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
|
-
|
|
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
|
|
771
|
+
let srcAddr;
|
|
772
|
+
let srcEUI64;
|
|
1067
773
|
let header;
|
|
1068
|
-
|
|
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
|
|
1089
|
-
|
|
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 (
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
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
|
|
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
|
|
836
|
+
if (resp && resp.profileId != Zdo.ZDO_PROFILE_ID) {
|
|
1134
837
|
const payload = {
|
|
1135
838
|
clusterID: resp.clusterId,
|
|
1136
839
|
header,
|
|
1137
|
-
data:
|
|
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,
|