@robdobsn/raftjs 1.7.8 → 1.10.7

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 (224) hide show
  1. package/.editorconfig +14 -0
  2. package/.gitattributes +11 -0
  3. package/.nvmrc +1 -0
  4. package/TODO.md +1 -0
  5. package/dist/react-native/RaftAttributeHandler.d.ts +14 -0
  6. package/dist/react-native/RaftAttributeHandler.js +375 -0
  7. package/dist/react-native/RaftAttributeHandler.js.map +1 -0
  8. package/dist/react-native/RaftChannel.d.ts +20 -0
  9. package/dist/react-native/RaftChannel.js +12 -0
  10. package/dist/react-native/RaftChannel.js.map +1 -0
  11. package/dist/react-native/RaftChannelBLE.native.d.ts +95 -0
  12. package/dist/react-native/RaftChannelBLE.native.js +483 -0
  13. package/dist/react-native/RaftChannelBLE.native.js.map +1 -0
  14. package/dist/react-native/RaftChannelBLE.web.d.ts +40 -0
  15. package/dist/react-native/RaftChannelBLE.web.js +302 -0
  16. package/dist/react-native/RaftChannelBLE.web.js.map +1 -0
  17. package/dist/react-native/RaftChannelBLEFactory.d.ts +10 -0
  18. package/dist/react-native/RaftChannelBLEFactory.js +17 -0
  19. package/dist/react-native/RaftChannelBLEFactory.js.map +1 -0
  20. package/dist/react-native/RaftChannelBLEScanner.native.d.ts +18 -0
  21. package/dist/react-native/RaftChannelBLEScanner.native.js +138 -0
  22. package/dist/react-native/RaftChannelBLEScanner.native.js.map +1 -0
  23. package/dist/react-native/RaftChannelSimulated.d.ts +42 -0
  24. package/dist/react-native/RaftChannelSimulated.js +1000 -0
  25. package/dist/react-native/RaftChannelSimulated.js.map +1 -0
  26. package/dist/react-native/RaftChannelWebSerial.d.ts +39 -0
  27. package/dist/react-native/RaftChannelWebSerial.js +329 -0
  28. package/dist/react-native/RaftChannelWebSerial.js.map +1 -0
  29. package/dist/react-native/RaftChannelWebSocket.d.ts +30 -0
  30. package/dist/react-native/RaftChannelWebSocket.js +222 -0
  31. package/dist/react-native/RaftChannelWebSocket.js.map +1 -0
  32. package/dist/react-native/RaftCommsStats.d.ts +39 -0
  33. package/dist/react-native/RaftCommsStats.js +128 -0
  34. package/dist/react-native/RaftCommsStats.js.map +1 -0
  35. package/dist/react-native/RaftConnEvents.d.ts +39 -0
  36. package/dist/react-native/RaftConnEvents.js +54 -0
  37. package/dist/react-native/RaftConnEvents.js.map +1 -0
  38. package/dist/react-native/RaftConnector.d.ts +248 -0
  39. package/dist/react-native/RaftConnector.js +658 -0
  40. package/dist/react-native/RaftConnector.js.map +1 -0
  41. package/dist/react-native/RaftCustomAttrHandler.d.ts +6 -0
  42. package/dist/react-native/RaftCustomAttrHandler.js +93 -0
  43. package/dist/react-native/RaftCustomAttrHandler.js.map +1 -0
  44. package/dist/react-native/RaftDeviceInfo.d.ts +71 -0
  45. package/dist/react-native/RaftDeviceInfo.js +50 -0
  46. package/dist/react-native/RaftDeviceInfo.js.map +1 -0
  47. package/dist/react-native/RaftDeviceManager.d.ts +61 -0
  48. package/dist/react-native/RaftDeviceManager.js +665 -0
  49. package/dist/react-native/RaftDeviceManager.js.map +1 -0
  50. package/dist/react-native/RaftDeviceMgrIF.d.ts +15 -0
  51. package/dist/react-native/RaftDeviceMgrIF.js +11 -0
  52. package/dist/react-native/RaftDeviceMgrIF.js.map +1 -0
  53. package/dist/react-native/RaftDeviceMsg.d.ts +9 -0
  54. package/dist/react-native/RaftDeviceMsg.js +11 -0
  55. package/dist/react-native/RaftDeviceMsg.js.map +1 -0
  56. package/dist/react-native/RaftDeviceStates.d.ts +37 -0
  57. package/dist/react-native/RaftDeviceStates.js +60 -0
  58. package/dist/react-native/RaftDeviceStates.js.map +1 -0
  59. package/dist/react-native/RaftFileHandler.d.ts +52 -0
  60. package/dist/react-native/RaftFileHandler.js +502 -0
  61. package/dist/react-native/RaftFileHandler.js.map +1 -0
  62. package/dist/react-native/RaftLog.d.ts +22 -0
  63. package/dist/react-native/RaftLog.js +63 -0
  64. package/dist/react-native/RaftLog.js.map +1 -0
  65. package/dist/react-native/RaftMiniHDLC.d.ts +18 -0
  66. package/dist/react-native/RaftMiniHDLC.js +383 -0
  67. package/dist/react-native/RaftMiniHDLC.js.map +1 -0
  68. package/dist/react-native/RaftMsgHandler.d.ts +62 -0
  69. package/dist/react-native/RaftMsgHandler.js +511 -0
  70. package/dist/react-native/RaftMsgHandler.js.map +1 -0
  71. package/dist/react-native/RaftMsgTrackInfo.d.ts +17 -0
  72. package/dist/react-native/RaftMsgTrackInfo.js +42 -0
  73. package/dist/react-native/RaftMsgTrackInfo.js.map +1 -0
  74. package/dist/react-native/RaftProtocolDefs.d.ts +30 -0
  75. package/dist/react-native/RaftProtocolDefs.js +48 -0
  76. package/dist/react-native/RaftProtocolDefs.js.map +1 -0
  77. package/dist/react-native/RaftStreamHandler.d.ts +38 -0
  78. package/dist/react-native/RaftStreamHandler.js +258 -0
  79. package/dist/react-native/RaftStreamHandler.js.map +1 -0
  80. package/dist/react-native/RaftStruct.d.ts +3 -0
  81. package/dist/react-native/RaftStruct.js +258 -0
  82. package/dist/react-native/RaftStruct.js.map +1 -0
  83. package/dist/react-native/RaftSysTypeManager.d.ts +16 -0
  84. package/dist/react-native/RaftSysTypeManager.js +78 -0
  85. package/dist/react-native/RaftSysTypeManager.js.map +1 -0
  86. package/dist/react-native/RaftSystemType.d.ts +30 -0
  87. package/dist/react-native/RaftSystemType.js +3 -0
  88. package/dist/react-native/RaftSystemType.js.map +1 -0
  89. package/dist/react-native/RaftSystemUtils.d.ts +136 -0
  90. package/dist/react-native/RaftSystemUtils.js +412 -0
  91. package/dist/react-native/RaftSystemUtils.js.map +1 -0
  92. package/dist/react-native/RaftTypes.d.ts +195 -0
  93. package/dist/react-native/RaftTypes.js +153 -0
  94. package/dist/react-native/RaftTypes.js.map +1 -0
  95. package/dist/react-native/RaftUpdateEvents.d.ts +33 -0
  96. package/dist/react-native/RaftUpdateEvents.js +46 -0
  97. package/dist/react-native/RaftUpdateEvents.js.map +1 -0
  98. package/dist/react-native/RaftUpdateManager.d.ts +61 -0
  99. package/dist/react-native/RaftUpdateManager.js +621 -0
  100. package/dist/react-native/RaftUpdateManager.js.map +1 -0
  101. package/dist/react-native/RaftUtils.d.ts +128 -0
  102. package/dist/react-native/RaftUtils.js +487 -0
  103. package/dist/react-native/RaftUtils.js.map +1 -0
  104. package/dist/react-native/RaftWifiTypes.d.ts +23 -0
  105. package/dist/react-native/RaftWifiTypes.js +43 -0
  106. package/dist/react-native/RaftWifiTypes.js.map +1 -0
  107. package/dist/react-native/main.d.ts +26 -0
  108. package/dist/react-native/main.js +51 -0
  109. package/dist/react-native/main.js.map +1 -0
  110. package/dist/web/RaftAttributeHandler.js +9 -6
  111. package/dist/web/RaftAttributeHandler.js.map +1 -1
  112. package/dist/web/RaftChannelBLE.web.js +8 -6
  113. package/dist/web/RaftChannelBLE.web.js.map +1 -1
  114. package/dist/web/RaftChannelSimulated.d.ts +10 -0
  115. package/dist/web/RaftChannelSimulated.js +662 -80
  116. package/dist/web/RaftChannelSimulated.js.map +1 -1
  117. package/dist/web/RaftChannelWebSerial.js +2 -2
  118. package/dist/web/RaftChannelWebSerial.js.map +1 -1
  119. package/dist/web/RaftChannelWebSocket.js +16 -1
  120. package/dist/web/RaftChannelWebSocket.js.map +1 -1
  121. package/dist/web/RaftConnector.d.ts +2 -0
  122. package/dist/web/RaftConnector.js +38 -15
  123. package/dist/web/RaftConnector.js.map +1 -1
  124. package/dist/web/RaftCustomAttrHandler.d.ts +2 -0
  125. package/dist/web/RaftCustomAttrHandler.js +54 -26
  126. package/dist/web/RaftCustomAttrHandler.js.map +1 -1
  127. package/dist/web/RaftDeviceInfo.d.ts +3 -1
  128. package/dist/web/RaftDeviceInfo.js +17 -3
  129. package/dist/web/RaftDeviceInfo.js.map +1 -1
  130. package/dist/web/RaftDeviceManager.d.ts +22 -1
  131. package/dist/web/RaftDeviceManager.js +210 -44
  132. package/dist/web/RaftDeviceManager.js.map +1 -1
  133. package/dist/web/RaftDeviceStates.d.ts +1 -1
  134. package/dist/web/RaftDeviceStates.js +2 -2
  135. package/dist/web/RaftDeviceStates.js.map +1 -1
  136. package/dist/web/RaftMsgHandler.js.map +1 -1
  137. package/dist/web/RaftStreamHandler.js +2 -1
  138. package/dist/web/RaftStreamHandler.js.map +1 -1
  139. package/dist/web/RaftStruct.js +197 -147
  140. package/dist/web/RaftStruct.js.map +1 -1
  141. package/dist/web/RaftUpdateManager.js +1 -1
  142. package/dist/web/RaftUpdateManager.js.map +1 -1
  143. package/dist/web/RaftUtils.d.ts +2 -0
  144. package/dist/web/RaftUtils.js +20 -0
  145. package/dist/web/RaftUtils.js.map +1 -1
  146. package/dist/web/main.d.ts +1 -0
  147. package/dist/web/main.js.map +1 -1
  148. package/eslint.config.mjs +33 -0
  149. package/examples/dashboard/package.json +36 -0
  150. package/examples/dashboard/src/CommandPanel.tsx +147 -0
  151. package/examples/dashboard/src/ConnManager.ts +166 -0
  152. package/examples/dashboard/src/DeviceActionsForm.tsx +133 -0
  153. package/examples/dashboard/src/DeviceAttrsForm.tsx +49 -0
  154. package/examples/dashboard/src/DeviceLineChart.tsx +163 -0
  155. package/examples/dashboard/src/DevicePanel.tsx +171 -0
  156. package/examples/dashboard/src/DevicesPanel.tsx +58 -0
  157. package/examples/dashboard/src/DispLedGrid.tsx +110 -0
  158. package/examples/dashboard/src/DispOneLed.tsx +20 -0
  159. package/examples/dashboard/src/LatencyTest.ts +130 -0
  160. package/examples/dashboard/src/LatencyTestPanel.tsx +92 -0
  161. package/examples/dashboard/src/Main.tsx +234 -0
  162. package/examples/dashboard/src/SettingsManager.ts +67 -0
  163. package/examples/dashboard/src/SettingsScreen.tsx +174 -0
  164. package/examples/dashboard/src/StatusPanel.tsx +71 -0
  165. package/examples/dashboard/src/SystemTypeCog/CogStateInfo.ts +162 -0
  166. package/examples/dashboard/src/SystemTypeCog/SystemTypeCog.ts +91 -0
  167. package/examples/dashboard/src/SystemTypeGeneric/StateInfoGeneric.ts +30 -0
  168. package/examples/dashboard/src/SystemTypeGeneric/SystemTypeGeneric.ts +91 -0
  169. package/examples/dashboard/src/SystemTypeMarty/RICAddOn.ts +70 -0
  170. package/examples/dashboard/src/SystemTypeMarty/RICAddOnBase.ts +33 -0
  171. package/examples/dashboard/src/SystemTypeMarty/RICAddOnManager.ts +342 -0
  172. package/examples/dashboard/src/SystemTypeMarty/RICCommsStats.ts +170 -0
  173. package/examples/dashboard/src/SystemTypeMarty/RICHWElem.ts +123 -0
  174. package/examples/dashboard/src/SystemTypeMarty/RICLEDPatternChecker.ts +207 -0
  175. package/examples/dashboard/src/SystemTypeMarty/RICROSSerial.ts +464 -0
  176. package/examples/dashboard/src/SystemTypeMarty/RICServoFaultDetector.ts +146 -0
  177. package/examples/dashboard/src/SystemTypeMarty/RICStateInfo.ts +97 -0
  178. package/examples/dashboard/src/SystemTypeMarty/RICSystemUtils.ts +371 -0
  179. package/examples/dashboard/src/SystemTypeMarty/RICTypes.ts +20 -0
  180. package/examples/dashboard/src/SystemTypeMarty/SystemTypeMarty.ts +119 -0
  181. package/examples/dashboard/src/index.html +15 -0
  182. package/examples/dashboard/src/index.tsx +13 -0
  183. package/examples/dashboard/src/styles.css +408 -0
  184. package/examples/dashboard/tsconfig.json +18 -0
  185. package/jest.config.js +11 -0
  186. package/package.json +4 -7
  187. package/src/RaftAttributeHandler.ts +450 -0
  188. package/src/RaftChannel.ts +32 -0
  189. package/src/RaftChannelBLE.native.ts +617 -0
  190. package/src/RaftChannelBLE.web.ts +374 -0
  191. package/src/RaftChannelBLEFactory.ts +13 -0
  192. package/src/RaftChannelBLEScanner.native.ts +184 -0
  193. package/src/RaftChannelSimulated.ts +1176 -0
  194. package/src/RaftChannelWebSerial.ts +420 -0
  195. package/src/RaftChannelWebSocket.ts +272 -0
  196. package/src/RaftCommsStats.ts +142 -0
  197. package/src/RaftConnEvents.ts +58 -0
  198. package/src/RaftConnector.ts +785 -0
  199. package/src/RaftCustomAttrHandler.ts +117 -0
  200. package/src/RaftDeviceInfo.ts +125 -0
  201. package/src/RaftDeviceManager.ts +844 -0
  202. package/src/RaftDeviceMgrIF.ts +33 -0
  203. package/src/RaftDeviceMsg.ts +20 -0
  204. package/src/RaftDeviceStates.ts +92 -0
  205. package/src/RaftFileHandler.ts +668 -0
  206. package/src/RaftLog.ts +70 -0
  207. package/src/RaftMiniHDLC.ts +396 -0
  208. package/src/RaftMsgHandler.ts +812 -0
  209. package/src/RaftMsgTrackInfo.ts +51 -0
  210. package/src/RaftProtocolDefs.ts +46 -0
  211. package/src/RaftStreamHandler.ts +329 -0
  212. package/src/RaftStruct.ts +282 -0
  213. package/src/RaftSysTypeManager.ts +87 -0
  214. package/src/RaftSystemType.ts +34 -0
  215. package/src/RaftSystemUtils.ts +489 -0
  216. package/src/RaftTypes.ts +279 -0
  217. package/src/RaftUpdateEvents.ts +48 -0
  218. package/src/RaftUpdateManager.ts +781 -0
  219. package/src/RaftUtils.ts +514 -0
  220. package/src/RaftWifiTypes.ts +36 -0
  221. package/src/main.ts +39 -0
  222. package/testdata/TestDeviceTypeRecs.json +492 -0
  223. package/tsconfig.json +30 -0
  224. package/tsconfig.react-native.json +29 -0
@@ -0,0 +1,665 @@
1
+ "use strict";
2
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3
+ //
4
+ // RaftDeviceManager
5
+ // Device manager for Raft devices
6
+ //
7
+ // Rob Dobson (C) 2024
8
+ //
9
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.DeviceManager = void 0;
12
+ const tslib_1 = require("tslib");
13
+ const RaftDeviceStates_1 = require("./RaftDeviceStates");
14
+ const RaftAttributeHandler_1 = tslib_1.__importDefault(require("./RaftAttributeHandler"));
15
+ const RaftStruct_1 = require("./RaftStruct");
16
+ class DeviceManager {
17
+ getDevicesState() {
18
+ return this._devicesState;
19
+ }
20
+ getDeviceState(deviceKey) {
21
+ return this._devicesState[deviceKey];
22
+ }
23
+ // Constructor
24
+ constructor() {
25
+ // Max data points to store
26
+ this._maxDatapointsToStore = 1000;
27
+ // Min time between attempts to retrieve device type info
28
+ this._minTimeBetweenDeviceTypeInfoRetrievalMs = 60000;
29
+ // Attribute handler
30
+ this._attributeHandler = new RaftAttributeHandler_1.default();
31
+ // Devices state
32
+ this._devicesState = new RaftDeviceStates_1.DevicesState();
33
+ // Last time each device was updated - used to detect devices that are no longer present
34
+ this._deviceLastUpdateTime = {};
35
+ // Flag indicating that removed devices should be removed from the state
36
+ this._removeDevicesFlag = true;
37
+ this._removeDevicesTimeMs = 60000;
38
+ // System utils
39
+ this._systemUtils = null;
40
+ // Device callbacks
41
+ this._newDeviceCallbacks = [];
42
+ this._newDeviceAttributeCallbacks = [];
43
+ this._newAttributeDataCallbacks = [];
44
+ this._decodedDataCallbacks = [];
45
+ // Debug message index (to help debug with async messages)
46
+ this._debugMsgIndex = 0;
47
+ // Cached device type data
48
+ this._cachedDeviceTypeRecs = {};
49
+ // Cached device type previous attempt times
50
+ this._cachedDeviceTypePreviousAttemptTimes = {};
51
+ // Pending device type requests - queue-based to maintain order
52
+ this._pendingDeviceTypeRequests = {};
53
+ }
54
+ ////////////////////////////////////////////////////////////////////////////
55
+ // Settings
56
+ ////////////////////////////////////////////////////////////////////////////
57
+ setMaxDataPointsToStore(maxDatapointsToStore) {
58
+ this._maxDatapointsToStore = maxDatapointsToStore;
59
+ // console.log(`DeviceManager setMaxDataPointsToStore ${maxDatapointsToStore}`);
60
+ }
61
+ ////////////////////////////////////////////////////////////////////////////
62
+ // Send REST commands
63
+ ////////////////////////////////////////////////////////////////////////////
64
+ async sendCommand(cmd) {
65
+ var _a;
66
+ try {
67
+ // Get the msg handler
68
+ const msgHandler = (_a = this._systemUtils) === null || _a === void 0 ? void 0 : _a.getMsgHandler();
69
+ if (msgHandler) {
70
+ const msgRslt = await msgHandler.sendRICRESTURL(cmd);
71
+ return msgRslt.rslt === "ok";
72
+ }
73
+ return false;
74
+ }
75
+ catch (error) {
76
+ console.warn(`DeviceManager sendCommand error ${error}`);
77
+ return false;
78
+ }
79
+ }
80
+ ////////////////////////////////////////////////////////////////////////////
81
+ // Setup
82
+ ////////////////////////////////////////////////////////////////////////////
83
+ async setup(systemUtils) {
84
+ // Save the system utils
85
+ this._systemUtils = systemUtils;
86
+ return true;
87
+ }
88
+ ////////////////////////////////////////////////////////////////////////////
89
+ // Register callbacks
90
+ ////////////////////////////////////////////////////////////////////////////
91
+ addNewDeviceCallback(callback) {
92
+ if (!this._newDeviceCallbacks.includes(callback)) {
93
+ this._newDeviceCallbacks.push(callback);
94
+ }
95
+ }
96
+ removeNewDeviceCallback(callback) {
97
+ this._newDeviceCallbacks = this._newDeviceCallbacks.filter((cb) => cb !== callback);
98
+ }
99
+ addNewAttributeCallback(callback) {
100
+ if (!this._newDeviceAttributeCallbacks.includes(callback)) {
101
+ this._newDeviceAttributeCallbacks.push(callback);
102
+ }
103
+ }
104
+ removeNewAttributeCallback(callback) {
105
+ this._newDeviceAttributeCallbacks = this._newDeviceAttributeCallbacks.filter((cb) => cb !== callback);
106
+ }
107
+ addAttributeDataCallback(callback) {
108
+ if (!this._newAttributeDataCallbacks.includes(callback)) {
109
+ this._newAttributeDataCallbacks.push(callback);
110
+ }
111
+ }
112
+ removeAttributeDataCallback(callback) {
113
+ this._newAttributeDataCallbacks = this._newAttributeDataCallbacks.filter((cb) => cb !== callback);
114
+ }
115
+ addDecodedDataCallback(callback) {
116
+ if (!this._decodedDataCallbacks.includes(callback)) {
117
+ this._decodedDataCallbacks.push(callback);
118
+ }
119
+ }
120
+ removeDecodedDataCallback(callback) {
121
+ this._decodedDataCallbacks = this._decodedDataCallbacks.filter((cb) => cb !== callback);
122
+ }
123
+ ////////////////////////////////////////////////////////////////////////////
124
+ // Set the friendly name for the device
125
+ ////////////////////////////////////////////////////////////////////////////
126
+ async setFriendlyName(friendlyName) {
127
+ var _a;
128
+ // Set using utils
129
+ await ((_a = this._systemUtils) === null || _a === void 0 ? void 0 : _a.setRaftName(friendlyName));
130
+ }
131
+ ////////////////////////////////////////////////////////////////////////////
132
+ // Handle device message binary
133
+ ////////////////////////////////////////////////////////////////////////////
134
+ async handleClientMsgBinary(rxMsg) {
135
+ // console.log(`DeviceManager client1 msg ${RaftUtils.bufferToHex(rxMsg)}`);
136
+ // Example messages
137
+ // 0080 0015 81 0000006a 0004 53b7 feff00000100081857079314 0011 80 00000000 0011 53b2 075106e400d60054 0010 80 00000000 0012 5231 000d0000010e01
138
+ // 0080 0011 80 00000000 0002 4ae1 0787052606240007 000e 80 00000000 0003 0006 030001af01
139
+ // 0080 0011 80 00000000 0002 e46e 061e05a206830433 0010 80000000000003e4760006030001c701
140
+ // 0080 0010 81 00000015 0004 e4a2 0650fe00305002 0011 80000000000002e4a8061f059f06850438 001080000000000003e4aa0006030001c701
141
+ // 0080 0011 80 00000000 0002 31e4 05ea05a506660137 000e 80 00000000 0003 0007 030001d901
142
+ // 0080 0011 80 00000000 0002 4d63 0792053e06500061 000e 80 00000000 0003 0005 030001de01
143
+ // First two bytes of each message are the message type (0080)
144
+ // There are then a series of sections each of which is the data for a device
145
+ // First two bytes of each section is the section length (big endian) not including the section length bytes themselves
146
+ // Next byte is the connection mode (0 for direct connect, 1+ for bus number) and the MSB of this byte is 1 if the device is online
147
+ // Next is the device address (4 bytes big endian)
148
+ // Next is the device type index (2 bytes big endian)
149
+ // Finally the device data which can be one or more groups of attributes defined by the schema
150
+ // Debug
151
+ // const debugMsgTime = Date.now();
152
+ const debugMsgIndex = this._debugMsgIndex++;
153
+ // Message layout
154
+ const msgTypeLen = 2; // Length of the message type (first two bytes)
155
+ const sectionLengthLen = 2; // Length of the inclusive section length (first two bytes of each section)
156
+ const sectionConnectionModeLen = 1; // Length of the connection mode (next byte after section length)
157
+ const sectionDeviceAddrLen = 4; // Length of the device address (next 4 bytes after connection mode)
158
+ const sectionDeviceTypeIdxLen = 2; // Length of the device type index (next 2 bytes after device address)
159
+ const sectionHeaderLen = sectionConnectionModeLen + sectionDeviceAddrLen + sectionDeviceTypeIdxLen;
160
+ // console.log(`DevMan.handleClientMsgBinary debugIdx ${debugMsgIndex} rxMsg.length ${rxMsg.length} rxMsg ${RaftUtils.bufferToHex(rxMsg)}`);
161
+ // Start after the message type
162
+ let msgPos = msgTypeLen;
163
+ // Iterate through sections
164
+ while (msgPos < rxMsg.length) {
165
+ // Check length
166
+ const remainingLen = rxMsg.length - msgPos;
167
+ if (remainingLen < sectionLengthLen + sectionHeaderLen) {
168
+ console.warn(`DevMan.handleClientMsgBinary debugIdx ${debugMsgIndex} invalid length ${rxMsg.length} < ${sectionLengthLen + sectionHeaderLen + msgPos}`);
169
+ return;
170
+ }
171
+ // Get the length of the section
172
+ const sectionLen = (rxMsg[msgPos] << 8) + rxMsg[msgPos + 1];
173
+ if (sectionLen > remainingLen + sectionLengthLen) {
174
+ console.warn(`DevMan.handleClientMsgBinary debugIdx ${debugMsgIndex} invalid msgPos ${msgPos} msgLen ${sectionLen} remainingLenAfterLenBytes ${remainingLen - sectionLengthLen}`);
175
+ return;
176
+ }
177
+ // Extract message elements
178
+ let sectionPos = msgPos + sectionLengthLen;
179
+ const busNum = rxMsg[sectionPos] & 0x7f;
180
+ const isOnline = (rxMsg[sectionPos] & 0x80) !== 0;
181
+ sectionPos += sectionConnectionModeLen;
182
+ // Get the device address and type index
183
+ const devAddr = (rxMsg[sectionPos] << 24) + (rxMsg[sectionPos + 1] << 16) + (rxMsg[sectionPos + 2] << 8) + rxMsg[sectionPos + 3];
184
+ sectionPos += sectionDeviceAddrLen;
185
+ const devTypeIdx = (rxMsg[sectionPos] << 8) + rxMsg[sectionPos + 1];
186
+ let attrGroupPos = sectionPos + sectionDeviceTypeIdxLen;
187
+ // Debug
188
+ // console.log(`DevMan.handleClientMsgBinary debugIdx ${debugMsgIndex} overallLen ${rxMsg.length} sectionPos ${msgPos} sectionLen ${sectionLen} ${attrGroupPos} ${RaftUtils.bufferToHex(rxMsg.slice(msgPos, msgPos + sectionLen))}`);
189
+ // console.log(`DevMan.handleClientMsgBinary debugIdx ${debugMsgIndex} connMode ${busNum} isOnline ${isOnline} devAddr ${devAddr} devTypeIdx ${devTypeIdx} attrGroupDataLen ${sectionLen - sectionHeaderLen}`);
190
+ // Device key
191
+ const deviceKey = (0, RaftDeviceStates_1.getDeviceKey)(busNum.toString(), devAddr.toString(16));
192
+ // Update the last update time
193
+ this._deviceLastUpdateTime[deviceKey] = Date.now();
194
+ // Check if a device state already exists
195
+ if (!(deviceKey in this._devicesState) || (this._devicesState[deviceKey].deviceTypeInfo === undefined)) {
196
+ // Get the device type info
197
+ const deviceTypeInfo = await this.getDeviceTypeInfo(busNum.toString(), devTypeIdx.toString());
198
+ // Debug
199
+ // console.log(`DevMan.handleClientMsgBinary debugIdx ${debugMsgIndex} attrGroupPos ${attrGroupPos} busNum ${busNum} devAddr ${devAddr} devTypeIdx ${devTypeIdx} deviceTypeInfo ${JSON.stringify(deviceTypeInfo)}`);
200
+ // Handle case where device type info is not available
201
+ if (deviceTypeInfo === undefined) {
202
+ console.warn(`DevMan.handleClientMsgBinary debugIdx ${debugMsgIndex} deviceType ${devTypeIdx} info not available, skipping attribute processing for this section`);
203
+ // Skip to next section without processing attributes
204
+ msgPos += sectionLengthLen + sectionLen;
205
+ continue;
206
+ }
207
+ // Check if device record exists
208
+ if (deviceKey in this._devicesState) {
209
+ if (deviceTypeInfo !== undefined) {
210
+ this._devicesState[deviceKey].deviceTypeInfo = deviceTypeInfo;
211
+ this._devicesState[deviceKey].deviceType = deviceTypeInfo.name || "";
212
+ this._devicesState[deviceKey].busName = busNum.toString();
213
+ this._devicesState[deviceKey].deviceAddress = devAddr.toString();
214
+ }
215
+ }
216
+ else {
217
+ // Create device record - device type info may be undefined
218
+ this._devicesState[deviceKey] = {
219
+ deviceTypeInfo: deviceTypeInfo,
220
+ deviceTimeline: {
221
+ timestampsUs: [],
222
+ lastReportTimestampUs: 0,
223
+ reportTimestampOffsetUs: 0
224
+ },
225
+ deviceAttributes: {},
226
+ deviceIsNew: true,
227
+ stateChanged: false,
228
+ isOnline: true,
229
+ deviceAddress: devAddr.toString(),
230
+ deviceType: (deviceTypeInfo === null || deviceTypeInfo === void 0 ? void 0 : deviceTypeInfo.name) || "",
231
+ busName: busNum.toString()
232
+ };
233
+ }
234
+ }
235
+ // Get device state
236
+ const deviceState = this._devicesState[deviceKey];
237
+ deviceState.isOnline = isOnline;
238
+ // Check if device type info is available and complete
239
+ if (deviceState.deviceTypeInfo && deviceState.deviceTypeInfo.resp) {
240
+ // Iterate over attributes in the group
241
+ const pollRespMetadata = deviceState.deviceTypeInfo.resp;
242
+ // Iterate over attribute groups
243
+ const attrGroupDataLen = sectionLen - sectionHeaderLen;
244
+ const attrGroupStartPos = attrGroupPos;
245
+ const attrLengthsBefore = this.snapshotAttrLengths(deviceState.deviceAttributes, pollRespMetadata);
246
+ const timelineLenBefore = deviceState.deviceTimeline.timestampsUs.length;
247
+ while (attrGroupPos < attrGroupStartPos + attrGroupDataLen) {
248
+ // Add bounds checking
249
+ if (attrGroupPos >= rxMsg.length) {
250
+ console.warn(`DevMan.handleClientMsgBinary debugIdx ${debugMsgIndex} attrGroupPos ${attrGroupPos} exceeds message length ${rxMsg.length}`);
251
+ break;
252
+ }
253
+ const newMsgBufIdx = this._attributeHandler.processMsgAttrGroup(rxMsg, attrGroupPos, deviceState.deviceTimeline, pollRespMetadata, deviceState.deviceAttributes, this._maxDatapointsToStore);
254
+ // console.log(`DevMan.handleClientMsgBinary decoded debugIdx ${debugMsgIndex} devType ${deviceState.deviceTypeInfo.name} attrGroupDataLen ${attrGroupDataLen} attrGroupPos ${attrGroupPos} sectionLen ${sectionLen} msgPos ${msgPos} rxMsgLen ${rxMsg.length} remainingLen ${remainingLen} pollRespMetadata ${JSON.stringify(pollRespMetadata)}`);
255
+ if (newMsgBufIdx < 0) {
256
+ console.warn(`DevMan.handleClientMsgBinary debugIdx ${debugMsgIndex} processMsgAttrGroup failed newMsgBufIdx ${newMsgBufIdx}`);
257
+ break;
258
+ }
259
+ // Prevent infinite loops
260
+ if (newMsgBufIdx <= attrGroupPos) {
261
+ console.warn(`DevMan.handleClientMsgBinary debugIdx ${debugMsgIndex} processMsgAttrGroup didn't advance position from ${attrGroupPos} to ${newMsgBufIdx}`);
262
+ break;
263
+ }
264
+ attrGroupPos = newMsgBufIdx;
265
+ deviceState.stateChanged = true;
266
+ // console.log(`debugMsgTime ${debugMsgTime} newPt debugMsgIdx ${debugMsgIndex} rxMsgLen ${rxMsg.length} devType ${deviceState.deviceTypeInfo!.name} timestampsUs ${deviceState.deviceTimeline.timestampsUs[deviceState.deviceTimeline.timestampsUs.length - 1]} curTimelineLen ${deviceState.deviceTimeline.timestampsUs.length}`);
267
+ // console.log(`DevMan.handleClientMsgBinary group done debugIdx ${debugMsgIndex} attrGroupPos ${attrGroupPos} sectionLen ${sectionLen} msgPos ${msgPos} rxMsgLen ${rxMsg.length} remainingLen ${remainingLen}`);
268
+ }
269
+ // Inform decoded-data callbacks
270
+ this.emitDecodedData(deviceKey, busNum.toString(), devAddr.toString(), deviceState, pollRespMetadata, attrLengthsBefore, timelineLenBefore);
271
+ }
272
+ else {
273
+ console.warn(`DevMan.handleClientMsgBinary debugIdx ${debugMsgIndex} deviceState incomplete for device ${deviceKey}, skipping attribute processing`);
274
+ }
275
+ // Debug
276
+ // console.log(`DevMan.handleClientMsgBinary section done debugIdx ${debugMsgIndex} attrGroupPos ${attrGroupPos} sectionLen ${sectionLen} msgPos ${msgPos} newMsgPos ${msgPos + sectionLengthLen + sectionLen} rxMsgLen ${rxMsg.length} remainingLen ${remainingLen}`);
277
+ // Move to next message
278
+ msgPos += sectionLengthLen + sectionLen;
279
+ }
280
+ // Check for devices that have not been updated for a while
281
+ if (this._removeDevicesFlag) {
282
+ const nowTime = Date.now();
283
+ Object.entries(this._deviceLastUpdateTime).forEach(([deviceKey, lastUpdateTime]) => {
284
+ if ((nowTime - lastUpdateTime) > this._removeDevicesTimeMs) {
285
+ delete this._devicesState[deviceKey];
286
+ }
287
+ });
288
+ }
289
+ // Process the callback
290
+ this.processStateCallback();
291
+ }
292
+ ////////////////////////////////////////////////////////////////////////////
293
+ // Handle device message JSON
294
+ ////////////////////////////////////////////////////////////////////////////
295
+ async handleClientMsgJson(jsonMsg) {
296
+ const data = JSON.parse(jsonMsg);
297
+ // console.log(`DeviceManager client msg ${JSON.stringify(data)}`);
298
+ // Iterate over the buses
299
+ Object.entries(data).forEach(([busName, devices]) => {
300
+ // Check for bus status info
301
+ if (devices && typeof devices === "object" && "_s" in devices) {
302
+ // console.log(`DeviceManager bus status ${JSON.stringify(devices._s)}`);
303
+ return;
304
+ }
305
+ // Iterate over the devices
306
+ Object.entries(devices).forEach(async ([devAddr, attrGroups]) => {
307
+ // Check for non-device info (starts with _)
308
+ if (devAddr.startsWith("_")) {
309
+ return;
310
+ }
311
+ // Device type name
312
+ let deviceTypeName = "";
313
+ let deviceTypeIdx = -1;
314
+ if (attrGroups && typeof attrGroups === 'object' && "_t" in attrGroups && typeof attrGroups._t === "string") {
315
+ deviceTypeName = attrGroups._t || "";
316
+ }
317
+ else if (attrGroups && typeof attrGroups === 'object' && "_i" in attrGroups && typeof attrGroups._i === "number") {
318
+ deviceTypeIdx = attrGroups._i || -1;
319
+ deviceTypeName = deviceTypeIdx.toString();
320
+ }
321
+ else {
322
+ console.warn(`DeviceManager missing device type attrGroups ${JSON.stringify(attrGroups)}`);
323
+ return;
324
+ }
325
+ // Device key
326
+ const deviceKey = (0, RaftDeviceStates_1.getDeviceKey)(busName, devAddr);
327
+ // Update the last update time
328
+ this._deviceLastUpdateTime[deviceKey] = Date.now();
329
+ // Check if a device state already exists
330
+ if (!(deviceKey in this._devicesState) || (this._devicesState[deviceKey].deviceTypeInfo === undefined)) {
331
+ // Get the device type info
332
+ const deviceTypeInfo = await this.getDeviceTypeInfo(busName, deviceTypeName);
333
+ // Check if device record exists
334
+ if (deviceKey in this._devicesState) {
335
+ if (deviceTypeInfo !== undefined) {
336
+ this._devicesState[deviceKey].deviceTypeInfo = deviceTypeInfo;
337
+ this._devicesState[deviceKey].deviceType = deviceTypeName;
338
+ this._devicesState[deviceKey].deviceAddress = devAddr;
339
+ this._devicesState[deviceKey].busName = busName;
340
+ }
341
+ }
342
+ else {
343
+ // Create device record - device type info may be undefined
344
+ this._devicesState[deviceKey] = {
345
+ deviceTypeInfo: deviceTypeInfo,
346
+ deviceTimeline: {
347
+ timestampsUs: [],
348
+ lastReportTimestampUs: 0,
349
+ reportTimestampOffsetUs: 0
350
+ },
351
+ deviceAttributes: {},
352
+ deviceIsNew: true,
353
+ stateChanged: false,
354
+ isOnline: true,
355
+ deviceAddress: devAddr,
356
+ deviceType: deviceTypeName,
357
+ busName: busName
358
+ };
359
+ }
360
+ }
361
+ // Get device state
362
+ const deviceState = this._devicesState[deviceKey];
363
+ // Check for online/offline state information
364
+ if (attrGroups && typeof attrGroups === "object" && "_o" in attrGroups) {
365
+ deviceState.isOnline = ((attrGroups._o === true) || (attrGroups._o === "1") || (attrGroups._o === 1));
366
+ }
367
+ // Check if device type info is available
368
+ if (!deviceState.deviceTypeInfo) {
369
+ return;
370
+ }
371
+ const markers = this.extractMarkers(attrGroups);
372
+ // Iterate attribute groups
373
+ Object.entries(attrGroups).forEach(([attrGroupName, msgHexStr]) => {
374
+ // Check valid
375
+ if (attrGroupName.startsWith("_") || (typeof msgHexStr != 'string')) {
376
+ return;
377
+ }
378
+ // Check the device type info
379
+ if (!deviceState.deviceTypeInfo.resp) {
380
+ return;
381
+ }
382
+ // Convert the hex string to an arraybuffer by converting each pair of hex chars to a byte
383
+ const msgBytes = this.hexToBytes(msgHexStr);
384
+ // Work through the message which may contain multiple data instances
385
+ let msgBufIdx = 0;
386
+ // Iterate over attributes in the group
387
+ const pollRespMetadata = deviceState.deviceTypeInfo.resp;
388
+ const attrLengthsBefore = this.snapshotAttrLengths(deviceState.deviceAttributes, pollRespMetadata);
389
+ const timelineLenBefore = deviceState.deviceTimeline.timestampsUs.length;
390
+ // Loop
391
+ while (msgBufIdx < msgBytes.length) {
392
+ const newMsgBufIdx = this._attributeHandler.processMsgAttrGroup(msgBytes, msgBufIdx, deviceState.deviceTimeline, pollRespMetadata, deviceState.deviceAttributes, this._maxDatapointsToStore);
393
+ if (newMsgBufIdx < 0)
394
+ break;
395
+ msgBufIdx = newMsgBufIdx;
396
+ deviceState.stateChanged = true;
397
+ }
398
+ this.emitDecodedData(deviceKey, busName, devAddr, deviceState, pollRespMetadata, attrLengthsBefore, timelineLenBefore, attrGroupName, markers);
399
+ });
400
+ });
401
+ });
402
+ // Check for devices that have not been updated for a while
403
+ if (this._removeDevicesFlag) {
404
+ const nowTime = Date.now();
405
+ Object.entries(this._deviceLastUpdateTime).forEach(([deviceKey, lastUpdateTime]) => {
406
+ if ((nowTime - lastUpdateTime) > this._removeDevicesTimeMs) {
407
+ delete this._devicesState[deviceKey];
408
+ }
409
+ });
410
+ }
411
+ // Process the callback
412
+ this.processStateCallback();
413
+ }
414
+ ////////////////////////////////////////////////////////////////////////////
415
+ // Process state change callback
416
+ ////////////////////////////////////////////////////////////////////////////
417
+ processStateCallback() {
418
+ // Iterate over the devices
419
+ Object.entries(this._devicesState).forEach(([deviceKey, deviceState]) => {
420
+ // Check if device record is new
421
+ if (deviceState.deviceIsNew) {
422
+ this._newDeviceCallbacks.forEach((cb) => cb(deviceKey, deviceState));
423
+ deviceState.deviceIsNew = false;
424
+ }
425
+ // Iterate over the attributes
426
+ Object.entries(deviceState.deviceAttributes).forEach(([, attrState]) => {
427
+ if (attrState.newAttribute) {
428
+ this._newDeviceAttributeCallbacks.forEach((cb) => cb(deviceKey, attrState));
429
+ attrState.newAttribute = false;
430
+ }
431
+ if (attrState.newData) {
432
+ this._newAttributeDataCallbacks.forEach((cb) => cb(deviceKey, attrState));
433
+ attrState.newData = false;
434
+ }
435
+ });
436
+ });
437
+ }
438
+ ////////////////////////////////////////////////////////////////////////////
439
+ // Get device type info
440
+ ////////////////////////////////////////////////////////////////////////////
441
+ async getDeviceTypeInfo(busName, deviceType) {
442
+ // Check if already in cache
443
+ if (deviceType in this._cachedDeviceTypeRecs) {
444
+ return this._cachedDeviceTypeRecs[deviceType];
445
+ }
446
+ // Check if there's already a pending request for this device type
447
+ if (deviceType in this._pendingDeviceTypeRequests) {
448
+ // console.log(`DevMan.getDeviceTypeInfo joining existing request queue for deviceType ${deviceType}`);
449
+ // Add this request to the waiting queue
450
+ return new Promise((resolve, reject) => {
451
+ this._pendingDeviceTypeRequests[deviceType].waitingQueue.push({ resolve, reject });
452
+ });
453
+ }
454
+ // Check rate limiting for new requests
455
+ if (deviceType in this._cachedDeviceTypePreviousAttemptTimes) {
456
+ const timeSinceLastAttempt = Date.now() - this._cachedDeviceTypePreviousAttemptTimes[deviceType];
457
+ if (timeSinceLastAttempt < this._minTimeBetweenDeviceTypeInfoRetrievalMs) {
458
+ console.log(`DevMan.getDeviceTypeInfo rate limited for deviceType ${deviceType}`);
459
+ return undefined;
460
+ }
461
+ }
462
+ // Create and cache the promise with an empty waiting queue
463
+ const requestPromise = this.executeDeviceTypeInfoRequest(busName, deviceType);
464
+ this._pendingDeviceTypeRequests[deviceType] = {
465
+ promise: requestPromise,
466
+ waitingQueue: []
467
+ };
468
+ try {
469
+ const result = await requestPromise;
470
+ // Resolve all waiting requests with the same result
471
+ const waitingQueue = this._pendingDeviceTypeRequests[deviceType].waitingQueue;
472
+ waitingQueue.forEach(({ resolve }) => resolve(result));
473
+ return result;
474
+ }
475
+ catch (error) {
476
+ // Reject all waiting requests with the same error
477
+ const waitingQueue = this._pendingDeviceTypeRequests[deviceType].waitingQueue;
478
+ waitingQueue.forEach(({ reject }) => reject(error));
479
+ console.warn(`DevMan.getDeviceTypeInfo failed for ${deviceType}: ${error}`);
480
+ return undefined;
481
+ }
482
+ finally {
483
+ // Clean up the pending request
484
+ delete this._pendingDeviceTypeRequests[deviceType];
485
+ }
486
+ }
487
+ async executeDeviceTypeInfoRequest(busName, deviceType) {
488
+ var _a;
489
+ this._cachedDeviceTypePreviousAttemptTimes[deviceType] = Date.now();
490
+ try {
491
+ const cmd = "devman/typeinfo?bus=" + busName + "&type=" + deviceType;
492
+ const msgHandler = (_a = this._systemUtils) === null || _a === void 0 ? void 0 : _a.getMsgHandler();
493
+ if (msgHandler) {
494
+ const msgRslt = await msgHandler.sendRICRESTURL(cmd);
495
+ if (msgRslt && msgRslt.rslt === "ok") {
496
+ this._cachedDeviceTypeRecs[deviceType] = msgRslt.devinfo;
497
+ return msgRslt.devinfo;
498
+ }
499
+ }
500
+ return undefined;
501
+ }
502
+ catch (error) {
503
+ console.warn(`DeviceManager getDeviceTypeInfo error ${error}`);
504
+ return undefined;
505
+ }
506
+ }
507
+ ////////////////////////////////////////////////////////////////////////////
508
+ // Send action to device
509
+ ////////////////////////////////////////////////////////////////////////////
510
+ toHex(data) {
511
+ return Array.from(data)
512
+ .map(byte => byte.toString(16).padStart(2, "0"))
513
+ .join("");
514
+ }
515
+ async sendAction(deviceKey, action, data) {
516
+ // console.log(`DeviceManager sendAction ${deviceKey} action name ${action.n} value ${value} prefix ${action.w}`);
517
+ var _a;
518
+ let writeBytes;
519
+ // Check for one data item
520
+ if (data.length === 1) {
521
+ let value = data[0];
522
+ // Check for conversion
523
+ if (action.sub !== undefined) {
524
+ value = value - action.sub;
525
+ }
526
+ if (action.mul !== undefined) {
527
+ value = value * action.mul;
528
+ }
529
+ // Form the write bytes
530
+ writeBytes = action.t ? (0, RaftStruct_1.structPack)(action.t, [value]) : new Uint8Array(0);
531
+ }
532
+ else {
533
+ // Form the write bytes which may have multiple data items
534
+ writeBytes = action.t ? (0, RaftStruct_1.structPack)(action.t, data) : new Uint8Array(0);
535
+ }
536
+ // Convert to hex string
537
+ let writeHexStr = this.toHex(writeBytes);
538
+ // Add prefix and postfix
539
+ writeHexStr = (action.w ? action.w : "") + writeHexStr + (action.wz ? action.wz : "");
540
+ // Separate the bus and address in the deviceKey (_ char)
541
+ const devBus = deviceKey.split("_")[0];
542
+ const devAddr = deviceKey.split("_")[1];
543
+ // Send the action to the server
544
+ const cmd = "devman/cmdraw?bus=" + devBus + "&addr=" + devAddr + "&hexWr=" + writeHexStr;
545
+ console.log(`DeviceManager deviceKey ${deviceKey} action name ${action.n} value ${data} prefix ${action.w} sendAction ${cmd}`);
546
+ // Send the command
547
+ try {
548
+ // Get the msg handler
549
+ const msgHandler = (_a = this._systemUtils) === null || _a === void 0 ? void 0 : _a.getMsgHandler();
550
+ if (msgHandler) {
551
+ const msgRslt = await msgHandler.sendRICRESTURL(cmd);
552
+ return msgRslt.rslt === "ok";
553
+ }
554
+ return false;
555
+ }
556
+ catch (error) {
557
+ console.warn(`DeviceManager sendAction error ${error}`);
558
+ return false;
559
+ }
560
+ }
561
+ ////////////////////////////////////////////////////////////////////////////
562
+ // Send a compound action to the device
563
+ ////////////////////////////////////////////////////////////////////////////
564
+ async sendCompoundAction(deviceKey, action, data) {
565
+ // console.log(`DeviceManager sendAction ${deviceKey} action name ${action.n} value ${value} prefix ${action.w}`);
566
+ // Check if all data to be sent at once
567
+ if (action.concat) {
568
+ // Form a single list by flattening data
569
+ let dataToWrite = [];
570
+ for (let dataIdx = 0; dataIdx < data.length; dataIdx++) {
571
+ dataToWrite = dataToWrite.concat(data[dataIdx]);
572
+ }
573
+ // Use sendAction to send this
574
+ return await this.sendAction(deviceKey, action, dataToWrite);
575
+ }
576
+ else {
577
+ // Iterate over the data
578
+ let allOk = true;
579
+ for (let dataIdx = 0; dataIdx < data.length; dataIdx++) {
580
+ // Create the data to write by prepending the index to the data for this index
581
+ const dataToWrite = [dataIdx].concat(data[dataIdx]);
582
+ // Use sendAction to send this
583
+ allOk = allOk && await this.sendAction(deviceKey, action, dataToWrite);
584
+ }
585
+ }
586
+ return false;
587
+ }
588
+ ////////////////////////////////////////////////////////////////////////////
589
+ // Convert hex to bytes
590
+ ////////////////////////////////////////////////////////////////////////////
591
+ hexToBytes(hex) {
592
+ const bytes = new Uint8Array(hex.length / 2);
593
+ for (let i = 0; i < bytes.length; i++) {
594
+ bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
595
+ }
596
+ return bytes;
597
+ }
598
+ ////////////////////////////////////////////////////////////////////////////
599
+ // Helpers for decoded data callbacks
600
+ ////////////////////////////////////////////////////////////////////////////
601
+ snapshotAttrLengths(deviceAttrs, pollRespMetadata) {
602
+ const lengths = {};
603
+ if (!pollRespMetadata) {
604
+ return lengths;
605
+ }
606
+ pollRespMetadata.a.forEach((attr) => {
607
+ var _a;
608
+ lengths[attr.n] = ((_a = deviceAttrs[attr.n]) === null || _a === void 0 ? void 0 : _a.values.length) || 0;
609
+ });
610
+ return lengths;
611
+ }
612
+ emitDecodedData(deviceKey, busName, devAddr, deviceState, pollRespMetadata, attrLengthsBefore, timelineLenBefore, attrGroupName = "", markers) {
613
+ if (!pollRespMetadata) {
614
+ return;
615
+ }
616
+ const attrValues = {};
617
+ let hasValues = false;
618
+ pollRespMetadata.a.forEach((attr) => {
619
+ const attrState = deviceState.deviceAttributes[attr.n];
620
+ if (!attrState) {
621
+ return;
622
+ }
623
+ const prevLen = attrLengthsBefore[attr.n] || 0;
624
+ if (attrState.values.length > prevLen) {
625
+ attrValues[attr.n] = attrState.values.slice(prevLen);
626
+ hasValues = hasValues || attrValues[attr.n].length > 0;
627
+ }
628
+ });
629
+ if (!hasValues) {
630
+ return;
631
+ }
632
+ const timestampsUs = deviceState.deviceTimeline.timestampsUs.slice(timelineLenBefore);
633
+ const decoded = {
634
+ deviceKey,
635
+ busName,
636
+ deviceAddress: devAddr,
637
+ deviceType: deviceState.deviceType,
638
+ attrGroupName: attrGroupName || undefined,
639
+ attrValues,
640
+ timestampsUs,
641
+ };
642
+ if (markers && Object.keys(markers).length > 0) {
643
+ decoded.markers = markers;
644
+ decoded.fromOfflineBuffer = this.isTruthy(markers["_buf"]);
645
+ }
646
+ this._decodedDataCallbacks.forEach((cb) => cb(decoded));
647
+ }
648
+ extractMarkers(attrGroups) {
649
+ const markers = {};
650
+ if (!attrGroups || typeof attrGroups !== "object") {
651
+ return markers;
652
+ }
653
+ Object.entries(attrGroups).forEach(([key, value]) => {
654
+ if (key.startsWith("_") && key !== "_t" && key !== "_o") {
655
+ markers[key] = value;
656
+ }
657
+ });
658
+ return markers;
659
+ }
660
+ isTruthy(val) {
661
+ return val === true || val === 1 || val === "1";
662
+ }
663
+ }
664
+ exports.DeviceManager = DeviceManager;
665
+ //# sourceMappingURL=RaftDeviceManager.js.map