@hangtime/grip-connect 0.8.6 → 0.8.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 (229) hide show
  1. package/dist/cjs/index.d.ts +3 -0
  2. package/dist/cjs/index.d.ts.map +1 -0
  3. package/dist/cjs/index.js +14 -0
  4. package/dist/cjs/index.js.map +1 -0
  5. package/dist/cjs/interfaces/base.interface.d.ts +18 -0
  6. package/dist/cjs/interfaces/base.interface.d.ts.map +1 -0
  7. package/dist/cjs/interfaces/base.interface.js +3 -0
  8. package/dist/cjs/interfaces/base.interface.js.map +1 -0
  9. package/dist/cjs/interfaces/callback.interface.d.ts +56 -0
  10. package/dist/cjs/interfaces/callback.interface.d.ts.map +1 -0
  11. package/dist/cjs/interfaces/callback.interface.js +3 -0
  12. package/dist/cjs/interfaces/callback.interface.js.map +1 -0
  13. package/dist/cjs/interfaces/command.interface.d.ts +92 -0
  14. package/dist/cjs/interfaces/command.interface.d.ts.map +1 -0
  15. package/dist/cjs/interfaces/command.interface.js +3 -0
  16. package/dist/cjs/interfaces/command.interface.js.map +1 -0
  17. package/dist/cjs/interfaces/device/climbro.interface.d.ts +7 -0
  18. package/dist/cjs/interfaces/device/climbro.interface.d.ts.map +1 -0
  19. package/dist/cjs/interfaces/device/climbro.interface.js +3 -0
  20. package/dist/cjs/interfaces/device/climbro.interface.js.map +1 -0
  21. package/dist/cjs/interfaces/device/entralpi.interface.d.ts +53 -0
  22. package/dist/cjs/interfaces/device/entralpi.interface.d.ts.map +1 -0
  23. package/dist/cjs/interfaces/device/entralpi.interface.js +3 -0
  24. package/dist/cjs/interfaces/device/entralpi.interface.js.map +1 -0
  25. package/dist/cjs/interfaces/device/forceboard.interface.d.ts +64 -0
  26. package/dist/cjs/interfaces/device/forceboard.interface.d.ts.map +1 -0
  27. package/dist/cjs/interfaces/device/forceboard.interface.js +3 -0
  28. package/dist/cjs/interfaces/device/forceboard.interface.js.map +1 -0
  29. package/dist/cjs/interfaces/device/kilterboard.interface.d.ts +16 -0
  30. package/dist/cjs/interfaces/device/kilterboard.interface.d.ts.map +1 -0
  31. package/dist/cjs/interfaces/device/kilterboard.interface.js +3 -0
  32. package/dist/cjs/interfaces/device/kilterboard.interface.js.map +1 -0
  33. package/dist/cjs/interfaces/device/motherboard.interface.d.ts +54 -0
  34. package/dist/cjs/interfaces/device/motherboard.interface.d.ts.map +1 -0
  35. package/dist/cjs/interfaces/device/motherboard.interface.js +3 -0
  36. package/dist/cjs/interfaces/device/motherboard.interface.js.map +1 -0
  37. package/dist/cjs/interfaces/device/mysmartboard.interface.d.ts +7 -0
  38. package/dist/cjs/interfaces/device/mysmartboard.interface.d.ts.map +1 -0
  39. package/dist/cjs/interfaces/device/mysmartboard.interface.js +3 -0
  40. package/dist/cjs/interfaces/device/mysmartboard.interface.js.map +1 -0
  41. package/dist/cjs/interfaces/device/progressor.interface.d.ts +28 -0
  42. package/dist/cjs/interfaces/device/progressor.interface.d.ts.map +1 -0
  43. package/dist/cjs/interfaces/device/progressor.interface.js +3 -0
  44. package/dist/cjs/interfaces/device/progressor.interface.js.map +1 -0
  45. package/dist/cjs/interfaces/device/smartboard-pro.interface.d.ts +7 -0
  46. package/dist/cjs/interfaces/device/smartboard-pro.interface.d.ts.map +1 -0
  47. package/dist/cjs/interfaces/device/smartboard-pro.interface.js +3 -0
  48. package/dist/cjs/interfaces/device/smartboard-pro.interface.js.map +1 -0
  49. package/dist/cjs/interfaces/device/wh-c06.interface.d.ts +7 -0
  50. package/dist/cjs/interfaces/device/wh-c06.interface.d.ts.map +1 -0
  51. package/dist/cjs/interfaces/device/wh-c06.interface.js +3 -0
  52. package/dist/cjs/interfaces/device/wh-c06.interface.js.map +1 -0
  53. package/dist/cjs/interfaces/device.interface.d.ts +203 -0
  54. package/dist/cjs/interfaces/device.interface.d.ts.map +1 -0
  55. package/dist/cjs/interfaces/device.interface.js +3 -0
  56. package/dist/cjs/interfaces/device.interface.js.map +1 -0
  57. package/dist/cjs/interfaces/download.interface.d.ts +16 -0
  58. package/dist/cjs/interfaces/download.interface.d.ts.map +1 -0
  59. package/dist/cjs/interfaces/download.interface.js +3 -0
  60. package/dist/cjs/interfaces/download.interface.js.map +1 -0
  61. package/dist/cjs/interfaces/index.d.ts +10 -0
  62. package/dist/cjs/interfaces/index.d.ts.map +1 -0
  63. package/dist/cjs/interfaces/index.js +3 -0
  64. package/dist/cjs/interfaces/index.js.map +1 -0
  65. package/dist/cjs/models/base.model.d.ts +13 -0
  66. package/dist/cjs/models/base.model.d.ts.map +1 -0
  67. package/dist/cjs/models/base.model.js +24 -0
  68. package/dist/cjs/models/base.model.js.map +1 -0
  69. package/dist/cjs/models/device/climbro.model.d.ts +11 -0
  70. package/dist/cjs/models/device/climbro.model.d.ts.map +1 -0
  71. package/dist/cjs/models/device/climbro.model.js +19 -0
  72. package/dist/cjs/models/device/climbro.model.js.map +1 -0
  73. package/dist/cjs/models/device/entralpi.model.d.ts +64 -0
  74. package/dist/cjs/models/device/entralpi.model.d.ts.map +1 -0
  75. package/dist/cjs/models/device/entralpi.model.js +244 -0
  76. package/dist/cjs/models/device/entralpi.model.js.map +1 -0
  77. package/dist/cjs/models/device/forceboard.model.d.ts +73 -0
  78. package/dist/cjs/models/device/forceboard.model.d.ts.map +1 -0
  79. package/dist/cjs/models/device/forceboard.model.js +316 -0
  80. package/dist/cjs/models/device/forceboard.model.js.map +1 -0
  81. package/dist/cjs/models/device/kilterboard.model.d.ts +144 -0
  82. package/dist/cjs/models/device/kilterboard.model.d.ts.map +1 -0
  83. package/dist/cjs/models/device/kilterboard.model.js +291 -0
  84. package/dist/cjs/models/device/kilterboard.model.js.map +1 -0
  85. package/dist/cjs/models/device/motherboard.model.d.ts +110 -0
  86. package/dist/cjs/models/device/motherboard.model.d.ts.map +1 -0
  87. package/dist/cjs/models/device/motherboard.model.js +382 -0
  88. package/dist/cjs/models/device/motherboard.model.js.map +1 -0
  89. package/dist/cjs/models/device/mysmartboard.model.d.ts +11 -0
  90. package/dist/cjs/models/device/mysmartboard.model.d.ts.map +1 -0
  91. package/dist/cjs/models/device/mysmartboard.model.js +19 -0
  92. package/dist/cjs/models/device/mysmartboard.model.js.map +1 -0
  93. package/dist/cjs/models/device/progressor.model.d.ts +39 -0
  94. package/dist/cjs/models/device/progressor.model.d.ts.map +1 -0
  95. package/dist/cjs/models/device/progressor.model.js +220 -0
  96. package/dist/cjs/models/device/progressor.model.js.map +1 -0
  97. package/dist/cjs/models/device/smartboard-pro.model.d.ts +11 -0
  98. package/dist/cjs/models/device/smartboard-pro.model.d.ts.map +1 -0
  99. package/dist/cjs/models/device/smartboard-pro.model.js +56 -0
  100. package/dist/cjs/models/device/smartboard-pro.model.js.map +1 -0
  101. package/dist/cjs/models/device/wh-c06.model.d.ts +57 -0
  102. package/dist/cjs/models/device/wh-c06.model.d.ts.map +1 -0
  103. package/dist/cjs/models/device/wh-c06.model.js +171 -0
  104. package/dist/cjs/models/device/wh-c06.model.js.map +1 -0
  105. package/dist/cjs/models/device.model.d.ts +408 -0
  106. package/dist/cjs/models/device.model.d.ts.map +1 -0
  107. package/dist/cjs/models/device.model.js +665 -0
  108. package/dist/cjs/models/device.model.js.map +1 -0
  109. package/dist/cjs/models/index.d.ts +10 -0
  110. package/dist/cjs/models/index.d.ts.map +1 -0
  111. package/dist/cjs/models/index.js +22 -0
  112. package/dist/cjs/models/index.js.map +1 -0
  113. package/dist/index.d.ts +3 -0
  114. package/dist/index.d.ts.map +1 -0
  115. package/dist/index.js +2 -0
  116. package/dist/index.js.map +1 -0
  117. package/dist/interfaces/base.interface.d.ts +18 -0
  118. package/dist/interfaces/base.interface.d.ts.map +1 -0
  119. package/dist/interfaces/base.interface.js +2 -0
  120. package/dist/interfaces/base.interface.js.map +1 -0
  121. package/dist/interfaces/callback.interface.d.ts +56 -0
  122. package/dist/interfaces/callback.interface.d.ts.map +1 -0
  123. package/dist/interfaces/callback.interface.js +2 -0
  124. package/dist/interfaces/callback.interface.js.map +1 -0
  125. package/dist/interfaces/command.interface.d.ts +92 -0
  126. package/dist/interfaces/command.interface.d.ts.map +1 -0
  127. package/dist/interfaces/command.interface.js +2 -0
  128. package/dist/interfaces/command.interface.js.map +1 -0
  129. package/dist/interfaces/device/climbro.interface.d.ts +7 -0
  130. package/dist/interfaces/device/climbro.interface.d.ts.map +1 -0
  131. package/dist/interfaces/device/climbro.interface.js +2 -0
  132. package/dist/interfaces/device/climbro.interface.js.map +1 -0
  133. package/dist/interfaces/device/entralpi.interface.d.ts +53 -0
  134. package/dist/interfaces/device/entralpi.interface.d.ts.map +1 -0
  135. package/dist/interfaces/device/entralpi.interface.js +2 -0
  136. package/dist/interfaces/device/entralpi.interface.js.map +1 -0
  137. package/dist/interfaces/device/forceboard.interface.d.ts +64 -0
  138. package/dist/interfaces/device/forceboard.interface.d.ts.map +1 -0
  139. package/dist/interfaces/device/forceboard.interface.js +2 -0
  140. package/dist/interfaces/device/forceboard.interface.js.map +1 -0
  141. package/dist/interfaces/device/kilterboard.interface.d.ts +16 -0
  142. package/dist/interfaces/device/kilterboard.interface.d.ts.map +1 -0
  143. package/dist/interfaces/device/kilterboard.interface.js +2 -0
  144. package/dist/interfaces/device/kilterboard.interface.js.map +1 -0
  145. package/dist/interfaces/device/motherboard.interface.d.ts +54 -0
  146. package/dist/interfaces/device/motherboard.interface.d.ts.map +1 -0
  147. package/dist/interfaces/device/motherboard.interface.js +2 -0
  148. package/dist/interfaces/device/motherboard.interface.js.map +1 -0
  149. package/dist/interfaces/device/mysmartboard.interface.d.ts +7 -0
  150. package/dist/interfaces/device/mysmartboard.interface.d.ts.map +1 -0
  151. package/dist/interfaces/device/mysmartboard.interface.js +2 -0
  152. package/dist/interfaces/device/mysmartboard.interface.js.map +1 -0
  153. package/dist/interfaces/device/progressor.interface.d.ts +28 -0
  154. package/dist/interfaces/device/progressor.interface.d.ts.map +1 -0
  155. package/dist/interfaces/device/progressor.interface.js +2 -0
  156. package/dist/interfaces/device/progressor.interface.js.map +1 -0
  157. package/dist/interfaces/device/smartboard-pro.interface.d.ts +7 -0
  158. package/dist/interfaces/device/smartboard-pro.interface.d.ts.map +1 -0
  159. package/dist/interfaces/device/smartboard-pro.interface.js +2 -0
  160. package/dist/interfaces/device/smartboard-pro.interface.js.map +1 -0
  161. package/dist/interfaces/device/wh-c06.interface.d.ts +7 -0
  162. package/dist/interfaces/device/wh-c06.interface.d.ts.map +1 -0
  163. package/dist/interfaces/device/wh-c06.interface.js +2 -0
  164. package/dist/interfaces/device/wh-c06.interface.js.map +1 -0
  165. package/dist/interfaces/device.interface.d.ts +203 -0
  166. package/dist/interfaces/device.interface.d.ts.map +1 -0
  167. package/dist/interfaces/device.interface.js +2 -0
  168. package/dist/interfaces/device.interface.js.map +1 -0
  169. package/dist/interfaces/download.interface.d.ts +16 -0
  170. package/dist/interfaces/download.interface.d.ts.map +1 -0
  171. package/dist/interfaces/download.interface.js +2 -0
  172. package/dist/interfaces/download.interface.js.map +1 -0
  173. package/dist/interfaces/index.d.ts +10 -0
  174. package/dist/interfaces/index.d.ts.map +1 -0
  175. package/dist/interfaces/index.js +2 -0
  176. package/dist/interfaces/index.js.map +1 -0
  177. package/dist/models/base.model.d.ts +13 -0
  178. package/dist/models/base.model.d.ts.map +1 -0
  179. package/dist/models/base.model.js +22 -0
  180. package/dist/models/base.model.js.map +1 -0
  181. package/dist/models/device/climbro.model.d.ts +11 -0
  182. package/dist/models/device/climbro.model.d.ts.map +1 -0
  183. package/dist/models/device/climbro.model.js +15 -0
  184. package/dist/models/device/climbro.model.js.map +1 -0
  185. package/dist/models/device/entralpi.model.d.ts +64 -0
  186. package/dist/models/device/entralpi.model.d.ts.map +1 -0
  187. package/dist/models/device/entralpi.model.js +240 -0
  188. package/dist/models/device/entralpi.model.js.map +1 -0
  189. package/dist/models/device/forceboard.model.d.ts +73 -0
  190. package/dist/models/device/forceboard.model.d.ts.map +1 -0
  191. package/dist/models/device/forceboard.model.js +312 -0
  192. package/dist/models/device/forceboard.model.js.map +1 -0
  193. package/dist/models/device/kilterboard.model.d.ts +144 -0
  194. package/dist/models/device/kilterboard.model.d.ts.map +1 -0
  195. package/dist/models/device/kilterboard.model.js +287 -0
  196. package/dist/models/device/kilterboard.model.js.map +1 -0
  197. package/dist/models/device/motherboard.model.d.ts +110 -0
  198. package/dist/models/device/motherboard.model.d.ts.map +1 -0
  199. package/dist/models/device/motherboard.model.js +378 -0
  200. package/dist/models/device/motherboard.model.js.map +1 -0
  201. package/dist/models/device/mysmartboard.model.d.ts +11 -0
  202. package/dist/models/device/mysmartboard.model.d.ts.map +1 -0
  203. package/dist/models/device/mysmartboard.model.js +15 -0
  204. package/dist/models/device/mysmartboard.model.js.map +1 -0
  205. package/dist/models/device/progressor.model.d.ts +39 -0
  206. package/dist/models/device/progressor.model.d.ts.map +1 -0
  207. package/dist/models/device/progressor.model.js +216 -0
  208. package/dist/models/device/progressor.model.js.map +1 -0
  209. package/dist/models/device/smartboard-pro.model.d.ts +11 -0
  210. package/dist/models/device/smartboard-pro.model.d.ts.map +1 -0
  211. package/dist/models/device/smartboard-pro.model.js +52 -0
  212. package/dist/models/device/smartboard-pro.model.js.map +1 -0
  213. package/dist/models/device/wh-c06.model.d.ts +57 -0
  214. package/dist/models/device/wh-c06.model.d.ts.map +1 -0
  215. package/dist/models/device/wh-c06.model.js +167 -0
  216. package/dist/models/device/wh-c06.model.js.map +1 -0
  217. package/dist/models/device.model.d.ts +408 -0
  218. package/dist/models/device.model.d.ts.map +1 -0
  219. package/dist/models/device.model.js +720 -0
  220. package/dist/models/device.model.js.map +1 -0
  221. package/dist/models/index.d.ts +10 -0
  222. package/dist/models/index.d.ts.map +1 -0
  223. package/dist/models/index.js +10 -0
  224. package/dist/models/index.js.map +1 -0
  225. package/dist/tsconfig.cjs.tsbuildinfo +1 -0
  226. package/package.json +5 -1
  227. package/deno.json +0 -8
  228. package/tsconfig.cjs.json +0 -15
  229. package/tsconfig.json +0 -13
@@ -0,0 +1,720 @@
1
+ import { BaseModel } from "./../models/base.model.js";
2
+ export class Device extends BaseModel {
3
+ /**
4
+ * Filters to identify the device during Bluetooth scanning.
5
+ * Used to match devices that meet specific criteria such as name, service UUIDs, etc.
6
+ * @type {BluetoothLEScanFilter[]}
7
+ * @public
8
+ * @readonly
9
+ */
10
+ filters;
11
+ /**
12
+ * Array of services provided by the device.
13
+ * Services represent functionalities that the device supports, such as weight measurement, battery information, or custom services.
14
+ * @type {Service[]}
15
+ * @public
16
+ * @readonly
17
+ */
18
+ services;
19
+ /**
20
+ * Reference to the `BluetoothDevice` object representing this device.
21
+ * This is the actual device object obtained from the Web Bluetooth API after a successful connection.
22
+ * @type {BluetoothDevice | undefined}
23
+ * @public
24
+ */
25
+ bluetooth;
26
+ /**
27
+ * Object representing the set of commands available for this device.
28
+ * These commands allow communication with the device to perform various operations such as starting measurements, retrieving data, or calibrating the device.
29
+ * @type {Commands}
30
+ * @public
31
+ * @readonly
32
+ */
33
+ commands;
34
+ /**
35
+ * The BluetoothRemoteGATTServer interface of the Web Bluetooth API represents a GATT Server on a remote device.
36
+ * @type {BluetoothRemoteGATTServer | undefined}
37
+ * @private
38
+ */
39
+ server;
40
+ /**
41
+ * The last message written to the device.
42
+ * @type {string | Uint8Array | null}
43
+ * @protected
44
+ */
45
+ writeLast = null;
46
+ /**
47
+ * Indicates whether the device is currently active.
48
+ * @type {boolean}
49
+ */
50
+ isActive = false;
51
+ /**
52
+ * Configuration for threshold and duration.
53
+ */
54
+ activeConfig = {
55
+ threshold: 2.5,
56
+ duration: 1000,
57
+ };
58
+ /**
59
+ * Maximum mass recorded from the device, initialized to "0".
60
+ * @type {string}
61
+ * @protected
62
+ */
63
+ massMax;
64
+ /**
65
+ * Average mass calculated from the device data, initialized to "0".
66
+ * @type {string}
67
+ * @protected
68
+ */
69
+ massAverage;
70
+ /**
71
+ * Total sum of all mass data points recorded from the device.
72
+ * Used to calculate the average mass.
73
+ * @type {number}
74
+ * @protected
75
+ */
76
+ massTotalSum;
77
+ /**
78
+ * Number of data points received from the device.
79
+ * Used to calculate the average mass.
80
+ * @type {number}
81
+ * @protected
82
+ */
83
+ dataPointCount;
84
+ /**
85
+ * Array of DownloadPacket entries.
86
+ * This array holds packets that contain data downloaded from the device.
87
+ * @type {DownloadPacket[]}
88
+ * @protected
89
+ */
90
+ downloadPackets = []; // Initialize an empty array of DownloadPacket entries
91
+ /**
92
+ * Represents the current tare value for calibration.
93
+ * @type {number}
94
+ */
95
+ tareCurrent = 0;
96
+ /**
97
+ * Indicates whether the tare calibration process is active.
98
+ * @type {boolean}
99
+ */
100
+ tareActive = false;
101
+ /**
102
+ * Timestamp when the tare calibration process started.
103
+ * @type {number | null}
104
+ */
105
+ tareStartTime = null;
106
+ /**
107
+ * Array holding the samples collected during tare calibration.
108
+ * @type {number[]}
109
+ */
110
+ tareSamples = [];
111
+ /**
112
+ * Duration time for the tare calibration process.
113
+ * @type {number}
114
+ */
115
+ tareDuration = 5000;
116
+ /**
117
+ * Optional callback for handling write operations.
118
+ * @callback NotifyCallback
119
+ * @param {massObject} data - The data passed to the callback.
120
+ * @type {NotifyCallback | undefined}
121
+ * @protected
122
+ */
123
+ notifyCallback = (data) => console.log(data);
124
+ /**
125
+ * Optional callback for handling write operations.
126
+ * @callback WriteCallback
127
+ * @param {string} data - The data passed to the callback.
128
+ * @type {WriteCallback | undefined}
129
+ * @protected
130
+ */
131
+ writeCallback = (data) => console.log(data);
132
+ /**
133
+ * Optional callback for handling write operations.
134
+ * @callback ActiveCallback
135
+ * @param {string} data - The data passed to the callback.
136
+ * @type {ActiveCallback | undefined}
137
+ * @protected
138
+ */
139
+ activeCallback = (data) => console.log(data);
140
+ /**
141
+ * Event listener for handling the 'gattserverdisconnected' event.
142
+ * This listener delegates the event to the `onDisconnected` method.
143
+ *
144
+ * @private
145
+ * @type {(event: Event) => void}
146
+ */
147
+ onDisconnectedListener = (event) => this.onDisconnected(event);
148
+ /**
149
+ * A map that stores notification event listeners keyed by characteristic UUIDs.
150
+ * This allows for proper addition and removal of event listeners associated with each characteristic.
151
+ *
152
+ * @private
153
+ * @type {Map<string, EventListener>}
154
+ */
155
+ notificationListeners = new Map();
156
+ constructor(device) {
157
+ super(device);
158
+ this.filters = device.filters || [];
159
+ this.services = device.services || [];
160
+ this.commands = device.commands || {};
161
+ if (device.bluetooth !== undefined) {
162
+ this.bluetooth = device.bluetooth;
163
+ }
164
+ this.massMax = "0";
165
+ this.massAverage = "0";
166
+ this.massTotalSum = 0;
167
+ this.dataPointCount = 0;
168
+ this.createdAt = new Date();
169
+ this.updatedAt = new Date();
170
+ }
171
+ /**
172
+ * Sets the callback function to be called when the activity status changes,
173
+ * and optionally sets the configuration for threshold and duration.
174
+ *
175
+ * This function allows you to specify a callback that will be invoked whenever
176
+ * the activity status changes, indicating whether the device is currently active.
177
+ * It also allows optionally configuring the threshold and duration used to determine activity.
178
+ *
179
+ * @param {ActiveCallback} callback - The callback function to be set. This function
180
+ * receives a boolean value indicating the new activity status.
181
+ * @param {object} [options] - Optional configuration object containing the threshold and duration.
182
+ * @param {number} [options.threshold=2.5] - The threshold value for determining activity.
183
+ * @param {number} [options.duration=1000] - The duration (in milliseconds) to monitor the input for activity.
184
+ * @returns {void}
185
+ * @public
186
+ *
187
+ * @example
188
+ * device.active((isActive) => {
189
+ * console.log(`Device is ${isActive ? 'active' : 'inactive'}`);
190
+ * }, { threshold: 3.0, duration: 1500 });
191
+ */
192
+ active = (callback, options) => {
193
+ this.activeCallback = callback;
194
+ // Update the config values only if provided, otherwise use defaults
195
+ this.activeConfig = {
196
+ threshold: options?.threshold ?? this.activeConfig.threshold, // Use new threshold if provided, else use default
197
+ duration: options?.duration ?? this.activeConfig.duration, // Use new duration if provided, else use default
198
+ };
199
+ };
200
+ /**
201
+ * Checks if a dynamic value is active based on a threshold and duration.
202
+ *
203
+ * This function assesses whether a given dynamic value surpasses a specified threshold
204
+ * and remains active for a specified duration. If the activity status changes from
205
+ * the previous state, the callback function is called with the updated activity status.
206
+ *
207
+ * @param {number} input - The dynamic value to check for activity status.
208
+ * @returns {Promise<void>} A promise that resolves once the activity check is complete.
209
+ *
210
+ * @example
211
+ * await device.activityCheck(5.0);
212
+ */
213
+ activityCheck = async (input) => {
214
+ const startValue = input;
215
+ const { threshold, duration } = this.activeConfig;
216
+ // After waiting for `duration`, check if still active.
217
+ await new Promise((resolve) => setTimeout(resolve, duration));
218
+ const activeNow = startValue > threshold;
219
+ if (this.isActive !== activeNow) {
220
+ this.isActive = activeNow;
221
+ this.activeCallback?.(activeNow);
222
+ }
223
+ };
224
+ /**
225
+ * Connects to a Bluetooth device.
226
+ * @param {Function} [onSuccess] - Optional callback function to execute on successful connection. Default logs success.
227
+ * @param {Function} [onError] - Optional callback function to execute on error. Default logs the error.
228
+ * @public
229
+ *
230
+ * @example
231
+ * device.connect(
232
+ * () => console.log("Connected successfully"),
233
+ * (error) => console.error("Connection failed:", error)
234
+ * );
235
+ */
236
+ connect = async (onSuccess = () => console.log("Connected successfully"), onError = (error) => console.error(error)) => {
237
+ try {
238
+ // Request device and set up connection
239
+ const deviceServices = this.getAllServiceUUIDs();
240
+ const bluetooth = await this.getBluetooth();
241
+ this.bluetooth = await bluetooth.requestDevice({
242
+ filters: this.filters,
243
+ optionalServices: deviceServices,
244
+ });
245
+ if (!this.bluetooth.gatt) {
246
+ throw new Error("GATT is not available on this device");
247
+ }
248
+ this.bluetooth.addEventListener("gattserverdisconnected", this.onDisconnectedListener);
249
+ this.server = await this.bluetooth.gatt.connect();
250
+ if (this.server.connected) {
251
+ await this.onConnected(onSuccess);
252
+ }
253
+ }
254
+ catch (error) {
255
+ onError(error);
256
+ }
257
+ };
258
+ /**
259
+ * Disconnects the device if it is currently connected.
260
+ * - Removes all notification listeners from the device's characteristics.
261
+ * - Removes the 'gattserverdisconnected' event listener.
262
+ * - Attempts to gracefully disconnect the device's GATT server.
263
+ * - Resets relevant properties to their initial states.
264
+ * @returns {void}
265
+ * @public
266
+ *
267
+ * @example
268
+ * device.disconnect();
269
+ */
270
+ disconnect = () => {
271
+ if (this.isConnected()) {
272
+ this.updateTimestamp();
273
+ // Remove all notification listeners
274
+ this.services.forEach((service) => {
275
+ service.characteristics.forEach((char) => {
276
+ // Look for the "rx" characteristic that accepts notifications
277
+ if (char.characteristic && char.id === "rx") {
278
+ char.characteristic.stopNotifications();
279
+ const listener = this.notificationListeners.get(char.uuid);
280
+ if (listener) {
281
+ char.characteristic.removeEventListener("characteristicvaluechanged", listener);
282
+ this.notificationListeners.delete(char.uuid);
283
+ }
284
+ }
285
+ });
286
+ });
287
+ // Remove disconnect listener
288
+ this.bluetooth?.removeEventListener("gattserverdisconnected", this.onDisconnectedListener);
289
+ // Safely attempt to disconnect the device's GATT server, if available
290
+ this.bluetooth?.gatt?.disconnect();
291
+ // Reset properties
292
+ this.server = undefined;
293
+ this.writeLast = null;
294
+ this.isActive = false;
295
+ }
296
+ };
297
+ /**
298
+ * Converts the `downloadPackets` array into a CSV formatted string.
299
+ * @returns {string} A CSV string representation of the `downloadPackets` data, with each packet on a new line.
300
+ * @private
301
+ *
302
+ * @example
303
+ * const csvData = device.downloadToCSV();
304
+ * console.log(csvData);
305
+ */
306
+ downloadToCSV = () => {
307
+ const packets = [...this.downloadPackets];
308
+ if (packets.length === 0) {
309
+ return "";
310
+ }
311
+ return packets
312
+ .map((packet) => [
313
+ packet.received.toString(),
314
+ packet.sampleNum.toString(),
315
+ packet.battRaw.toString(),
316
+ ...packet.samples.map(String),
317
+ ...packet.masses.map(String),
318
+ ]
319
+ .map((v) => v.replace(/"/g, '""'))
320
+ .map((v) => `"${v}"`)
321
+ .join(","))
322
+ .join("\r\n");
323
+ };
324
+ /**
325
+ * Converts an array of DownloadPacket objects to a JSON string.
326
+ * @returns {string} JSON string representation of the data.
327
+ * @private
328
+ *
329
+ * @example
330
+ * const jsonData = device.downloadToJSON();
331
+ * console.log(jsonData);
332
+ */
333
+ downloadToJSON = () => {
334
+ // Pretty print JSON with 2-space indentation
335
+ return JSON.stringify(this.downloadPackets, null, 2);
336
+ };
337
+ /**
338
+ * Converts an array of DownloadPacket objects to an XML string.
339
+ * @returns {string} XML string representation of the data.
340
+ * @private
341
+ *
342
+ * @example
343
+ * const xmlData = device.downloadToXML();
344
+ * console.log(xmlData);
345
+ */
346
+ downloadToXML = () => {
347
+ const xmlPackets = this.downloadPackets
348
+ .map((packet) => {
349
+ const samples = packet.samples.map((sample) => `<sample>${sample}</sample>`).join("");
350
+ const masses = packet.masses.map((mass) => `<mass>${mass}</mass>`).join("");
351
+ return `
352
+ <packet>
353
+ <received>${packet.received}</received>
354
+ <sampleNum>${packet.sampleNum}</sampleNum>
355
+ <battRaw>${packet.battRaw}</battRaw>
356
+ <samples>${samples}</samples>
357
+ <masses>${masses}</masses>
358
+ </packet>
359
+ `;
360
+ })
361
+ .join("");
362
+ return `<DownloadPackets>${xmlPackets}</DownloadPackets>`;
363
+ };
364
+ /**
365
+ * Exports the data in the specified format (CSV, JSON, XML) with a filename format:
366
+ * 'data-export-YYYY-MM-DD-HH-MM-SS.{format}'.
367
+ *
368
+ * @param {('csv' | 'json' | 'xml')} [format='csv'] - The format in which to download the data.
369
+ * Defaults to 'csv'. Accepted values are 'csv', 'json', and 'xml'.
370
+ *
371
+ * @returns {Promise<void>} Resolves when the data has been downloaded/written
372
+ * @public
373
+ *
374
+ * @example
375
+ * await device.download('json');
376
+ */
377
+ download = async (format = "csv") => {
378
+ let content = "";
379
+ if (format === "csv") {
380
+ content = this.downloadToCSV();
381
+ }
382
+ else if (format === "json") {
383
+ content = this.downloadToJSON();
384
+ }
385
+ else if (format === "xml") {
386
+ content = this.downloadToXML();
387
+ }
388
+ const now = new Date();
389
+ // YYYY-MM-DD
390
+ const date = now.toISOString().split("T")[0];
391
+ // HH-MM-SS
392
+ const time = now.toTimeString().split(" ")[0].replace(/:/g, "-");
393
+ const fileName = `data-export-${date}-${time}.${format}`;
394
+ const mimeTypes = {
395
+ csv: "text/csv",
396
+ json: "application/json",
397
+ xml: "application/xml",
398
+ };
399
+ // Create a Blob object containing the data
400
+ const blob = new Blob([content], { type: mimeTypes[format] });
401
+ // Create a URL for the Blob
402
+ const url = globalThis.URL.createObjectURL(blob);
403
+ // Create a link element
404
+ const link = document.createElement("a");
405
+ // Set link attributes
406
+ link.href = url;
407
+ link.setAttribute("download", fileName);
408
+ // Append link to document body
409
+ document.body.appendChild(link);
410
+ // Programmatically click the link to trigger the download
411
+ link.click();
412
+ // Clean up: remove the link and revoke the URL
413
+ document.body.removeChild(link);
414
+ globalThis.URL.revokeObjectURL(url);
415
+ };
416
+ /**
417
+ * Returns UUIDs of all services associated with the device.
418
+ * @returns {string[]} Array of service UUIDs.
419
+ * @protected
420
+ *
421
+ * @example
422
+ * const serviceUUIDs = device.getAllServiceUUIDs();
423
+ * console.log(serviceUUIDs);
424
+ */
425
+ getAllServiceUUIDs = () => {
426
+ return this.services.filter((service) => service?.uuid).map((service) => service.uuid);
427
+ };
428
+ /**
429
+ * Returns the Bluetooth instance available for the current environment.
430
+ * In browsers, it returns the native Web Bluetooth API (i.e. `navigator.bluetooth`).
431
+ * In a Node, Bun, or Deno environment, it dynamically imports the `webbluetooth` package.
432
+ * {@link https://github.com/thegecko/webbluetooth}
433
+ *
434
+ * @returns {Promise<Bluetooth>} A promise that resolves to the Bluetooth instance.
435
+ * @throws {Error} If Web Bluetooth is not available in the current environment.
436
+ */
437
+ async getBluetooth() {
438
+ // If running in a browser with native Web Bluetooth support:
439
+ if (typeof navigator !== "undefined" && navigator.bluetooth) {
440
+ return navigator.bluetooth;
441
+ }
442
+ // If none of the above conditions are met, throw an error.
443
+ throw new Error("Bluetooth not available.");
444
+ }
445
+ /**
446
+ * Handles notifications received from a characteristic.
447
+ * @param {DataView} value - The notification event.
448
+ *
449
+ * @example
450
+ * device.handleNotifications(someCharacteristic);
451
+ */
452
+ handleNotifications = (value) => {
453
+ if (!value)
454
+ return;
455
+ this.updateTimestamp();
456
+ // Received notification data
457
+ console.log(value);
458
+ };
459
+ /**
460
+ * Checks if a Bluetooth device is connected.
461
+ * @returns {boolean} A boolean indicating whether the device is connected.
462
+ * @public
463
+ *
464
+ * @example
465
+ * if (device.isConnected()) {
466
+ * console.log('Device is connected');
467
+ * } else {
468
+ * console.log('Device is not connected');
469
+ * }
470
+ */
471
+ isConnected = () => {
472
+ // Check if the device is defined and available
473
+ if (!this.bluetooth) {
474
+ return false;
475
+ }
476
+ // Check if the device is connected
477
+ return !!this.bluetooth.gatt?.connected;
478
+ };
479
+ /**
480
+ * Sets the callback function to be called when notifications are received.
481
+ * @param {NotifyCallback} callback - The callback function to be set.
482
+ * @returns {void}
483
+ * @public
484
+ *
485
+ * @example
486
+ * device.notify((data) => {
487
+ * console.log('Received notification:', data);
488
+ * });
489
+ */
490
+ notify = (callback) => {
491
+ this.notifyCallback = callback;
492
+ };
493
+ /**
494
+ * Handles the 'connected' event.
495
+ * @param {Function} onSuccess - Callback function to execute on successful connection.
496
+ * @public
497
+ *
498
+ * @example
499
+ * device.onConnected(() => {
500
+ * console.log('Device connected successfully');
501
+ * });
502
+ */
503
+ onConnected = async (onSuccess) => {
504
+ this.updateTimestamp();
505
+ if (!this.server) {
506
+ throw new Error("GATT server is not available");
507
+ }
508
+ // Connect to GATT server and set up characteristics
509
+ const services = await this.server.getPrimaryServices();
510
+ if (!services || services.length === 0) {
511
+ throw new Error("No services found");
512
+ }
513
+ for (const service of services) {
514
+ const matchingService = this.services.find((boardService) => boardService.uuid === service.uuid);
515
+ if (matchingService) {
516
+ // Android bug: Add a small delay before getting characteristics
517
+ await new Promise((resolve) => setTimeout(resolve, 100));
518
+ const characteristics = await service.getCharacteristics();
519
+ for (const characteristic of matchingService.characteristics) {
520
+ const matchingCharacteristic = characteristics.find((char) => char.uuid === characteristic.uuid);
521
+ if (matchingCharacteristic) {
522
+ // Find the corresponding characteristic descriptor in the service's characteristics array
523
+ const descriptor = matchingService.characteristics.find((char) => char.uuid === matchingCharacteristic.uuid);
524
+ if (descriptor) {
525
+ // Assign the actual Bluetooth characteristic object to the descriptor so it can be used later
526
+ descriptor.characteristic = matchingCharacteristic;
527
+ // Look for the "rx" characteristic id that accepts notifications
528
+ if (descriptor.id === "rx") {
529
+ // Start receiving notifications for changes on this characteristic
530
+ matchingCharacteristic.startNotifications();
531
+ // Triggered when the characteristic's value changes
532
+ const listener = (event) => {
533
+ // Cast the event's target to a BluetoothRemoteGATTCharacteristic to access its properties
534
+ const target = event.target;
535
+ if (target && target.value) {
536
+ // Delegate the data to handleNotifications method
537
+ this.handleNotifications(target.value);
538
+ }
539
+ };
540
+ // Attach the event listener to listen for changes in the characteristic's value
541
+ matchingCharacteristic.addEventListener("characteristicvaluechanged", listener);
542
+ // Store the listener so it can be referenced (for later removal)
543
+ this.notificationListeners.set(descriptor.uuid, listener);
544
+ }
545
+ }
546
+ }
547
+ else {
548
+ throw new Error(`Characteristic ${characteristic.uuid} not found in service ${service.uuid}`);
549
+ }
550
+ }
551
+ }
552
+ }
553
+ // Call the onSuccess callback after successful connection and setup
554
+ onSuccess();
555
+ };
556
+ /**
557
+ * Handles the 'disconnected' event.
558
+ * @param {Event} event - The 'disconnected' event.
559
+ * @public
560
+ *
561
+ * @example
562
+ * device.onDisconnected(event);
563
+ */
564
+ onDisconnected = (event) => {
565
+ console.warn(`Device ${event.target.name} is disconnected.`);
566
+ this.disconnect();
567
+ };
568
+ /**
569
+ * Reads the value of the specified characteristic from the device.
570
+ * @param {string} serviceId - The service ID where the characteristic belongs.
571
+ * @param {string} characteristicId - The characteristic ID to read from.
572
+ * @param {number} [duration=0] - The duration to wait before resolving the promise, in milliseconds.
573
+ * @returns {Promise<string | undefined>} A promise that resolves when the read operation is completed.
574
+ * @public
575
+ *
576
+ * @example
577
+ * const value = await device.read('battery', 'level', 1000);
578
+ * console.log('Battery level:', value);
579
+ */
580
+ read = async (serviceId, characteristicId, duration = 0) => {
581
+ if (!this.isConnected()) {
582
+ return undefined;
583
+ }
584
+ // Get the characteristic from the service
585
+ const characteristic = this.services
586
+ .find((service) => service.id === serviceId)
587
+ ?.characteristics.find((char) => char.id === characteristicId)?.characteristic;
588
+ if (!characteristic) {
589
+ throw new Error(`Characteristic "${characteristicId}" not found in service "${serviceId}"`);
590
+ }
591
+ this.updateTimestamp();
592
+ // Decode the value based on characteristicId and serviceId
593
+ let decodedValue;
594
+ const decoder = new TextDecoder("utf-8");
595
+ // Read the value from the characteristic
596
+ const value = await characteristic.readValue();
597
+ if ((serviceId === "battery" || serviceId === "humidity" || serviceId === "temperature") &&
598
+ characteristicId === "level") {
599
+ // This is battery-specific; return the first byte as the level
600
+ decodedValue = value.getUint8(0).toString();
601
+ }
602
+ else {
603
+ // Otherwise use a UTF-8 decoder
604
+ decodedValue = decoder.decode(value);
605
+ }
606
+ // Wait for the specified duration before returning the result
607
+ if (duration > 0) {
608
+ await new Promise((resolve) => setTimeout(resolve, duration));
609
+ }
610
+ return decodedValue;
611
+ };
612
+ /**
613
+ * Initiates the tare calibration process.
614
+ * @param {number} duration - The duration time for tare calibration.
615
+ * @returns {boolean} A boolean indicating whether the tare calibration was successful.
616
+ * @public
617
+ *
618
+ * @example
619
+ * const success = device.tare(5000);
620
+ * if (success) {
621
+ * console.log('Tare calibration started');
622
+ * } else {
623
+ * console.log('Tare calibration failed to start');
624
+ * }
625
+ */
626
+ tare(duration = 5000) {
627
+ if (this.tareActive)
628
+ return false;
629
+ this.updateTimestamp();
630
+ this.tareActive = true;
631
+ this.tareDuration = duration;
632
+ this.tareSamples = [];
633
+ this.tareStartTime = Date.now();
634
+ return true;
635
+ }
636
+ /**
637
+ * Apply tare calibration to the provided sample.
638
+ * @param {number} sample - The sample to calibrate.
639
+ * @returns {number} The calibrated tare value.
640
+ * @protected
641
+ *
642
+ * @example
643
+ * const calibratedSample = device.applyTare(rawSample);
644
+ * console.log('Calibrated sample:', calibratedSample);
645
+ */
646
+ applyTare(sample) {
647
+ if (this.tareActive && this.tareStartTime) {
648
+ // Add current sample to the tare samples array
649
+ this.tareSamples.push(sample);
650
+ // Check if the tare calibration duration has passed
651
+ if (Date.now() - this.tareStartTime >= this.tareDuration) {
652
+ // Calculate the average of the tare samples
653
+ const total = this.tareSamples.reduce((acc, sample) => acc + sample, 0);
654
+ this.tareCurrent = total / this.tareSamples.length;
655
+ // Reset the tare calibration process
656
+ this.tareActive = false;
657
+ this.tareStartTime = null;
658
+ this.tareSamples = [];
659
+ }
660
+ }
661
+ // Return the current tare-adjusted value
662
+ return this.tareCurrent;
663
+ }
664
+ /**
665
+ * Updates the timestamp of the last device interaction.
666
+ * This method sets the updatedAt property to the current date and time.
667
+ * @protected
668
+ *
669
+ * @example
670
+ * device.updateTimestamp();
671
+ * console.log('Last updated:', device.updatedAt);
672
+ */
673
+ updateTimestamp = () => {
674
+ this.updatedAt = new Date();
675
+ };
676
+ /**
677
+ * Writes a message to the specified characteristic of a Bluetooth device and optionally provides a callback to handle responses.
678
+ * @param {string} serviceId - The service UUID of the Bluetooth device containing the target characteristic.
679
+ * @param {string} characteristicId - The characteristic UUID where the message will be written.
680
+ * @param {string | Uint8Array | undefined} message - The message to be written to the characteristic. It can be a string or a Uint8Array.
681
+ * @param {number} [duration=0] - Optional. The time in milliseconds to wait before resolving the promise. Defaults to 0 for immediate resolution.
682
+ * @param {WriteCallback} [callback=writeCallback] - Optional. A custom callback to handle the response after the write operation is successful.
683
+ * @returns {Promise<void>} A promise that resolves once the write operation is complete.
684
+ * @public
685
+ * @throws {Error} Throws an error if the characteristic is undefined.
686
+ *
687
+ * @example
688
+ * // Example usage of the write function with a custom callback
689
+ * await Progressor.write("progressor", "tx", ProgressorCommands.GET_BATT_VLTG, 250, (data) => {
690
+ * console.log(`Battery voltage: ${data}`);
691
+ * });
692
+ */
693
+ write = async (serviceId, characteristicId, message, duration = 0, callback = this.writeCallback) => {
694
+ // Check if not connected or no message is provided
695
+ if (!this.isConnected() || message === undefined) {
696
+ return Promise.resolve();
697
+ }
698
+ // Get the characteristic from the service
699
+ const characteristic = this.services
700
+ .find((service) => service.id === serviceId)
701
+ ?.characteristics.find((char) => char.id === characteristicId)?.characteristic;
702
+ if (!characteristic) {
703
+ throw new Error(`Characteristic "${characteristicId}" not found in service "${serviceId}"`);
704
+ }
705
+ this.updateTimestamp();
706
+ // Convert the message to Uint8Array if it's a string
707
+ const valueToWrite = typeof message === "string" ? new Uint8Array(new TextEncoder().encode(message)) : new Uint8Array(message);
708
+ // Write the value to the characteristic
709
+ await characteristic.writeValue(valueToWrite);
710
+ // Update the last written message
711
+ this.writeLast = message;
712
+ // Assign the provided callback to `writeCallback`
713
+ this.writeCallback = callback;
714
+ // If a duration is specified, resolve the promise after the duration
715
+ if (duration > 0) {
716
+ await new Promise((resolve) => setTimeout(resolve, duration));
717
+ }
718
+ };
719
+ }
720
+ //# sourceMappingURL=device.model.js.map