zigbee-herdsman 1.0.1 → 2.0.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 +23 -0
- package/dist/adapter/adapter.d.ts +8 -12
- package/dist/adapter/adapter.d.ts.map +1 -1
- package/dist/adapter/adapter.js +3 -0
- package/dist/adapter/adapter.js.map +1 -1
- package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +7 -15
- package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +1 -1
- package/dist/adapter/deconz/adapter/deconzAdapter.js +154 -693
- 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 +5 -22
- package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/emberAdapter.js +92 -325
- package/dist/adapter/ember/adapter/emberAdapter.js.map +1 -1
- package/dist/adapter/ember/adapter/oneWaitress.d.ts +17 -14
- package/dist/adapter/ember/adapter/oneWaitress.d.ts.map +1 -1
- package/dist/adapter/ember/adapter/oneWaitress.js +16 -42
- package/dist/adapter/ember/adapter/oneWaitress.js.map +1 -1
- package/dist/adapter/events.d.ts +1 -9
- package/dist/adapter/events.d.ts.map +1 -1
- package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts +12 -19
- package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +1 -1
- package/dist/adapter/ezsp/adapter/ezspAdapter.js +90 -272
- 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/tstype.d.ts +1 -27
- package/dist/adapter/tstype.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/manager.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/manager.js +20 -10
- package/dist/adapter/z-stack/adapter/manager.js.map +1 -1
- package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts +7 -15
- package/dist/adapter/z-stack/adapter/zStackAdapter.d.ts.map +1 -1
- package/dist/adapter/z-stack/adapter/zStackAdapter.js +128 -253
- 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 +8 -16
- package/dist/adapter/zboss/adapter/zbossAdapter.d.ts.map +1 -1
- package/dist/adapter/zboss/adapter/zbossAdapter.js +124 -162
- 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 +6 -10
- package/dist/adapter/zigate/adapter/zigateAdapter.d.ts.map +1 -1
- package/dist/adapter/zigate/adapter/zigateAdapter.js +99 -289
- 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 +5 -0
- package/dist/controller/controller.d.ts.map +1 -1
- package/dist/controller/controller.js +143 -37
- package/dist/controller/controller.js.map +1 -1
- package/dist/controller/greenPower.js +3 -3
- package/dist/controller/greenPower.js.map +1 -1
- package/dist/controller/model/device.d.ts +8 -7
- package/dist/controller/model/device.d.ts.map +1 -1
- package/dist/controller/model/device.js +176 -72
- package/dist/controller/model/device.js.map +1 -1
- package/dist/controller/model/endpoint.d.ts +1 -0
- package/dist/controller/model/endpoint.d.ts.map +1 -1
- package/dist/controller/model/endpoint.js +27 -4
- package/dist/controller/model/endpoint.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 +5 -4
|
@@ -28,11 +28,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
};
|
|
29
29
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
30
|
const assert_1 = __importDefault(require("assert"));
|
|
31
|
-
const __1 = require("../../..");
|
|
32
31
|
const device_1 = __importDefault(require("../../../controller/model/device"));
|
|
33
32
|
const utils_1 = require("../../../utils");
|
|
34
33
|
const logger_1 = require("../../../utils/logger");
|
|
34
|
+
const ZSpec = __importStar(require("../../../zspec"));
|
|
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,18 @@ 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
|
-
|
|
54
|
+
this.manufacturerID = Zcl.ManufacturerCode.DRESDEN_ELEKTRONIK_INGENIEURTECHNIK_GMBH;
|
|
55
|
+
// const concurrent = this.adapterOptions && this.adapterOptions.concurrent ? this.adapterOptions.concurrent : 2;
|
|
55
56
|
// TODO: https://github.com/Koenkk/zigbee2mqtt/issues/4884#issuecomment-728903121
|
|
56
57
|
const delay = this.adapterOptions && typeof this.adapterOptions.delay === 'number' ? this.adapterOptions.delay : 0;
|
|
57
58
|
this.waitress = new utils_1.Waitress(this.waitressValidator, this.waitressTimeoutFormatter);
|
|
@@ -63,10 +64,8 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
63
64
|
this.driver.on('rxFrame', (frame) => {
|
|
64
65
|
(0, frameParser_1.default)(frame);
|
|
65
66
|
});
|
|
66
|
-
this.queue = new utils_1.Queue(concurrent);
|
|
67
67
|
this.transactionID = 0;
|
|
68
68
|
this.openRequestsQueue = [];
|
|
69
|
-
this.joinPermitted = false;
|
|
70
69
|
this.fwVersion = undefined;
|
|
71
70
|
this.frameParserEvent.on('receivedDataPayload', (data) => {
|
|
72
71
|
this.checkReceivedDataPayload(data);
|
|
@@ -77,9 +76,6 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
77
76
|
setInterval(() => {
|
|
78
77
|
this.checkReceivedDataPayload(null);
|
|
79
78
|
}, 1000);
|
|
80
|
-
setTimeout(async () => {
|
|
81
|
-
await this.checkCoordinatorSimpleDescriptor(false);
|
|
82
|
-
}, 3000);
|
|
83
79
|
}
|
|
84
80
|
static async isValidPath(path) {
|
|
85
81
|
return await driver_1.default.isValidPath(path);
|
|
@@ -160,7 +156,7 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
160
156
|
}
|
|
161
157
|
try {
|
|
162
158
|
await this.driver.writeParameterRequest(constants_1.default.PARAM.Network.CHANNEL_MASK, setChannelMask);
|
|
163
|
-
await
|
|
159
|
+
await (0, utils_1.Wait)(500);
|
|
164
160
|
changed = true;
|
|
165
161
|
}
|
|
166
162
|
catch (error) {
|
|
@@ -172,7 +168,7 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
172
168
|
logger_1.logger.debug('panid in configuration.yaml (' + this.networkOptions.panID + ') differs from current panid (' + panid + '). Changing panid.', NS);
|
|
173
169
|
try {
|
|
174
170
|
await this.driver.writeParameterRequest(constants_1.default.PARAM.Network.PAN_ID, this.networkOptions.panID);
|
|
175
|
-
await
|
|
171
|
+
await (0, utils_1.Wait)(500);
|
|
176
172
|
changed = true;
|
|
177
173
|
}
|
|
178
174
|
catch (error) {
|
|
@@ -188,7 +184,7 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
188
184
|
'). Changing extended panid.', NS);
|
|
189
185
|
try {
|
|
190
186
|
await this.driver.writeParameterRequest(constants_1.default.PARAM.Network.APS_EXT_PAN_ID, this.networkOptions.extendedPanID);
|
|
191
|
-
await
|
|
187
|
+
await (0, utils_1.Wait)(500);
|
|
192
188
|
changed = true;
|
|
193
189
|
}
|
|
194
190
|
catch (error) {
|
|
@@ -200,7 +196,7 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
200
196
|
logger_1.logger.debug('network key in configuration.yaml (hidden) differs from current network key (' + networkKey + '). Changing network key.', NS);
|
|
201
197
|
try {
|
|
202
198
|
await this.driver.writeParameterRequest(constants_1.default.PARAM.Network.NETWORK_KEY, this.networkOptions.networkKey);
|
|
203
|
-
await
|
|
199
|
+
await (0, utils_1.Wait)(500);
|
|
204
200
|
changed = true;
|
|
205
201
|
}
|
|
206
202
|
catch (error) {
|
|
@@ -209,75 +205,49 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
209
205
|
}
|
|
210
206
|
if (changed) {
|
|
211
207
|
await this.driver.changeNetworkStateRequest(constants_1.default.PARAM.Network.NET_OFFLINE);
|
|
212
|
-
await
|
|
208
|
+
await (0, utils_1.Wait)(2000);
|
|
213
209
|
await this.driver.changeNetworkStateRequest(constants_1.default.PARAM.Network.NET_CONNECTED);
|
|
214
|
-
await
|
|
210
|
+
await (0, utils_1.Wait)(2000);
|
|
215
211
|
}
|
|
212
|
+
// write endpoints
|
|
213
|
+
//[ sd1 ep proId devId vers #inCl iCl1 iCl2 iCl3 iCl4 iCl5 #outC oCl1 oCl2 oCl3 oCl4 ]
|
|
214
|
+
const sd = [
|
|
215
|
+
0x00, 0x01, 0x04, 0x01, 0x05, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x06, 0x0a, 0x00, 0x19, 0x00, 0x01, 0x05, 0x04, 0x01, 0x00, 0x20, 0x00,
|
|
216
|
+
0x00, 0x05, 0x02, 0x05,
|
|
217
|
+
];
|
|
218
|
+
const sd1 = sd.reverse();
|
|
219
|
+
await this.driver.writeParameterRequest(constants_1.default.PARAM.STK.Endpoint, sd1);
|
|
216
220
|
return 'resumed';
|
|
217
221
|
}
|
|
218
222
|
async stop() {
|
|
219
223
|
await this.driver.close();
|
|
220
224
|
}
|
|
221
|
-
async
|
|
222
|
-
|
|
223
|
-
const nwkAddr = await this.driver.readParameterRequest(constants_1.default.PARAM.Network.NWK_ADDRESS);
|
|
224
|
-
const endpoints = [
|
|
225
|
-
{
|
|
226
|
-
ID: 0x01,
|
|
227
|
-
profileID: 0x0104,
|
|
228
|
-
deviceID: 0x0005,
|
|
229
|
-
inputClusters: [0x0000, 0x0006, 0x000a, 0x0019, 0x0501],
|
|
230
|
-
outputClusters: [0x0001, 0x0020, 0x0500, 0x0502],
|
|
231
|
-
},
|
|
232
|
-
{
|
|
233
|
-
ID: 0xf2,
|
|
234
|
-
profileID: 0xa1e0,
|
|
235
|
-
deviceID: 0x0064,
|
|
236
|
-
inputClusters: [],
|
|
237
|
-
outputClusters: [0x0021],
|
|
238
|
-
},
|
|
239
|
-
];
|
|
240
|
-
return {
|
|
241
|
-
networkAddress: nwkAddr,
|
|
242
|
-
manufacturerID: 0x1135,
|
|
243
|
-
ieeeAddr: ieeeAddr,
|
|
244
|
-
endpoints,
|
|
245
|
-
};
|
|
225
|
+
async getCoordinatorIEEE() {
|
|
226
|
+
return (await this.driver.readParameterRequest(constants_1.default.PARAM.Network.MAC));
|
|
246
227
|
}
|
|
247
228
|
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;
|
|
229
|
+
const clusterId = Zdo.ClusterId.PERMIT_JOINING_REQUEST;
|
|
230
|
+
if (networkAddress) {
|
|
231
|
+
// `authentication`: TC significance always 1 (zb specs)
|
|
232
|
+
const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, seconds, 1, []);
|
|
233
|
+
const result = await this.sendZdo(ZSpec.BLANK_EUI64, networkAddress, clusterId, zdoPayload, false);
|
|
234
|
+
/* istanbul ignore next */
|
|
235
|
+
if (!Zdo.Buffalo.checkStatus(result)) {
|
|
236
|
+
// TODO: will disappear once moved upstream
|
|
237
|
+
throw new Zdo.StatusError(result[0]);
|
|
267
238
|
}
|
|
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
239
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
logger_1.logger.debug(
|
|
277
|
-
//
|
|
278
|
-
|
|
279
|
-
|
|
240
|
+
else {
|
|
241
|
+
await this.driver.writeParameterRequest(constants_1.default.PARAM.Network.PERMIT_JOIN, seconds);
|
|
242
|
+
logger_1.logger.debug(`Permit joining on coordinator for ${seconds} sec.`, NS);
|
|
243
|
+
// broadcast permit joining ZDO
|
|
244
|
+
if (networkAddress === undefined) {
|
|
245
|
+
// `authentication`: TC significance always 1 (zb specs)
|
|
246
|
+
const zdoPayload = Zdo.Buffalo.buildRequest(this.hasZdoMessageOverhead, clusterId, seconds, 1, []);
|
|
247
|
+
await this.sendZdo(ZSpec.BLANK_EUI64, ZSpec.BroadcastAddress.DEFAULT, clusterId, zdoPayload, true);
|
|
248
|
+
}
|
|
280
249
|
}
|
|
250
|
+
this.joinPermitted = seconds !== 0;
|
|
281
251
|
}
|
|
282
252
|
async getCoordinatorVersion() {
|
|
283
253
|
// product: number; transportrev: number; majorrel: number; minorrel: number; maintrel: number; revision: string;
|
|
@@ -316,396 +286,6 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
316
286
|
async reset(type) {
|
|
317
287
|
return await Promise.reject(new Error('Reset is not supported'));
|
|
318
288
|
}
|
|
319
|
-
async lqi(networkAddress) {
|
|
320
|
-
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
|
-
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
|
-
}
|
|
381
|
-
}
|
|
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;
|
|
392
|
-
}
|
|
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));
|
|
397
|
-
}
|
|
398
|
-
};
|
|
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;
|
|
406
|
-
}
|
|
407
|
-
return { neighbors };
|
|
408
|
-
}
|
|
409
|
-
async routingTable(networkAddress) {
|
|
410
|
-
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
|
-
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`);
|
|
456
|
-
}
|
|
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;
|
|
487
|
-
}
|
|
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));
|
|
492
|
-
}
|
|
493
|
-
};
|
|
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;
|
|
501
|
-
}
|
|
502
|
-
return { table };
|
|
503
|
-
}
|
|
504
|
-
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 };
|
|
540
|
-
}
|
|
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));
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
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 };
|
|
580
|
-
}
|
|
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));
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
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,
|
|
633
|
-
};
|
|
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
|
-
}
|
|
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));
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
async checkCoordinatorSimpleDescriptor(skip) {
|
|
651
|
-
logger_1.logger.debug('checking coordinator simple descriptor', NS);
|
|
652
|
-
let simpleDesc;
|
|
653
|
-
if (skip === false) {
|
|
654
|
-
try {
|
|
655
|
-
simpleDesc = await this.simpleDescriptor(0x0, 1);
|
|
656
|
-
}
|
|
657
|
-
catch {
|
|
658
|
-
/* empty */
|
|
659
|
-
}
|
|
660
|
-
if (simpleDesc == undefined) {
|
|
661
|
-
await this.checkCoordinatorSimpleDescriptor(false);
|
|
662
|
-
return;
|
|
663
|
-
}
|
|
664
|
-
logger_1.logger.debug('EP: ' + simpleDesc.endpointID, NS);
|
|
665
|
-
logger_1.logger.debug('profile ID: ' + simpleDesc.profileID, NS);
|
|
666
|
-
logger_1.logger.debug('device ID: ' + simpleDesc.deviceID, NS);
|
|
667
|
-
for (let i = 0; i < simpleDesc.inputClusters.length; i++) {
|
|
668
|
-
logger_1.logger.debug('input cluster: 0x' + simpleDesc.inputClusters[i].toString(16), NS);
|
|
669
|
-
}
|
|
670
|
-
for (let o = 0; o < simpleDesc.outputClusters.length; o++) {
|
|
671
|
-
logger_1.logger.debug('output cluster: 0x' + simpleDesc.outputClusters[o].toString(16), NS);
|
|
672
|
-
}
|
|
673
|
-
let ok = true;
|
|
674
|
-
if (simpleDesc.endpointID === 0x1) {
|
|
675
|
-
if (!simpleDesc.inputClusters.includes(0x0) ||
|
|
676
|
-
!simpleDesc.inputClusters.includes(0x0a) ||
|
|
677
|
-
!simpleDesc.inputClusters.includes(0x06) ||
|
|
678
|
-
!simpleDesc.inputClusters.includes(0x19) ||
|
|
679
|
-
!simpleDesc.inputClusters.includes(0x0501) ||
|
|
680
|
-
!simpleDesc.outputClusters.includes(0x01) ||
|
|
681
|
-
!simpleDesc.outputClusters.includes(0x20) ||
|
|
682
|
-
!simpleDesc.outputClusters.includes(0x500) ||
|
|
683
|
-
!simpleDesc.outputClusters.includes(0x502)) {
|
|
684
|
-
logger_1.logger.debug('missing cluster', NS);
|
|
685
|
-
ok = false;
|
|
686
|
-
}
|
|
687
|
-
if (ok === true) {
|
|
688
|
-
return;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
logger_1.logger.debug('setting new simple descriptor', NS);
|
|
693
|
-
try {
|
|
694
|
-
//[ sd1 ep proId devId vers #inCl iCl1 iCl2 iCl3 iCl4 iCl5 #outC oCl1 oCl2 oCl3 oCl4 ]
|
|
695
|
-
const sd = [
|
|
696
|
-
0x00, 0x01, 0x04, 0x01, 0x05, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x06, 0x0a, 0x00, 0x19, 0x00, 0x01, 0x05, 0x04, 0x01, 0x00, 0x20,
|
|
697
|
-
0x00, 0x00, 0x05, 0x02, 0x05,
|
|
698
|
-
];
|
|
699
|
-
const sd1 = sd.reverse();
|
|
700
|
-
await this.driver.writeParameterRequest(constants_1.default.PARAM.STK.Endpoint, sd1);
|
|
701
|
-
}
|
|
702
|
-
catch (error) {
|
|
703
|
-
logger_1.logger.debug(`error setting simple descriptor: ${error} - try again`, NS);
|
|
704
|
-
await this.checkCoordinatorSimpleDescriptor(true);
|
|
705
|
-
return;
|
|
706
|
-
}
|
|
707
|
-
logger_1.logger.debug('success setting simple descriptor', NS);
|
|
708
|
-
}
|
|
709
289
|
waitFor(networkAddress, endpoint, frameType, direction, transactionSequenceNumber, clusterID, commandIdentifier, timeout) {
|
|
710
290
|
const payload = {
|
|
711
291
|
address: networkAddress,
|
|
@@ -720,24 +300,54 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
720
300
|
const cancel = () => this.waitress.remove(waiter.ID);
|
|
721
301
|
return { promise: waiter.start().promise, cancel };
|
|
722
302
|
}
|
|
303
|
+
async sendZdo(ieeeAddress, networkAddress, clusterId, payload, disableResponse) {
|
|
304
|
+
const transactionID = this.nextTransactionID();
|
|
305
|
+
payload[0] = transactionID;
|
|
306
|
+
const isNwkAddrRequest = clusterId === Zdo.ClusterId.NETWORK_ADDRESS_REQUEST;
|
|
307
|
+
const req = {
|
|
308
|
+
requestId: transactionID,
|
|
309
|
+
destAddrMode: isNwkAddrRequest ? constants_1.default.PARAM.addressMode.IEEE_ADDR : constants_1.default.PARAM.addressMode.NWK_ADDR,
|
|
310
|
+
destAddr16: isNwkAddrRequest ? undefined : networkAddress,
|
|
311
|
+
destAddr64: isNwkAddrRequest ? ieeeAddress : undefined,
|
|
312
|
+
destEndpoint: Zdo.ZDO_ENDPOINT,
|
|
313
|
+
profileId: Zdo.ZDO_PROFILE_ID,
|
|
314
|
+
clusterId,
|
|
315
|
+
srcEndpoint: Zdo.ZDO_ENDPOINT,
|
|
316
|
+
asduLength: payload.length,
|
|
317
|
+
asduPayload: payload,
|
|
318
|
+
txOptions: 0,
|
|
319
|
+
radius: constants_1.default.PARAM.txRadius.DEFAULT_RADIUS,
|
|
320
|
+
timeout: 30,
|
|
321
|
+
};
|
|
322
|
+
this.driver
|
|
323
|
+
.enqueueSendDataRequest(req)
|
|
324
|
+
.then(() => { })
|
|
325
|
+
.catch(() => { });
|
|
326
|
+
if (!disableResponse) {
|
|
327
|
+
const responseClusterId = Zdo.Utils.getResponseClusterId(clusterId);
|
|
328
|
+
if (responseClusterId) {
|
|
329
|
+
const response = await this.waitForData(isNwkAddrRequest ? ieeeAddress : networkAddress, Zdo.ZDO_PROFILE_ID, responseClusterId);
|
|
330
|
+
return response.zdo;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
723
334
|
async sendZclFrameToEndpoint(ieeeAddr, networkAddress, endpoint, zclFrame, timeout, disableResponse, disableRecovery, sourceEndpoint) {
|
|
724
335
|
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;
|
|
336
|
+
const payload = zclFrame.toBuffer();
|
|
337
|
+
const request = {
|
|
338
|
+
requestId: transactionID,
|
|
339
|
+
destAddrMode: constants_1.default.PARAM.addressMode.NWK_ADDR,
|
|
340
|
+
destAddr16: networkAddress,
|
|
341
|
+
destEndpoint: endpoint,
|
|
342
|
+
profileId: sourceEndpoint === 242 && endpoint === 242 ? 0xa1e0 : 0x104,
|
|
343
|
+
clusterId: zclFrame.cluster.ID,
|
|
344
|
+
srcEndpoint: sourceEndpoint || 1,
|
|
345
|
+
asduLength: payload.length,
|
|
346
|
+
asduPayload: payload,
|
|
347
|
+
txOptions: this.TX_OPTIONS, // 0x00 normal, 0x04 APS ACK
|
|
348
|
+
radius: constants_1.default.PARAM.txRadius.DEFAULT_RADIUS,
|
|
349
|
+
timeout: timeout,
|
|
350
|
+
};
|
|
741
351
|
const command = zclFrame.command;
|
|
742
352
|
this.driver
|
|
743
353
|
.enqueueSendDataRequest(request)
|
|
@@ -763,16 +373,14 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
763
373
|
try {
|
|
764
374
|
let data = null;
|
|
765
375
|
if ((command.response != undefined && !disableResponse) || !zclFrame.header.frameControl.disableDefaultResponse) {
|
|
766
|
-
data = await this.waitForData(networkAddress,
|
|
376
|
+
data = await this.waitForData(networkAddress, ZSpec.HA_PROFILE_ID, zclFrame.cluster.ID, zclFrame.header.transactionSequenceNumber, request.timeout);
|
|
767
377
|
}
|
|
768
378
|
if (data !== null) {
|
|
769
|
-
const asdu = data.asduPayload;
|
|
770
|
-
const buffer = Buffer.from(asdu);
|
|
771
379
|
const response = {
|
|
772
380
|
address: data.srcAddr16 ?? `0x${data.srcAddr64}`,
|
|
773
|
-
data:
|
|
381
|
+
data: data.asduPayload,
|
|
774
382
|
clusterID: zclFrame.cluster.ID,
|
|
775
|
-
header: Zcl.Header.fromBuffer(
|
|
383
|
+
header: Zcl.Header.fromBuffer(data.asduPayload),
|
|
776
384
|
endpoint: data.srcEndpoint,
|
|
777
385
|
linkquality: data.lqi,
|
|
778
386
|
groupID: data.srcAddrMode === 0x01 ? data.srcAddr16 : 0,
|
|
@@ -792,181 +400,43 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
792
400
|
}
|
|
793
401
|
async sendZclFrameToGroup(groupID, zclFrame) {
|
|
794
402
|
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;
|
|
403
|
+
const payload = zclFrame.toBuffer();
|
|
404
|
+
logger_1.logger.debug(`zclFrame to group - ${groupID}`, NS);
|
|
405
|
+
const request = {
|
|
406
|
+
requestId: transactionID,
|
|
407
|
+
destAddrMode: constants_1.default.PARAM.addressMode.GROUP_ADDR,
|
|
408
|
+
destAddr16: groupID,
|
|
409
|
+
profileId: 0x104,
|
|
410
|
+
clusterId: zclFrame.cluster.ID,
|
|
411
|
+
srcEndpoint: 1,
|
|
412
|
+
asduLength: payload.length,
|
|
413
|
+
asduPayload: payload,
|
|
414
|
+
txOptions: 0,
|
|
415
|
+
radius: constants_1.default.PARAM.txRadius.UNLIMITED,
|
|
416
|
+
};
|
|
811
417
|
logger_1.logger.debug(`sendZclFrameToGroup - message send`, NS);
|
|
812
418
|
return await this.driver.enqueueSendDataRequest(request);
|
|
813
419
|
}
|
|
814
420
|
async sendZclFrameToAll(endpoint, zclFrame, sourceEndpoint, destination) {
|
|
815
421
|
const transactionID = this.nextTransactionID();
|
|
816
|
-
const
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
422
|
+
const payload = zclFrame.toBuffer();
|
|
423
|
+
logger_1.logger.debug(`zclFrame to all - ${endpoint}`, NS);
|
|
424
|
+
const request = {
|
|
425
|
+
requestId: transactionID,
|
|
426
|
+
destAddrMode: constants_1.default.PARAM.addressMode.NWK_ADDR,
|
|
427
|
+
destAddr16: destination,
|
|
428
|
+
destEndpoint: endpoint,
|
|
429
|
+
profileId: sourceEndpoint === 242 && endpoint === 242 ? 0xa1e0 : 0x104,
|
|
430
|
+
clusterId: zclFrame.cluster.ID,
|
|
431
|
+
srcEndpoint: sourceEndpoint,
|
|
432
|
+
asduLength: payload.length,
|
|
433
|
+
asduPayload: payload,
|
|
434
|
+
txOptions: 0,
|
|
435
|
+
radius: constants_1.default.PARAM.txRadius.UNLIMITED,
|
|
436
|
+
};
|
|
831
437
|
logger_1.logger.debug(`sendZclFrameToAll - message send`, NS);
|
|
832
438
|
return await this.driver.enqueueSendDataRequest(request);
|
|
833
439
|
}
|
|
834
|
-
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;
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
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;
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
|
-
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;
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
440
|
async supportsBackup() {
|
|
971
441
|
return false;
|
|
972
442
|
}
|
|
@@ -1010,10 +480,6 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
1010
480
|
throw new Error('not supported');
|
|
1011
481
|
}
|
|
1012
482
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1013
|
-
async changeChannel(newChannel) {
|
|
1014
|
-
throw new Error(`Channel change is not supported for 'deconz'`);
|
|
1015
|
-
}
|
|
1016
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1017
483
|
async setTransmitPower(value) {
|
|
1018
484
|
throw new Error('not supported');
|
|
1019
485
|
}
|
|
@@ -1024,9 +490,6 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
1024
490
|
/**
|
|
1025
491
|
* Private methods
|
|
1026
492
|
*/
|
|
1027
|
-
sleep(ms) {
|
|
1028
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1029
|
-
}
|
|
1030
493
|
waitForData(addr, profileId, clusterId, transactionSequenceNumber, timeout) {
|
|
1031
494
|
return new Promise((resolve, reject) => {
|
|
1032
495
|
const ts = Date.now();
|
|
@@ -1053,20 +516,20 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
1053
516
|
data: payBuf,
|
|
1054
517
|
clusterID: Zcl.Clusters.greenPower.ID,
|
|
1055
518
|
address: ind.srcId & 0xffff,
|
|
1056
|
-
endpoint:
|
|
519
|
+
endpoint: ZSpec.GP_ENDPOINT,
|
|
1057
520
|
linkquality: 0xff, // bogus
|
|
1058
|
-
groupID:
|
|
521
|
+
groupID: ZSpec.GP_GROUP_ID,
|
|
1059
522
|
wasBroadcast: true, // Take the codepath that doesn't require `gppNwkAddr` as its not present in the payload
|
|
1060
|
-
destinationEndpoint:
|
|
523
|
+
destinationEndpoint: ZSpec.GP_ENDPOINT,
|
|
1061
524
|
};
|
|
1062
525
|
this.waitress.resolve(payload);
|
|
1063
526
|
this.emit('zclPayload', payload);
|
|
1064
527
|
}
|
|
1065
528
|
checkReceivedDataPayload(resp) {
|
|
1066
|
-
let srcAddr
|
|
529
|
+
let srcAddr;
|
|
530
|
+
let srcEUI64;
|
|
1067
531
|
let header;
|
|
1068
|
-
|
|
1069
|
-
if (resp != null) {
|
|
532
|
+
if (resp) {
|
|
1070
533
|
if (resp.srcAddr16 != null) {
|
|
1071
534
|
srcAddr = resp.srcAddr16;
|
|
1072
535
|
}
|
|
@@ -1085,26 +548,38 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
1085
548
|
// so let's make sure they get the network address
|
|
1086
549
|
resp.srcAddr16 = srcAddr; // TODO: can't be undefined
|
|
1087
550
|
}
|
|
1088
|
-
if (resp.profileId
|
|
1089
|
-
|
|
551
|
+
if (resp.profileId === Zdo.ZDO_PROFILE_ID) {
|
|
552
|
+
if (resp.clusterId === Zdo.ClusterId.NETWORK_ADDRESS_RESPONSE) {
|
|
553
|
+
if (Zdo.Buffalo.checkStatus(resp.zdo)) {
|
|
554
|
+
srcEUI64 = resp.zdo[1].eui64;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
else if (resp.clusterId === Zdo.ClusterId.END_DEVICE_ANNOUNCE) {
|
|
558
|
+
// XXX: using same response for announce (handled by controller) or joined depending on permit join status?
|
|
559
|
+
if (this.joinPermitted === true && Zdo.Buffalo.checkStatus(resp.zdo)) {
|
|
560
|
+
const payload = resp.zdo[1];
|
|
561
|
+
this.emit('deviceJoined', { networkAddress: payload.nwkAddress, ieeeAddr: payload.eui64 });
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
this.emit('zdoResponse', resp.clusterId, resp.zdo);
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
header = Zcl.Header.fromBuffer(resp.asduPayload);
|
|
1090
568
|
}
|
|
1091
569
|
}
|
|
1092
570
|
let i = this.openRequestsQueue.length;
|
|
1093
571
|
while (i--) {
|
|
1094
572
|
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
|
-
}
|
|
573
|
+
if (resp &&
|
|
574
|
+
(req.addr === undefined ||
|
|
575
|
+
(typeof req.addr === 'number' ? srcAddr !== undefined && req.addr === srcAddr : srcEUI64 && req.addr === srcEUI64)) &&
|
|
576
|
+
req.clusterId === resp.clusterId &&
|
|
577
|
+
req.profileId === resp.profileId &&
|
|
578
|
+
(header === undefined ||
|
|
579
|
+
req.transactionSequenceNumber === undefined ||
|
|
580
|
+
req.transactionSequenceNumber === header.transactionSequenceNumber)) {
|
|
581
|
+
this.openRequestsQueue.splice(i, 1);
|
|
582
|
+
req.resolve(resp);
|
|
1108
583
|
}
|
|
1109
584
|
const now = Date.now();
|
|
1110
585
|
// Default timeout: 60 seconds.
|
|
@@ -1113,28 +588,14 @@ class DeconzAdapter extends adapter_1.default {
|
|
|
1113
588
|
//logger.debug("Timeout for request in openRequestsQueue addr: " + req.addr.toString(16) + " clusterId: " + req.clusterId.toString(16) + " profileId: " + req.profileId.toString(16), NS);
|
|
1114
589
|
//remove from busyQueue
|
|
1115
590
|
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);
|
|
591
|
+
req.reject(new Error('waiting for response TIMEOUT'));
|
|
1131
592
|
}
|
|
1132
593
|
}
|
|
1133
|
-
if (resp
|
|
594
|
+
if (resp && resp.profileId != Zdo.ZDO_PROFILE_ID) {
|
|
1134
595
|
const payload = {
|
|
1135
596
|
clusterID: resp.clusterId,
|
|
1136
597
|
header,
|
|
1137
|
-
data:
|
|
598
|
+
data: resp.asduPayload,
|
|
1138
599
|
address: resp.destAddrMode === 0x03 ? `0x${resp.srcAddr64}` : resp.srcAddr16,
|
|
1139
600
|
endpoint: resp.srcEndpoint,
|
|
1140
601
|
linkquality: resp.lqi,
|