zigbee-herdsman 4.1.2 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +22 -0
  3. package/biome.json +14 -5
  4. package/dist/adapter/adapterDiscovery.d.ts +1 -1
  5. package/dist/adapter/adapterDiscovery.d.ts.map +1 -1
  6. package/dist/adapter/adapterDiscovery.js.map +1 -1
  7. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts +5 -2
  8. package/dist/adapter/deconz/adapter/deconzAdapter.d.ts.map +1 -1
  9. package/dist/adapter/deconz/adapter/deconzAdapter.js +394 -330
  10. package/dist/adapter/deconz/adapter/deconzAdapter.js.map +1 -1
  11. package/dist/adapter/deconz/driver/constants.d.ts +122 -63
  12. package/dist/adapter/deconz/driver/constants.d.ts.map +1 -1
  13. package/dist/adapter/deconz/driver/constants.js +122 -40
  14. package/dist/adapter/deconz/driver/constants.js.map +1 -1
  15. package/dist/adapter/deconz/driver/driver.d.ts +66 -38
  16. package/dist/adapter/deconz/driver/driver.d.ts.map +1 -1
  17. package/dist/adapter/deconz/driver/driver.js +983 -435
  18. package/dist/adapter/deconz/driver/driver.js.map +1 -1
  19. package/dist/adapter/deconz/driver/frameParser.d.ts.map +1 -1
  20. package/dist/adapter/deconz/driver/frameParser.js +333 -266
  21. package/dist/adapter/deconz/driver/frameParser.js.map +1 -1
  22. package/dist/adapter/ember/adapter/emberAdapter.d.ts +1 -1
  23. package/dist/adapter/ember/adapter/emberAdapter.d.ts.map +1 -1
  24. package/dist/adapter/ember/adapter/emberAdapter.js +1 -1
  25. package/dist/adapter/ember/adapter/emberAdapter.js.map +1 -1
  26. package/dist/adapter/ember/adapter/tokensManager.d.ts.map +1 -1
  27. package/dist/adapter/ember/enums.d.ts +21 -370
  28. package/dist/adapter/ember/enums.d.ts.map +1 -1
  29. package/dist/adapter/ember/enums.js +20 -383
  30. package/dist/adapter/ember/enums.js.map +1 -1
  31. package/dist/adapter/ember/ezsp/buffalo.d.ts +1 -1
  32. package/dist/adapter/ember/ezsp/buffalo.d.ts.map +1 -1
  33. package/dist/adapter/ember/ezsp/consts.d.ts +1 -1
  34. package/dist/adapter/ember/ezsp/consts.js +1 -1
  35. package/dist/adapter/ember/ezsp/enums.d.ts +29 -3
  36. package/dist/adapter/ember/ezsp/enums.d.ts.map +1 -1
  37. package/dist/adapter/ember/ezsp/enums.js +29 -2
  38. package/dist/adapter/ember/ezsp/enums.js.map +1 -1
  39. package/dist/adapter/ember/ezsp/ezsp.d.ts +31 -6
  40. package/dist/adapter/ember/ezsp/ezsp.d.ts.map +1 -1
  41. package/dist/adapter/ember/ezsp/ezsp.js +66 -3
  42. package/dist/adapter/ember/ezsp/ezsp.js.map +1 -1
  43. package/dist/adapter/ember/uart/ash.js +1 -1
  44. package/dist/adapter/ezsp/adapter/ezspAdapter.d.ts.map +1 -1
  45. package/dist/adapter/ezsp/adapter/ezspAdapter.js +2 -2
  46. package/dist/adapter/ezsp/adapter/ezspAdapter.js.map +1 -1
  47. package/dist/adapter/ezsp/driver/driver.d.ts +1 -1
  48. package/dist/adapter/ezsp/driver/driver.d.ts.map +1 -1
  49. package/dist/adapter/ezsp/driver/driver.js +5 -5
  50. package/dist/adapter/ezsp/driver/driver.js.map +1 -1
  51. package/dist/adapter/ezsp/driver/types/index.d.ts +3 -3
  52. package/dist/adapter/ezsp/driver/types/index.d.ts.map +1 -1
  53. package/dist/adapter/ezsp/driver/types/index.js +6 -6
  54. package/dist/adapter/ezsp/driver/types/index.js.map +1 -1
  55. package/dist/adapter/ezsp/driver/types/named.js +1 -1
  56. package/dist/adapter/ezsp/driver/types/named.js.map +1 -1
  57. package/dist/adapter/serialPort.d.ts.map +1 -1
  58. package/dist/adapter/z-stack/adapter/manager.d.ts.map +1 -1
  59. package/dist/adapter/z-stack/adapter/manager.js +1 -1
  60. package/dist/adapter/z-stack/adapter/manager.js.map +1 -1
  61. package/dist/adapter/z-stack/adapter/zStackAdapter.js +2 -2
  62. package/dist/adapter/z-stack/adapter/zStackAdapter.js.map +1 -1
  63. package/dist/adapter/z-stack/structs/entries/index.d.ts +7 -7
  64. package/dist/adapter/z-stack/structs/entries/index.d.ts.map +1 -1
  65. package/dist/adapter/z-stack/structs/entries/index.js +7 -7
  66. package/dist/adapter/z-stack/structs/entries/index.js.map +1 -1
  67. package/dist/adapter/z-stack/structs/index.d.ts +2 -2
  68. package/dist/adapter/z-stack/structs/index.d.ts.map +1 -1
  69. package/dist/adapter/z-stack/structs/index.js +2 -2
  70. package/dist/adapter/z-stack/structs/index.js.map +1 -1
  71. package/dist/adapter/zboss/adapter/zbossAdapter.d.ts +1 -1
  72. package/dist/adapter/zboss/adapter/zbossAdapter.d.ts.map +1 -1
  73. package/dist/adapter/zboss/adapter/zbossAdapter.js +1 -1
  74. package/dist/adapter/zboss/adapter/zbossAdapter.js.map +1 -1
  75. package/dist/adapter/zboss/driver.d.ts +1 -1
  76. package/dist/adapter/zboss/driver.d.ts.map +1 -1
  77. package/dist/adapter/zboss/driver.js.map +1 -1
  78. package/dist/adapter/zboss/uart.d.ts.map +1 -1
  79. package/dist/adapter/zigate/driver/messageType.js +1 -1
  80. package/dist/adapter/zigate/driver/messageType.js.map +1 -1
  81. package/dist/adapter/zoh/adapter/zohAdapter.js +1 -1
  82. package/dist/adapter/zoh/adapter/zohAdapter.js.map +1 -1
  83. package/dist/buffalo/buffalo.d.ts.map +1 -1
  84. package/dist/buffalo/buffalo.js.map +1 -1
  85. package/dist/controller/controller.d.ts.map +1 -1
  86. package/dist/controller/controller.js +2 -2
  87. package/dist/controller/controller.js.map +1 -1
  88. package/dist/controller/helpers/request.js +2 -2
  89. package/dist/controller/helpers/request.js.map +1 -1
  90. package/dist/controller/model/device.js +1 -1
  91. package/dist/controller/model/device.js.map +1 -1
  92. package/dist/index.d.ts +5 -5
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +4 -4
  95. package/dist/index.js.map +1 -1
  96. package/dist/utils/backup.d.ts +1 -1
  97. package/dist/utils/backup.d.ts.map +1 -1
  98. package/dist/utils/backup.js +1 -1
  99. package/dist/utils/backup.js.map +1 -1
  100. package/dist/utils/utils.d.ts.map +1 -1
  101. package/dist/utils/utils.js +0 -1
  102. package/dist/utils/utils.js.map +1 -1
  103. package/dist/zspec/utils.d.ts.map +1 -1
  104. package/dist/zspec/utils.js.map +1 -1
  105. package/dist/zspec/zcl/index.d.ts +3 -3
  106. package/dist/zspec/zcl/index.d.ts.map +1 -1
  107. package/dist/zspec/zcl/index.js +6 -6
  108. package/dist/zspec/zcl/index.js.map +1 -1
  109. package/dist/zspec/zcl/utils.d.ts.map +1 -1
  110. package/dist/zspec/zcl/utils.js +0 -1
  111. package/dist/zspec/zcl/utils.js.map +1 -1
  112. package/dist/zspec/zdo/buffaloZdo.d.ts.map +1 -1
  113. package/dist/zspec/zdo/index.d.ts +3 -3
  114. package/dist/zspec/zdo/index.d.ts.map +1 -1
  115. package/dist/zspec/zdo/index.js +6 -6
  116. package/dist/zspec/zdo/index.js.map +1 -1
  117. package/package.json +4 -4
  118. package/src/adapter/adapterDiscovery.ts +1 -4
  119. package/src/adapter/deconz/adapter/deconzAdapter.ts +474 -369
  120. package/src/adapter/deconz/driver/constants.ts +148 -82
  121. package/src/adapter/deconz/driver/driver.ts +1092 -503
  122. package/src/adapter/deconz/driver/frameParser.ts +351 -272
  123. package/src/adapter/ember/adapter/emberAdapter.ts +2 -3
  124. package/src/adapter/ember/adapter/tokensManager.ts +1 -1
  125. package/src/adapter/ember/enums.ts +20 -397
  126. package/src/adapter/ember/ezsp/buffalo.ts +3 -3
  127. package/src/adapter/ember/ezsp/consts.ts +1 -1
  128. package/src/adapter/ember/ezsp/enums.ts +31 -4
  129. package/src/adapter/ember/ezsp/ezsp.ts +84 -8
  130. package/src/adapter/ember/uart/ash.ts +1 -1
  131. package/src/adapter/ezsp/adapter/ezspAdapter.ts +2 -2
  132. package/src/adapter/ezsp/driver/commands.ts +5 -5
  133. package/src/adapter/ezsp/driver/driver.ts +6 -6
  134. package/src/adapter/ezsp/driver/ezsp.ts +3 -3
  135. package/src/adapter/ezsp/driver/types/index.ts +3 -3
  136. package/src/adapter/ezsp/driver/types/named.ts +1 -1
  137. package/src/adapter/serialPort.ts +1 -1
  138. package/src/adapter/z-stack/adapter/manager.ts +2 -3
  139. package/src/adapter/z-stack/adapter/zStackAdapter.ts +2 -2
  140. package/src/adapter/z-stack/structs/entries/index.ts +7 -7
  141. package/src/adapter/z-stack/structs/index.ts +2 -2
  142. package/src/adapter/zboss/adapter/zbossAdapter.ts +1 -2
  143. package/src/adapter/zboss/driver.ts +2 -3
  144. package/src/adapter/zboss/uart.ts +1 -1
  145. package/src/adapter/zigate/adapter/zigateAdapter.ts +1 -1
  146. package/src/adapter/zigate/driver/messageType.ts +1 -1
  147. package/src/adapter/zigate/driver/zigate.ts +1 -1
  148. package/src/adapter/zoh/adapter/zohAdapter.ts +1 -1
  149. package/src/buffalo/buffalo.ts +1 -2
  150. package/src/controller/controller.ts +2 -2
  151. package/src/controller/helpers/request.ts +2 -2
  152. package/src/controller/model/device.ts +1 -1
  153. package/src/index.ts +5 -5
  154. package/src/utils/backup.ts +1 -1
  155. package/src/utils/utils.ts +0 -1
  156. package/src/zspec/utils.ts +1 -3
  157. package/src/zspec/zcl/index.ts +3 -3
  158. package/src/zspec/zcl/utils.ts +0 -1
  159. package/src/zspec/zdo/buffaloZdo.ts +2 -2
  160. package/src/zspec/zdo/index.ts +3 -3
  161. package/test/adapter/adapter.test.ts +1 -2
  162. package/test/adapter/ember/ash.test.ts +1 -1
  163. package/test/adapter/ember/emberAdapter.test.ts +1 -1
  164. package/test/adapter/ember/ezsp.test.ts +2 -3
  165. package/test/adapter/ezsp/uart.test.ts +3 -3
  166. package/test/adapter/z-stack/znp.test.ts +6 -6
  167. package/test/adapter/zboss/fixZdoResponse.test.ts +1 -1
  168. package/test/adapter/zoh/zohAdapter.test.ts +2 -2
  169. package/test/controller.test.ts +8 -8
  170. package/test/greenpower.test.ts +1 -2
  171. package/test/tsconfig.json +1 -1
  172. package/test/utils.test.ts +1 -1
  173. package/test/zspec/zdo/buffalo.test.ts +1 -1
@@ -33,114 +33,113 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  return result;
34
34
  };
35
35
  })();
36
- var __importDefault = (this && this.__importDefault) || function (mod) {
37
- return (mod && mod.__esModule) ? mod : { "default": mod };
38
- };
39
36
  Object.defineProperty(exports, "__esModule", { value: true });
40
37
  exports.frameParserEvents = void 0;
41
38
  const node_events_1 = require("node:events");
39
+ const buffalo_1 = require("../../../buffalo");
42
40
  const logger_1 = require("../../../utils/logger");
43
41
  const Zdo = __importStar(require("../../../zspec/zdo"));
44
- const constants_1 = __importDefault(require("./constants"));
42
+ const constants_1 = require("./constants");
45
43
  const driver_1 = require("./driver");
46
44
  const NS = "zh:deconz:frameparser";
47
- const MIN_BUFFER_SIZE = 3;
48
45
  const littleEndian = true;
49
46
  const lastReceivedGpInd = { srcId: 0, commandId: 0, frameCounter: 0 };
50
47
  exports.frameParserEvents = new node_events_1.EventEmitter();
51
48
  function parseReadParameterResponse(view) {
49
+ const seqNumber = view.getUint8(1);
50
+ const status = view.getUint8(2);
52
51
  const parameterId = view.getUint8(7);
52
+ let pos = 8;
53
+ let result = null;
53
54
  switch (parameterId) {
54
- case constants_1.default.PARAM.Network.MAC: {
55
- const mac = view.getBigUint64(8, littleEndian).toString(16);
56
- let result = mac;
57
- while (result.length < 16) {
58
- result = `0${result}`;
59
- }
60
- result = `0x${result}`;
61
- logger_1.logger.debug(`MAC: ${result}`, NS);
62
- return result;
63
- }
64
- case constants_1.default.PARAM.Network.PAN_ID: {
65
- const panId = view.getUint16(8, littleEndian);
66
- logger_1.logger.debug(`PANID: ${panId.toString(16)}`, NS);
67
- return panId;
68
- }
69
- case constants_1.default.PARAM.Network.NWK_ADDRESS: {
70
- const nwkAddr = view.getUint16(8, littleEndian);
71
- logger_1.logger.debug(`NWKADDR: ${nwkAddr.toString(16)}`, NS);
72
- return nwkAddr;
73
- }
74
- case constants_1.default.PARAM.Network.EXT_PAN_ID: {
75
- const extPanId = view.getBigUint64(8, littleEndian).toString(16);
76
- let res = extPanId;
77
- while (res.length < 16) {
78
- res = `0${res}`;
79
- }
80
- res = `0x${res}`;
81
- logger_1.logger.debug(`EXT_PANID: ${res}`, NS);
82
- return res;
83
- }
84
- case constants_1.default.PARAM.Network.APS_EXT_PAN_ID: {
85
- const apsExtPanId = view.getBigUint64(8, littleEndian).toString(16);
86
- let resAEPID = apsExtPanId;
87
- while (resAEPID.length < 16) {
88
- resAEPID = `0${resAEPID}`;
89
- }
90
- resAEPID = `0x${resAEPID}`;
91
- logger_1.logger.debug(`APS_EXT_PANID: ${resAEPID}`, NS);
92
- return resAEPID;
93
- }
94
- case constants_1.default.PARAM.Network.NETWORK_KEY: {
95
- const networkKey1 = view.getBigUint64(9).toString(16);
96
- let res1 = networkKey1;
97
- while (res1.length < 16) {
98
- res1 = `0${res1}`;
99
- }
100
- const networkKey2 = view.getBigUint64(17).toString(16);
101
- let res2 = networkKey2;
102
- while (res2.length < 16) {
103
- res2 = `0${res2}`;
55
+ case constants_1.ParamId.MAC_ADDRESS: {
56
+ result = view.getBigUint64(pos, littleEndian);
57
+ break;
58
+ }
59
+ case constants_1.ParamId.APS_TRUST_CENTER_ADDRESS: {
60
+ result = view.getBigUint64(pos, littleEndian);
61
+ break;
62
+ }
63
+ case constants_1.ParamId.NWK_PANID: {
64
+ result = view.getUint16(pos, littleEndian);
65
+ break;
66
+ }
67
+ case constants_1.ParamId.STK_PROTOCOL_VERSION: {
68
+ result = view.getUint16(pos, littleEndian);
69
+ break;
70
+ }
71
+ case constants_1.ParamId.NWK_NETWORK_ADDRESS: {
72
+ result = view.getUint16(pos, littleEndian);
73
+ break;
74
+ }
75
+ case constants_1.ParamId.NWK_EXTENDED_PANID: {
76
+ result = view.getBigUint64(pos, littleEndian);
77
+ break;
78
+ }
79
+ case constants_1.ParamId.APS_USE_EXTENDED_PANID: {
80
+ result = view.getBigUint64(pos, littleEndian);
81
+ break;
82
+ }
83
+ case constants_1.ParamId.STK_NETWORK_KEY: {
84
+ result = Buffer.alloc(16);
85
+ pos += 1; // key index
86
+ for (let i = 0; i < 16; i++) {
87
+ result[i] = view.getUint8(pos);
88
+ pos += 1;
104
89
  }
105
- logger_1.logger.debug("NETWORK_KEY: hidden", NS);
106
- return `0x${res1}${res2}`;
90
+ break;
91
+ }
92
+ case constants_1.ParamId.STK_CURRENT_CHANNEL: {
93
+ result = view.getUint8(pos);
94
+ break;
107
95
  }
108
- case constants_1.default.PARAM.Network.CHANNEL: {
109
- const channel = view.getUint8(8);
110
- logger_1.logger.debug(`CHANNEL: ${channel}`, NS);
111
- return channel;
96
+ case constants_1.ParamId.APS_CHANNEL_MASK: {
97
+ result = view.getUint32(pos, littleEndian);
98
+ break;
112
99
  }
113
- case constants_1.default.PARAM.Network.CHANNEL_MASK: {
114
- const chMask = view.getUint32(8, littleEndian);
115
- logger_1.logger.debug(`CHANNELMASK: ${chMask.toString(16)}`, NS);
116
- return chMask;
100
+ case constants_1.ParamId.STK_FRAME_COUNTER: {
101
+ result = view.getUint32(pos, littleEndian);
102
+ break;
117
103
  }
118
- case constants_1.default.PARAM.Network.PERMIT_JOIN: {
119
- const permitJoin = view.getUint8(8);
120
- logger_1.logger.debug(`PERMIT_JOIN: ${permitJoin}`, NS);
121
- return permitJoin;
104
+ case constants_1.ParamId.STK_PERMIT_JOIN: {
105
+ result = view.getUint8(pos);
106
+ break;
122
107
  }
123
- case constants_1.default.PARAM.Network.WATCHDOG_TTL: {
124
- const ttl = view.getUint32(8);
125
- logger_1.logger.debug(`WATCHDOG_TTL: ${ttl}`, NS);
126
- return ttl;
108
+ case constants_1.ParamId.DEV_WATCHDOG_TTL: {
109
+ result = view.getUint32(pos, littleEndian);
110
+ break;
111
+ }
112
+ case constants_1.ParamId.STK_NWK_UPDATE_ID: {
113
+ result = view.getUint8(pos);
114
+ break;
127
115
  }
128
116
  default:
129
117
  //throw new Error(`unknown parameter id ${parameterId}`);
130
118
  logger_1.logger.debug(`unknown parameter id ${parameterId}`, NS);
131
- return null;
119
+ break;
132
120
  }
121
+ if (parameterId in constants_1.ParamId) {
122
+ let p = result;
123
+ if (parameterId === constants_1.ParamId.STK_NETWORK_KEY) {
124
+ // don't show in logs
125
+ p = "<hidden>";
126
+ }
127
+ else if (typeof result === "bigint") {
128
+ p = `0x${result.toString(16).padStart(16, "0")}`;
129
+ }
130
+ logger_1.logger.debug(`Received read parameter response for ${constants_1.ParamId[parameterId]}, seq: ${seqNumber}, status: ${status}, parameter: ${p}`, NS);
131
+ }
132
+ return result;
133
133
  }
134
134
  function parseReadFirmwareResponse(view) {
135
- const fw = [view.getUint8(5), view.getUint8(6), view.getUint8(7), view.getUint8(8)];
136
- logger_1.logger.debug(`read firmware version response - version: ${fw}`, NS);
135
+ const fw = view.getUint32(5, littleEndian);
136
+ logger_1.logger.debug(`read firmware version response - version: 0x${fw.toString(16)}`, NS);
137
137
  return fw;
138
138
  }
139
139
  function parseDeviceStateResponse(view) {
140
- const flag = view.getUint8(5);
141
- logger_1.logger.debug(`device state: ${flag.toString(2)}`, NS);
142
- exports.frameParserEvents.emit("receivedDataNotification", flag);
143
- return flag;
140
+ const deviceState = view.getUint8(5);
141
+ exports.frameParserEvents.emit("deviceStateUpdated", deviceState);
142
+ return deviceState;
144
143
  }
145
144
  function parseChangeNetworkStateResponse(view) {
146
145
  const status = view.getUint8(2);
@@ -148,163 +147,198 @@ function parseChangeNetworkStateResponse(view) {
148
147
  logger_1.logger.debug(`change network state - status: ${status} new state: ${state}`, NS);
149
148
  return state;
150
149
  }
151
- function parseQuerySendDataStateResponse(view) {
152
- try {
153
- const commandId = view.getUint8(0);
154
- const seqNr = view.getUint8(1);
155
- const status = view.getUint8(2);
156
- if (status !== 0) {
157
- if (status !== 5) {
158
- logger_1.logger.debug(`DATA_CONFIRM RESPONSE - seqNr.: ${seqNr} status: ${status}`, NS);
159
- }
160
- return null;
161
- }
162
- const frameLength = 7;
163
- const payloadLength = view.getUint16(5, littleEndian);
164
- const deviceState = view.getUint8(7);
165
- const requestId = view.getUint8(8);
166
- const destAddrMode = view.getUint8(9);
167
- let destAddr64;
168
- let destAddr16;
169
- let destEndpoint;
170
- let destAddr = "";
171
- if (destAddrMode === constants_1.default.PARAM.addressMode.IEEE_ADDR) {
172
- let res = view.getBigUint64(10, littleEndian).toString(16);
173
- while (res.length < 16) {
174
- res = `0${res}`;
175
- }
176
- destAddr64 = res;
177
- // const buf2 = view.buffer.slice(18, view.buffer.byteLength);
178
- destAddr = destAddr64;
179
- }
180
- else {
181
- destAddr16 = view.getUint16(10, littleEndian);
182
- // const buf2 = view.buffer.slice(12, view.buffer.byteLength);
183
- destAddr = destAddr16.toString(16);
184
- }
185
- if (destAddrMode === constants_1.default.PARAM.addressMode.NWK_ADDR || destAddrMode === constants_1.default.PARAM.addressMode.IEEE_ADDR) {
186
- destEndpoint = view.getUint8(view.byteLength - 7);
150
+ function parseApsConfirmResponse(view) {
151
+ const buf = new buffalo_1.Buffalo(Buffer.from(view.buffer));
152
+ const commandId = buf.readUInt8();
153
+ const seqNr = buf.readUInt8();
154
+ const status = buf.readUInt8();
155
+ if (status !== constants_1.CommandStatus.Success) {
156
+ logger_1.logger.debug(`Response APS-DATA.confirm seq: ${seqNr} status: ${constants_1.CommandStatus[status]} (error)`, NS);
157
+ return null;
158
+ }
159
+ const frameLength = buf.readUInt16();
160
+ const payloadLength = buf.readUInt16();
161
+ // payload
162
+ const deviceState = buf.readUInt8();
163
+ const requestId = buf.readUInt8();
164
+ const destAddrMode = buf.readUInt8();
165
+ let destAddr64;
166
+ let destAddr16;
167
+ let destEndpoint;
168
+ let destAddr = "";
169
+ if (destAddrMode === constants_1.ApsAddressMode.Nwk) {
170
+ destAddr16 = buf.readUInt16();
171
+ destAddr = destAddr16.toString(16).padStart(4, "0");
172
+ destEndpoint = buf.readUInt8();
173
+ }
174
+ else if (destAddrMode === constants_1.ApsAddressMode.Group) {
175
+ destAddr16 = buf.readUInt16();
176
+ destAddr = destAddr16.toString(16).padStart(4, "0");
177
+ }
178
+ else if (destAddrMode === constants_1.ApsAddressMode.Ieee) {
179
+ destAddr64 = buf.readUInt64().toString(16).padStart(16, "0");
180
+ destAddr = destAddr64;
181
+ destEndpoint = buf.readUInt8();
182
+ }
183
+ else {
184
+ logger_1.logger.debug(`Response APS-DATA.confirm seq: ${seqNr} unsupported address mode: ${destAddrMode}`, NS);
185
+ }
186
+ const srcEndpoint = buf.readUInt8();
187
+ const confirmStatus = buf.readUInt8();
188
+ // resolve APS-DATA.request promise
189
+ const i = driver_1.apsBusyQueue.findIndex((r) => r.request && r.request.requestId === requestId);
190
+ if (i < 0) {
191
+ return null;
192
+ }
193
+ const req = driver_1.apsBusyQueue[i];
194
+ let strstatus = "unknown";
195
+ const hexstatus = `0x${confirmStatus.toString(16).padStart(2, "0")}`;
196
+ if (confirmStatus in constants_1.ApsStatusCode) {
197
+ strstatus = constants_1.ApsStatusCode[confirmStatus];
198
+ }
199
+ if (confirmStatus === constants_1.ApsStatusCode.Success) {
200
+ req.resolve(confirmStatus);
201
+ }
202
+ else {
203
+ req.reject(new Error(`Failed APS-DATA.request with confirm status: ${strstatus} (${hexstatus})`));
204
+ }
205
+ //remove from busyqueue
206
+ driver_1.apsBusyQueue.splice(i, 1);
207
+ logger_1.logger.debug(`APS-DATA.confirm destAddr: 0x${destAddr} APS request id: ${requestId} confirm status: ${strstatus} ${hexstatus}`, NS);
208
+ exports.frameParserEvents.emit("deviceStateUpdated", deviceState);
209
+ return {
210
+ commandId,
211
+ seqNr,
212
+ status,
213
+ frameLength,
214
+ payloadLength,
215
+ deviceState,
216
+ requestId,
217
+ destAddrMode,
218
+ destAddr16,
219
+ destAddr64,
220
+ destEndpoint,
221
+ srcEndpoint,
222
+ confirmStatus,
223
+ };
224
+ }
225
+ // TODO(mpi): The ../buffalo/buffalo.ts already provides this, so we should reuse it instead of a own implementation?!
226
+ class UDataView {
227
+ littleEndian = true;
228
+ pos = 0;
229
+ view;
230
+ constructor(view, littleEndian) {
231
+ this.view = view;
232
+ this.littleEndian = littleEndian;
233
+ }
234
+ getI8() {
235
+ if (this.pos + 1 <= this.view.byteLength) {
236
+ this.pos += 1;
237
+ return this.view.getInt8(this.pos - 1);
187
238
  }
188
- const srcEndpoint = view.getUint8(view.byteLength - 6);
189
- const confirmStatus = view.getInt8(view.byteLength - 5);
190
- let newStatus = deviceState.toString(2);
191
- for (let l = 0; l <= 8 - newStatus.length; l++) {
192
- newStatus = `0${newStatus}`;
239
+ throw new RangeError();
240
+ }
241
+ getU8() {
242
+ if (this.pos + 1 <= this.view.byteLength) {
243
+ this.pos += 1;
244
+ return this.view.getUint8(this.pos - 1);
193
245
  }
194
- // resolve send data request promise
195
- const i = driver_1.apsBusyQueue.findIndex((r) => r.request && r.request.requestId === requestId);
196
- if (i < 0) {
197
- return null;
246
+ throw new RangeError();
247
+ }
248
+ getU16() {
249
+ if (this.pos + 2 <= this.view.byteLength) {
250
+ this.pos += 2;
251
+ return this.view.getUint16(this.pos - 2, this.littleEndian);
198
252
  }
199
- clearTimeout(driver_1.enableRtsTimeout);
200
- (0, driver_1.enableRTS)(); // enable ReadyToSend because confirm received
201
- const req = driver_1.apsBusyQueue[i];
202
- // TODO timeout (at driver.ts)
203
- if (confirmStatus !== 0) {
204
- // reject if status is not SUCCESS
205
- //logger.debug("REJECT APS_REQUEST - request id: " + requestId + " confirm status: " + confirmStatus, NS);
206
- req.reject(new Error(`confirmStatus=${confirmStatus}`));
253
+ throw new RangeError();
254
+ }
255
+ getU32() {
256
+ if (this.pos + 4 <= this.view.byteLength) {
257
+ this.pos += 4;
258
+ return this.view.getUint16(this.pos - 4, this.littleEndian);
207
259
  }
208
- else {
209
- //logger.debug("RESOLVE APS_REQUEST - request id: " + requestId + " confirm status: " + confirmStatus, NS);
210
- req.resolve(confirmStatus);
211
- }
212
- //remove from busyqueue
213
- driver_1.apsBusyQueue.splice(i, 1);
214
- logger_1.logger.debug(`DATA_CONFIRM RESPONSE - destAddr: 0x${destAddr} request id: ${requestId} confirm status: ${confirmStatus}`, NS);
215
- exports.frameParserEvents.emit("receivedDataNotification", deviceState);
216
- return {
217
- commandId,
218
- seqNr,
219
- status,
220
- frameLength,
221
- payloadLength,
222
- deviceState,
223
- requestId,
224
- destAddrMode,
225
- destAddr16,
226
- destAddr64,
227
- destEndpoint,
228
- srcEndpoint,
229
- confirmStatus,
230
- };
260
+ throw new RangeError();
231
261
  }
232
- catch (error) {
233
- logger_1.logger.debug(`DATA_CONFIRM RESPONSE - ${error}`, NS);
234
- return null;
262
+ getU64() {
263
+ if (this.pos + 8 <= this.view.byteLength) {
264
+ this.pos += 8;
265
+ return this.view.getBigUint64(this.pos - 8, this.littleEndian);
266
+ }
267
+ throw new RangeError();
235
268
  }
236
269
  }
237
- function parseReadReceivedDataResponse(view) {
270
+ function parseApsDataIndicationResponse(inview) {
238
271
  // min 28 bytelength
239
272
  try {
240
- let buf2;
241
- let buf3;
242
- const commandId = view.getUint8(0);
243
- const seqNr = view.getUint8(1);
244
- const status = view.getUint8(2);
245
- if (status !== 0) {
246
- if (status !== 5) {
247
- logger_1.logger.debug(`DATA_INDICATION RESPONSE - seqNr.: ${seqNr} status: ${status}`, NS);
248
- }
273
+ const uview = new UDataView(inview, true);
274
+ const commandId = uview.getU8();
275
+ const seqNr = uview.getU8();
276
+ const status = uview.getU8();
277
+ if (status !== constants_1.CommandStatus.Success) {
278
+ logger_1.logger.debug(`Response APS-DATA.indication seq: ${seqNr} status: ${constants_1.CommandStatus[status]}`, NS);
249
279
  return null;
250
280
  }
251
- const frameLength = view.getUint16(3, littleEndian);
252
- const payloadLength = view.getUint16(5, littleEndian);
253
- const deviceState = view.getUint8(7);
254
- const destAddrMode = view.getUint8(8);
281
+ const frameLength = uview.getU16();
282
+ const payloadLength = uview.getU16();
283
+ //------ start of payload ----------------------------------
284
+ const deviceState = uview.getU8();
285
+ const destAddrMode = uview.getU8();
255
286
  let destAddr64;
256
287
  let destAddr16;
257
- let destAddr = "";
258
- if (destAddrMode === constants_1.default.PARAM.addressMode.IEEE_ADDR) {
259
- let res = view.getBigUint64(9, littleEndian).toString(16);
260
- while (res.length < 16) {
261
- res = `0${res}`;
262
- }
263
- destAddr64 = res;
264
- buf2 = view.buffer.slice(17, view.buffer.byteLength);
288
+ let destAddr;
289
+ if (destAddrMode === constants_1.ApsAddressMode.Ieee) {
290
+ destAddr64 = uview.getU64().toString(16).padStart(16, "0");
291
+ destAddr16 = 0xfffe;
265
292
  destAddr = destAddr64;
266
293
  }
267
- else {
268
- destAddr16 = view.getUint16(9, littleEndian);
269
- buf2 = view.buffer.slice(11, view.buffer.byteLength);
294
+ else if (destAddrMode === constants_1.ApsAddressMode.Nwk || destAddrMode === constants_1.ApsAddressMode.Group) {
295
+ destAddr16 = uview.getU16();
270
296
  destAddr = destAddr16.toString(16);
271
297
  }
272
- view = new DataView(buf2);
273
- const destEndpoint = view.getUint8(0);
274
- const srcAddrMode = view.getUint8(1);
298
+ else {
299
+ throw new Error(`unsupported destination address mode: ${destAddrMode}`);
300
+ }
301
+ const destEndpoint = uview.getU8();
302
+ const srcAddrMode = uview.getU8();
275
303
  let srcAddr64;
276
- let srcAddr16;
277
- let srcAddr = "";
278
- if (srcAddrMode === constants_1.default.PARAM.addressMode.NWK_ADDR || srcAddrMode === 0x04) {
279
- srcAddr16 = view.getUint16(2, littleEndian);
280
- buf3 = view.buffer.slice(4, view.buffer.byteLength);
304
+ let srcAddr16 = 0xfffe;
305
+ let srcAddr;
306
+ if (srcAddrMode === constants_1.ApsAddressMode.Nwk || srcAddrMode === constants_1.ApsAddressMode.NwkAndIeee) {
307
+ srcAddr16 = uview.getU16();
281
308
  srcAddr = srcAddr16.toString(16);
282
- }
283
- if (srcAddrMode === constants_1.default.PARAM.addressMode.IEEE_ADDR || srcAddrMode === 0x04) {
284
- let res = view.getBigUint64(2, littleEndian).toString(16);
285
- while (res.length < 16) {
286
- res = `0${res}`;
309
+ if (srcAddrMode === constants_1.ApsAddressMode.NwkAndIeee) {
310
+ srcAddr64 = uview.getU64().toString(16).padStart(16, "0");
287
311
  }
288
- srcAddr64 = res;
289
- buf3 = view.buffer.slice(10, view.buffer.byteLength);
290
- srcAddr = srcAddr64;
291
- }
292
- // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
293
- view = new DataView(buf3); // XXX: not validated?
294
- const srcEndpoint = view.getUint8(0);
295
- const profileId = view.getUint16(1, littleEndian);
296
- const clusterId = view.getUint16(3, littleEndian);
297
- const asduLength = view.getUint16(5, littleEndian);
298
- const asduPayload = Buffer.from(view.buffer.slice(7, asduLength + 7));
299
- const lqi = view.getUint8(view.byteLength - 8);
300
- const rssi = view.getInt8(view.byteLength - 3);
301
- let newStatus = deviceState.toString(2);
302
- for (let l = 0; l <= 8 - newStatus.length; l++) {
303
- newStatus = `0${newStatus}`;
304
- }
305
- logger_1.logger.debug(`DATA_INDICATION RESPONSE - seqNr. ${seqNr} srcAddr: 0x${srcAddr} destAddr: 0x${destAddr} profile id: 0x${profileId.toString(16)} cluster id: 0x${clusterId.toString(16)} lqi: ${lqi}`, NS);
306
- logger_1.logger.debug(`response payload: ${asduPayload.toString("hex")}`, NS);
307
- exports.frameParserEvents.emit("receivedDataNotification", deviceState);
312
+ }
313
+ else {
314
+ throw new Error(`unsupported source address mode: ${srcAddrMode}`);
315
+ }
316
+ // else if (srcAddrMode === PARAM.PARAM.addressMode.IEEE_ADDR) {
317
+ // srcAddr64 = uview.getU64().toString(16).padStart(16, '0');
318
+ // srcAddr = srcAddr64;
319
+ // }
320
+ const srcEndpoint = uview.getU8();
321
+ const profileId = uview.getU16();
322
+ const clusterId = uview.getU16();
323
+ const asduLength = uview.getU16();
324
+ const asdu = new Uint8Array(asduLength);
325
+ for (let i = 0; i < asduLength; i++) {
326
+ asdu[i] = uview.getU8();
327
+ }
328
+ // The following two bytes depends on protocol version 2 or 3
329
+ // for now just discard
330
+ uview.getU16();
331
+ const lqi = uview.getU8();
332
+ // version >= 2
333
+ let rssi = 0;
334
+ try {
335
+ rssi = uview.getI8();
336
+ }
337
+ catch (_) { }
338
+ logger_1.logger.debug(`Response APS-DATA.indication seq: ${seqNr} srcAddr: 0x${srcAddr} destAddr: 0x${destAddr} profile id: 0x${profileId.toString(16).padStart(4, "0")} cluster id: 0x${clusterId.toString(16).padStart(4, "0")} lqi: ${lqi}`, NS);
339
+ //logger.debug(`Response payload: [${Array.from(asdu).map(x =>x.toString(16).padStart(2, '0')).join(' ')}]`, NS);
340
+ exports.frameParserEvents.emit("deviceStateUpdated", deviceState);
341
+ const asduPayload = Buffer.from(asdu);
308
342
  const response = {
309
343
  commandId,
310
344
  seqNr,
@@ -332,17 +366,17 @@ function parseReadReceivedDataResponse(view) {
332
366
  return response;
333
367
  }
334
368
  catch (error) {
335
- logger_1.logger.debug(`DATA_INDICATION RESPONSE - ${error}`, NS);
369
+ logger_1.logger.debug(`Response APS-DATA.indication error: ${error}`, NS);
336
370
  return null;
337
371
  }
338
372
  }
339
- function parseEnqueueSendDataResponse(view) {
373
+ function parseApsDataRequestResponse(view) {
340
374
  try {
341
375
  const status = view.getUint8(2);
342
376
  const requestId = view.getUint8(8);
343
377
  const deviceState = view.getUint8(7);
344
- logger_1.logger.debug(`DATA_REQUEST RESPONSE - request id: ${requestId} status: ${status}`, NS);
345
- exports.frameParserEvents.emit("receivedDataNotification", deviceState);
378
+ logger_1.logger.debug(`Response APS-DATA.request APS request id: ${requestId} status: ${constants_1.CommandStatus[status]}`, NS);
379
+ exports.frameParserEvents.emit("deviceStateUpdated", deviceState);
346
380
  return deviceState;
347
381
  }
348
382
  catch (error) {
@@ -352,8 +386,12 @@ function parseEnqueueSendDataResponse(view) {
352
386
  }
353
387
  function parseWriteParameterResponse(view) {
354
388
  try {
389
+ const status = view.getUint8(2);
355
390
  const parameterId = view.getUint8(7);
356
- logger_1.logger.debug(`write parameter response - parameter id: ${parameterId} - status: ${view.getUint8(2)}`, NS);
391
+ if (parameterId in constants_1.ParamId) {
392
+ // should always be true
393
+ logger_1.logger.debug(`Write parameter response parameter: ${constants_1.ParamId[parameterId]}, status: ${constants_1.CommandStatus[status]}`, NS);
394
+ }
357
395
  return parameterId;
358
396
  }
359
397
  catch (error) {
@@ -361,15 +399,14 @@ function parseWriteParameterResponse(view) {
361
399
  return null;
362
400
  }
363
401
  }
364
- function parseReceivedDataNotification(view) {
402
+ function parseDeviceStateChangedNotification(view) {
365
403
  try {
366
404
  const deviceState = view.getUint8(5);
367
- logger_1.logger.debug(`DEVICE_STATE changed: ${deviceState.toString(2)}`, NS);
368
- exports.frameParserEvents.emit("receivedDataNotification", deviceState);
405
+ exports.frameParserEvents.emit("deviceStateUpdated", deviceState);
369
406
  return deviceState;
370
407
  }
371
408
  catch (error) {
372
- logger_1.logger.debug(`parseReceivedDataNotification - ${error}`, NS);
409
+ logger_1.logger.debug(`parsedeviceStateUpdated - ${error}`, NS);
373
410
  return null;
374
411
  }
375
412
  }
@@ -435,43 +472,73 @@ function parseGreenPowerDataIndication(view) {
435
472
  }
436
473
  function parseMacPollCommand(_view) {
437
474
  //logger.debug("Received command MAC_POLL", NS);
438
- return 28;
475
+ return constants_1.FirmwareCommand.MacPollIndication;
439
476
  }
440
477
  function parseBeaconRequest(_view) {
441
478
  logger_1.logger.debug("Received Beacon Request", NS);
442
- return 31;
479
+ return constants_1.FirmwareCommand.Beacon;
480
+ }
481
+ function parseDebugLog(view) {
482
+ let dbg = "";
483
+ const buf = new buffalo_1.Buffalo(Buffer.from(view.buffer));
484
+ /* const commandId = */ buf.readUInt8();
485
+ /* const seqNr = */ buf.readUInt8();
486
+ const status = buf.readUInt8();
487
+ if (status !== constants_1.CommandStatus.Success) {
488
+ // unlikely
489
+ return null;
490
+ }
491
+ /* const frameLength = */ buf.readUInt16();
492
+ const payloadLength = buf.readUInt16();
493
+ for (let i = 0; i < payloadLength && buf.isMore(); i++) {
494
+ const ch = buf.readUInt8();
495
+ if (ch >= 32 && ch <= 127) {
496
+ dbg += String.fromCharCode(ch);
497
+ }
498
+ }
499
+ if (dbg.length !== 0) {
500
+ logger_1.logger.debug(`firmware log: ${dbg}`, NS);
501
+ }
502
+ return null;
443
503
  }
444
504
  function parseUnknownCommand(view) {
445
505
  const id = view.getUint8(0);
446
- logger_1.logger.debug(`received unknown command - id ${id}`, NS);
506
+ if (id in constants_1.FirmwareCommand) {
507
+ logger_1.logger.debug(`received unsupported command: ${constants_1.FirmwareCommand[id]} id: 0x${id.toString(16).padStart(2, "0")}`, NS);
508
+ }
509
+ else {
510
+ logger_1.logger.debug(`received unknown command: id: 0x${id.toString(16).padStart(2, "0")}`, NS);
511
+ }
447
512
  return id;
448
513
  }
449
514
  function getParserForCommandId(id) {
450
515
  switch (id) {
451
- case constants_1.default.PARAM.FrameType.ReadParameter:
516
+ case constants_1.FirmwareCommand.ReadParameter:
452
517
  return parseReadParameterResponse;
453
- case constants_1.default.PARAM.FrameType.WriteParameter:
518
+ case constants_1.FirmwareCommand.WriteParameter:
454
519
  return parseWriteParameterResponse;
455
- case constants_1.default.PARAM.FrameType.ReadFirmwareVersion:
520
+ case constants_1.FirmwareCommand.FirmwareVersion:
456
521
  return parseReadFirmwareResponse;
457
- case constants_1.default.PARAM.FrameType.ReadDeviceState:
522
+ case constants_1.FirmwareCommand.Status:
458
523
  return parseDeviceStateResponse;
459
- case constants_1.default.PARAM.APS.DATA_INDICATION:
460
- return parseReadReceivedDataResponse;
461
- case constants_1.default.PARAM.APS.DATA_REQUEST:
462
- return parseEnqueueSendDataResponse;
463
- case constants_1.default.PARAM.APS.DATA_CONFIRM:
464
- return parseQuerySendDataStateResponse;
465
- case constants_1.default.PARAM.FrameType.DeviceStateChanged:
466
- return parseReceivedDataNotification;
467
- case constants_1.default.PARAM.NetworkState.CHANGE_NETWORK_STATE:
524
+ case constants_1.FirmwareCommand.ApsDataIndication:
525
+ return parseApsDataIndicationResponse;
526
+ case constants_1.FirmwareCommand.ApsDataRequest:
527
+ return parseApsDataRequestResponse;
528
+ case constants_1.FirmwareCommand.ApsDataConfirm:
529
+ return parseApsConfirmResponse;
530
+ case constants_1.FirmwareCommand.StatusChangeIndication:
531
+ return parseDeviceStateChangedNotification;
532
+ case constants_1.FirmwareCommand.ChangeNetworkState:
468
533
  return parseChangeNetworkStateResponse;
469
- case constants_1.default.PARAM.FrameType.GreenPowerDataInd:
534
+ case constants_1.FirmwareCommand.ZgpDataIndication:
470
535
  return parseGreenPowerDataIndication;
471
- case 28:
536
+ case constants_1.FirmwareCommand.MacPollIndication:
472
537
  return parseMacPollCommand;
473
- case 31:
538
+ case constants_1.FirmwareCommand.Beacon:
474
539
  return parseBeaconRequest;
540
+ case constants_1.FirmwareCommand.DebugLog:
541
+ return parseDebugLog;
475
542
  default:
476
543
  return parseUnknownCommand;
477
544
  //throw new Error(`unknown command id ${id}`);
@@ -479,46 +546,46 @@ function getParserForCommandId(id) {
479
546
  }
480
547
  function processFrame(frame) {
481
548
  const [seqNumber, status, command, commandId] = parseFrame(frame);
482
- //logger.debug(`process frame with seq: ${seqNumber} status: ${status}`, NS);
549
+ // logger.debug(`Process frame with cmd: 0x${commandId.toString(16).padStart(2,'0')}, seq: ${seqNumber} status: ${status}`, NS);
483
550
  let queue = driver_1.busyQueue;
484
- if (commandId === constants_1.default.PARAM.APS.DATA_INDICATION || commandId === constants_1.default.PARAM.APS.DATA_REQUEST || commandId === constants_1.default.PARAM.APS.DATA_CONFIRM) {
551
+ if (commandId === constants_1.FirmwareCommand.ApsDataRequest) {
485
552
  queue = driver_1.apsBusyQueue;
486
553
  }
487
- const i = queue.findIndex((r) => r.seqNumber === seqNumber);
554
+ const i = queue.findIndex((r) => r.seqNumber === seqNumber && r.commandId === commandId);
488
555
  if (i < 0) {
489
556
  return;
490
557
  }
491
558
  const req = queue[i];
492
- if (commandId === constants_1.default.PARAM.APS.DATA_REQUEST) {
493
- // if confirm is true resolve request only when data confirm arrives
494
- // TODO only return if a confirm was requested. if no confirm needed: go ahead
495
- //if (req.confirm === true) {
496
- return;
497
- //}
559
+ if (commandId === constants_1.FirmwareCommand.ApsDataRequest) {
560
+ if (status === constants_1.CommandStatus.Success) {
561
+ // wait for APS-DATA.confirm to arrive
562
+ return;
563
+ }
564
+ // TODO(mpi): Within the timeout we should reschedule the APS-DATA.request (given that network state = connected)
565
+ // continue to reject as there will be no APS-DATA.confirm
498
566
  }
499
567
  //remove from busyqueue
500
568
  queue.splice(i, 1);
501
- if (status !== 0) {
502
- // reject if status is not SUCCESS
503
- //logger.debug("REJECT REQUEST", NS);
504
- req.reject(new Error(`status=${status}`));
569
+ if (status === constants_1.CommandStatus.Success) {
570
+ req.resolve(command);
505
571
  }
506
572
  else {
507
- //logger.debug("RESOLVE REQUEST", NS);
508
- req.resolve(command);
573
+ let cmdName;
574
+ if (commandId in constants_1.FirmwareCommand) {
575
+ cmdName = constants_1.FirmwareCommand[commandId];
576
+ }
577
+ else {
578
+ cmdName = `0x${commandId.toString(16).padStart(2, "0")}`;
579
+ }
580
+ req.reject(new Error(`Command ${cmdName} failed with status: ${constants_1.CommandStatus[status]}`));
509
581
  }
510
582
  }
511
583
  function parseFrame(frame) {
512
- if (frame.length < MIN_BUFFER_SIZE) {
513
- logger_1.logger.debug("received frame size to small - discard frame", NS);
514
- return [null, null, null, null];
515
- }
584
+ // at this point frame.buffer.length is at least 5 bytes long
516
585
  const view = new DataView(frame.buffer);
517
586
  const commandId = view.getUint8(0);
518
587
  const seqNumber = view.getUint8(1);
519
588
  const status = view.getUint8(2);
520
- //const frameLength = view.getUint16(3, littleEndian);
521
- //const payloadLength = view.getUint16(5, littleEndian);
522
589
  const parser = getParserForCommandId(commandId);
523
590
  return [seqNumber, status, parser(view), commandId];
524
591
  }