@hangtime/grip-connect 0.5.3 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -117,7 +117,7 @@ motherboardButton.addEventListener("click", () => {
117
117
  enable it at `chrome://flags/#enable-experimental-web-platform-features`.
118
118
  - ✅ [Kilter Board](https://stevie-ray.github.io/hangtime-grip-connect/devices/kilterboard.html)
119
119
  - ✅ [Entralpi](https://stevie-ray.github.io/hangtime-grip-connect/devices/entralpi.html) / Lefu Scale
120
- - [PitchSix Force Board](https://stevie-ray.github.io/hangtime-grip-connect/devices/forceboard.html)
120
+ - [PitchSix Force Board](https://stevie-ray.github.io/hangtime-grip-connect/devices/forceboard.html)
121
121
  - ➡️ [Climbro](https://stevie-ray.github.io/hangtime-grip-connect/devices/climbro.html)
122
122
  - ➡️ [Smartboard Climbing - mySmartBoard](https://stevie-ray.github.io/hangtime-grip-connect/devices/mysmartboard.html)
123
123
 
@@ -18,4 +18,20 @@ export interface IForceBoard extends IDevice {
18
18
  * @returns {Promise<string | undefined>} A Promise that resolves with the manufacturer information.
19
19
  */
20
20
  manufacturer(): Promise<string | undefined>;
21
+ /**
22
+ * Stops the data stream on the specified device.
23
+ * @returns {Promise<void>} A promise that resolves when the stream is stopped.
24
+ */
25
+ stop(): Promise<void>;
26
+ /**
27
+ * Starts streaming data from the specified device.
28
+ * @param {number} [duration=0] - The duration of the stream in milliseconds. If set to 0, stream will continue indefinitely.
29
+ * @returns {Promise<void>} A promise that resolves when the streaming operation is completed.
30
+ */
31
+ stream(duration?: number): Promise<void>;
32
+ /**
33
+ * Retrieves temperature information from the device.
34
+ * @returns {Promise<string | undefined>} A Promise that resolves with the humidity level.
35
+ */
36
+ temperature(): Promise<string | undefined>;
21
37
  }
@@ -106,9 +106,9 @@ export interface IDevice extends IBase {
106
106
  * @param {string} serviceId - The service ID where the characteristic belongs.
107
107
  * @param {string} characteristicId - The characteristic ID to read from.
108
108
  * @param {number} [duration=0] - The duration to wait before resolving the promise, in milliseconds.
109
- * @returns {Promise<string>} A promise that resolves when the read operation is completed.
109
+ * @returns {Promise<string | undefined>} A promise that resolves when the read operation is completed.
110
110
  */
111
- read(serviceId: string, characteristicId: string, duration?: number): Promise<string>;
111
+ read(serviceId: string, characteristicId: string, duration?: number): Promise<string | undefined>;
112
112
  /**
113
113
  * Writes a message to the specified characteristic of a Bluetooth device and optionally provides a callback to handle responses.
114
114
  * @param {string} serviceId - The service UUID of the Bluetooth device containing the target characteristic.
@@ -18,7 +18,7 @@ export declare class Entralpi extends Device implements IEntralpi {
18
18
  */
19
19
  firmware: () => Promise<string | undefined>;
20
20
  /**
21
- * Handles data received from the Progressor device, processes weight measurements,
21
+ * Handles data received from the device, processes weight measurements,
22
22
  * and updates mass data including maximum and average values.
23
23
  * It also handles command responses for retrieving device information.
24
24
  *
@@ -1,6 +1,7 @@
1
1
  import { Device } from "../device.model";
2
2
  import { applyTare } from "../../helpers/tare";
3
3
  import { checkActivity } from "../../helpers/is-active";
4
+ import { DownloadPackets } from "../../helpers/download";
4
5
  export class Entralpi extends Device {
5
6
  constructor() {
6
7
  super({
@@ -128,40 +129,24 @@ export class Entralpi extends Device {
128
129
  * @returns {Promise<string | undefined>} A Promise that resolves with the battery or voltage information.
129
130
  */
130
131
  battery = async () => {
131
- if (this.isConnected()) {
132
- return await this.read("battery", "level", 250);
133
- }
134
- // If device is not found, return undefined
135
- return undefined;
132
+ return await this.read("battery", "level", 250);
136
133
  };
137
134
  /**
138
135
  * Retrieves IEEE 11073-20601 Regulatory Certification from the device.
139
136
  * @returns {Promise<string>} A Promise that resolves with the certification.
140
137
  */
141
138
  certification = async () => {
142
- // Check if the device is connected
143
- if (this.isConnected()) {
144
- // Read certification from the device
145
- return await this.read("device", "certification", 250);
146
- }
147
- // If device is not found, return undefined
148
- return undefined;
139
+ return await this.read("device", "certification", 250);
149
140
  };
150
141
  /**
151
142
  * Retrieves firmware version from the device.
152
143
  * @returns {Promise<string>} A Promise that resolves with the firmware version.
153
144
  */
154
145
  firmware = async () => {
155
- // Check if the device is connected
156
- if (this.isConnected()) {
157
- // Read firmware version from the Motherboard
158
- return await this.read("device", "firmware", 250);
159
- }
160
- // If device is not found, return undefined
161
- return undefined;
146
+ return await this.read("device", "firmware", 250);
162
147
  };
163
148
  /**
164
- * Handles data received from the Progressor device, processes weight measurements,
149
+ * Handles data received from the device, processes weight measurements,
165
150
  * and updates mass data including maximum and average values.
166
151
  * It also handles command responses for retrieving device information.
167
152
  *
@@ -174,10 +159,19 @@ export class Entralpi extends Device {
174
159
  if (value.buffer) {
175
160
  const buffer = value.buffer;
176
161
  const rawData = new DataView(buffer);
162
+ const receivedTime = Date.now();
177
163
  const receivedData = (rawData.getUint16(0) / 100).toFixed(1);
178
- let numericData = Number(receivedData);
164
+ const convertedData = Number(receivedData);
179
165
  // Tare correction
180
- numericData -= applyTare(numericData);
166
+ const numericData = convertedData - applyTare(convertedData);
167
+ // Add data to downloadable Array
168
+ DownloadPackets.push({
169
+ received: receivedTime,
170
+ sampleNum: this.dataPointCount,
171
+ battRaw: 0,
172
+ samples: [convertedData],
173
+ masses: [numericData],
174
+ });
181
175
  // Update massMax
182
176
  this.massMax = Math.max(Number(this.massMax), numericData).toFixed(1);
183
177
  // Update running sum and count
@@ -202,39 +196,21 @@ export class Entralpi extends Device {
202
196
  * @returns {Promise<string>} A Promise that resolves with the hardware version.
203
197
  */
204
198
  hardware = async () => {
205
- // Check if the device is connected
206
- if (this.isConnected()) {
207
- // Read hardware version from the device
208
- return await this.read("device", "hardware", 250);
209
- }
210
- // If device is not found, return undefined
211
- return undefined;
199
+ return await this.read("device", "hardware", 250);
212
200
  };
213
201
  /**
214
202
  * Retrieves manufacturer information from the device.
215
203
  * @returns {Promise<string>} A Promise that resolves with the manufacturer information.
216
204
  */
217
205
  manufacturer = async () => {
218
- // Check if the device is connected
219
- if (this.isConnected()) {
220
- // Read manufacturer information from the device
221
- return await this.read("device", "manufacturer", 250);
222
- }
223
- // If device is not found, return undefined
224
- return undefined;
206
+ return await this.read("device", "manufacturer", 250);
225
207
  };
226
208
  /**
227
209
  * Retrieves model number from the device.
228
210
  * @returns {Promise<string>} A Promise that resolves with the model number.
229
211
  */
230
212
  model = async () => {
231
- // Check if the device is connected
232
- if (this.isConnected()) {
233
- // Read model number from the Entralpi
234
- return await this.read("device", "model", 250);
235
- }
236
- // If device is not found, return undefined
237
- return undefined;
213
+ return await this.read("device", "model", 250);
238
214
  };
239
215
  /**
240
216
  * Retrieves PnP ID from the device, a set of values that used to create a device ID value that is unique for this device.
@@ -242,38 +218,20 @@ export class Entralpi extends Device {
242
218
  * @returns {Promise<string>} A Promise that resolves with the PnP ID.
243
219
  */
244
220
  pnp = async () => {
245
- // Check if the device is connected
246
- if (this.isConnected()) {
247
- // Read software version from the Entralpi
248
- return await this.read("device", "pnp", 250);
249
- }
250
- // If device is not found, return undefined
251
- return undefined;
221
+ return await this.read("device", "pnp", 250);
252
222
  };
253
223
  /**
254
224
  * Retrieves software version from the device.
255
225
  * @returns {Promise<string>} A Promise that resolves with the software version.
256
226
  */
257
227
  software = async () => {
258
- // Check if the device is connected
259
- if (this.isConnected()) {
260
- // Read software version from the Entralpi
261
- return await this.read("device", "software", 250);
262
- }
263
- // If device is not found, return undefined
264
- return undefined;
228
+ return await this.read("device", "software", 250);
265
229
  };
266
230
  /**
267
231
  * Retrieves system id from the device.
268
232
  * @returns {Promise<string>} A Promise that resolves with the system id.
269
233
  */
270
234
  system = async () => {
271
- // Check if the device is connected
272
- if (this.isConnected()) {
273
- // Read system id from the device
274
- return await this.read("device", "system", 250);
275
- }
276
- // If device is not found, return undefined
277
- return undefined;
235
+ return await this.read("device", "system", 250);
278
236
  };
279
237
  }
@@ -10,6 +10,14 @@ export declare class ForceBoard extends Device implements IForceBoard {
10
10
  * @returns {Promise<string | undefined>} A Promise that resolves with the battery or voltage information,
11
11
  */
12
12
  battery: () => Promise<string | undefined>;
13
+ /**
14
+ * Handles data received from the device, processes weight measurements,
15
+ * and updates mass data including maximum and average values.
16
+ * It also handles command responses for retrieving device information.
17
+ *
18
+ * @param {Event} event - The notification event.
19
+ */
20
+ handleNotifications: (event: Event) => void;
13
21
  /**
14
22
  * Retrieves humidity level from the device.
15
23
  * @returns {Promise<string>} A Promise that resolves with the humidity level,
@@ -20,4 +28,20 @@ export declare class ForceBoard extends Device implements IForceBoard {
20
28
  * @returns {Promise<string>} A Promise that resolves with the manufacturer information,
21
29
  */
22
30
  manufacturer: () => Promise<string | undefined>;
31
+ /**
32
+ * Stops the data stream on the specified device.
33
+ * @returns {Promise<void>} A promise that resolves when the stream is stopped.
34
+ */
35
+ stop: () => Promise<void>;
36
+ /**
37
+ * Starts streaming data from the specified device.
38
+ * @param {number} [duration=0] - The duration of the stream in milliseconds. If set to 0, stream will continue indefinitely.
39
+ * @returns {Promise<void>} A promise that resolves when the streaming operation is completed.
40
+ */
41
+ stream: (duration?: number) => Promise<void>;
42
+ /**
43
+ * Retrieves temperature information from the device.
44
+ * @returns {Promise<string>} A Promise that resolves with the manufacturer information,
45
+ */
46
+ temperature: () => Promise<string | undefined>;
23
47
  }
@@ -1,4 +1,7 @@
1
1
  import { Device } from "../device.model";
2
+ import { DownloadPackets, emptyDownloadPackets } from "../../helpers/download";
3
+ import { checkActivity } from "../../helpers/is-active";
4
+ import { applyTare } from "../../helpers/tare";
2
5
  /**
3
6
  * Represents a PitchSix Force Board device
4
7
  */
@@ -142,13 +145,13 @@ export class ForceBoard extends Device {
142
145
  ],
143
146
  },
144
147
  {
145
- name: "",
146
- id: "",
148
+ name: "Weight Serivce",
149
+ id: "weight",
147
150
  uuid: "467a8516-6e39-11eb-9439-0242ac130002",
148
151
  characteristics: [
149
152
  {
150
153
  name: "Read + Write",
151
- id: "",
154
+ id: "tx",
152
155
  uuid: "467a8517-6e39-11eb-9439-0242ac130002",
153
156
  },
154
157
  {
@@ -159,6 +162,9 @@ export class ForceBoard extends Device {
159
162
  ],
160
163
  },
161
164
  ],
165
+ commands: {
166
+ STOP_WEIGHT_MEAS: "",
167
+ },
162
168
  });
163
169
  }
164
170
  /**
@@ -166,35 +172,96 @@ export class ForceBoard extends Device {
166
172
  * @returns {Promise<string | undefined>} A Promise that resolves with the battery or voltage information,
167
173
  */
168
174
  battery = async () => {
169
- if (this.isConnected()) {
170
- return await this.read("battery", "level", 250);
175
+ return await this.read("battery", "level", 250);
176
+ };
177
+ /**
178
+ * Handles data received from the device, processes weight measurements,
179
+ * and updates mass data including maximum and average values.
180
+ * It also handles command responses for retrieving device information.
181
+ *
182
+ * @param {Event} event - The notification event.
183
+ */
184
+ handleNotifications = (event) => {
185
+ const characteristic = event.target;
186
+ const value = characteristic.value;
187
+ if (value) {
188
+ if (value.buffer) {
189
+ const buffer = value.buffer;
190
+ const rawData = new DataView(buffer);
191
+ const receivedTime = Date.now();
192
+ const receivedData = rawData.getUint8(4); // Read the value at index 4
193
+ // Convert from LBS to KG
194
+ const convertedReceivedData = receivedData * 0.453592;
195
+ // Tare correction
196
+ const numericData = convertedReceivedData - applyTare(convertedReceivedData);
197
+ // Add data to downloadable Array
198
+ DownloadPackets.push({
199
+ received: receivedTime,
200
+ sampleNum: this.dataPointCount,
201
+ battRaw: 0,
202
+ samples: [convertedReceivedData],
203
+ masses: [numericData],
204
+ });
205
+ // Update massMax
206
+ this.massMax = Math.max(Number(this.massMax), numericData).toFixed(1);
207
+ // Update running sum and count
208
+ const currentMassTotal = Math.max(-1000, numericData);
209
+ this.massTotalSum += currentMassTotal;
210
+ this.dataPointCount++;
211
+ // Calculate the average dynamically
212
+ this.massAverage = (this.massTotalSum / this.dataPointCount).toFixed(1);
213
+ // Check if device is being used
214
+ checkActivity(numericData);
215
+ // Notify with weight data
216
+ this.notifyCallback({
217
+ massMax: this.massMax,
218
+ massAverage: this.massAverage,
219
+ massTotal: Math.max(-1000, numericData).toFixed(1),
220
+ });
221
+ }
171
222
  }
172
- // If device is not found, return undefined
173
- return undefined;
174
223
  };
175
224
  /**
176
225
  * Retrieves humidity level from the device.
177
226
  * @returns {Promise<string>} A Promise that resolves with the humidity level,
178
227
  */
179
228
  humidity = async () => {
180
- // Check if the device is connected
181
- if (this.isConnected()) {
182
- return await this.read("humidity", "level", 250);
183
- }
184
- // If device is not found, return undefined
185
- return undefined;
229
+ return await this.read("humidity", "level", 250);
186
230
  };
187
231
  /**
188
232
  * Retrieves manufacturer information from the device.
189
233
  * @returns {Promise<string>} A Promise that resolves with the manufacturer information,
190
234
  */
191
235
  manufacturer = async () => {
192
- // Check if the device is connected
193
- if (this.isConnected()) {
194
- // Read manufacturer information from the device
195
- return await this.read("device", "manufacturer", 250);
236
+ return await this.read("device", "manufacturer", 250);
237
+ };
238
+ /**
239
+ * Stops the data stream on the specified device.
240
+ * @returns {Promise<void>} A promise that resolves when the stream is stopped.
241
+ */
242
+ stop = async () => {
243
+ await this.write("weight", "tx", this.commands.STOP_WEIGHT_MEAS, 0);
244
+ };
245
+ /**
246
+ * Starts streaming data from the specified device.
247
+ * @param {number} [duration=0] - The duration of the stream in milliseconds. If set to 0, stream will continue indefinitely.
248
+ * @returns {Promise<void>} A promise that resolves when the streaming operation is completed.
249
+ */
250
+ stream = async (duration = 0) => {
251
+ // Reset download packets
252
+ emptyDownloadPackets();
253
+ // Start streaming data
254
+ await this.write("weight", "tx", new Uint8Array([0x04]), duration); // ASCII control character EOT (End of Transmission)
255
+ // Stop streaming if duration is set
256
+ if (duration !== 0) {
257
+ await this.stop();
196
258
  }
197
- // If device is not found, return undefined
198
- return undefined;
259
+ };
260
+ /**
261
+ * Retrieves temperature information from the device.
262
+ * @returns {Promise<string>} A Promise that resolves with the manufacturer information,
263
+ */
264
+ temperature = async () => {
265
+ return await this.read("temperature", "level", 250);
199
266
  };
200
267
  }
@@ -162,37 +162,23 @@ export class Motherboard extends Device {
162
162
  * @returns {Promise<string | undefined>} A Promise that resolves with the battery or voltage information,
163
163
  */
164
164
  battery = async () => {
165
- if (this.isConnected()) {
166
- return await this.read("battery", "level", 250);
167
- }
168
- // If device is not found, return undefined
169
- return undefined;
165
+ return await this.read("battery", "level", 250);
170
166
  };
171
167
  /**
172
168
  * Writes a command to get calibration data from the device.
173
169
  * @returns {Promise<void>} A Promise that resolves when the command is successfully sent.
174
170
  */
175
171
  calibration = async () => {
176
- // Check if the device is connected
177
- if (this.isConnected()) {
178
- // Write the command to get calibration data to the device
179
- await this.write("uart", "tx", this.commands.GET_CALIBRATION, 2500, (data) => {
180
- console.log(data);
181
- });
182
- }
172
+ await this.write("uart", "tx", this.commands.GET_CALIBRATION, 2500, (data) => {
173
+ console.log(data);
174
+ });
183
175
  };
184
176
  /**
185
177
  * Retrieves firmware version from the device.
186
178
  * @returns {Promise<string>} A Promise that resolves with the firmware version,
187
179
  */
188
180
  firmware = async () => {
189
- // Check if the device is connected
190
- if (this.isConnected()) {
191
- // Read firmware version from the Motherboard
192
- return await this.read("device", "firmware", 250);
193
- }
194
- // If device is not found, return undefined
195
- return undefined;
181
+ return await this.read("device", "firmware", 250);
196
182
  };
197
183
  /**
198
184
  * Handles data received from the Motherboard device. Processes hex-encoded streaming packets
@@ -303,13 +289,7 @@ export class Motherboard extends Device {
303
289
  * @returns {Promise<string>} A Promise that resolves with the hardware version,
304
290
  */
305
291
  hardware = async () => {
306
- // Check if the device is connected
307
- if (this.isConnected()) {
308
- // Read hardware version from the device
309
- return await this.read("device", "hardware", 250);
310
- }
311
- // If device is not found, return undefined
312
- return undefined;
292
+ return await this.read("device", "hardware", 250);
313
293
  };
314
294
  /**
315
295
  * Sets the LED color based on a single color option. Defaults to turning the LEDs off if no configuration is provided.
@@ -337,40 +317,25 @@ export class Motherboard extends Device {
337
317
  * @returns {Promise<string>} A Promise that resolves with the manufacturer information,
338
318
  */
339
319
  manufacturer = async () => {
340
- // Check if the device is connected
341
- if (this.isConnected()) {
342
- // Read manufacturer information from the device
343
- return await this.read("device", "manufacturer", 250);
344
- }
345
- // If device is not found, return undefined
346
- return undefined;
320
+ return await this.read("device", "manufacturer", 250);
347
321
  };
348
322
  /**
349
323
  * Retrieves serial number from the device.
350
324
  * @returns {Promise<string>} A Promise that resolves with the serial number,
351
325
  */
352
326
  serial = async () => {
353
- // Check if the device is connected
354
- if (this.isConnected()) {
355
- // Write serial number command to the Motherboard and read output
356
- let response = undefined;
357
- await this.write("uart", "tx", this.commands.GET_SERIAL, 250, (data) => {
358
- response = data;
359
- });
360
- return response;
361
- }
362
- // If device is not found, return undefined
363
- return undefined;
327
+ let response = undefined;
328
+ await this.write("uart", "tx", this.commands.GET_SERIAL, 250, (data) => {
329
+ response = data;
330
+ });
331
+ return response;
364
332
  };
365
333
  /**
366
334
  * Stops the data stream on the specified device.
367
335
  * @returns {Promise<void>} A promise that resolves when the stream is stopped.
368
336
  */
369
337
  stop = async () => {
370
- if (this.isConnected()) {
371
- // Stop stream of device
372
- await this.write("uart", "tx", this.commands.STOP_WEIGHT_MEAS, 0);
373
- }
338
+ await this.write("uart", "tx", this.commands.STOP_WEIGHT_MEAS, 0);
374
339
  };
375
340
  /**
376
341
  * Starts streaming data from the specified device.
@@ -378,20 +343,17 @@ export class Motherboard extends Device {
378
343
  * @returns {Promise<void>} A promise that resolves when the streaming operation is completed.
379
344
  */
380
345
  stream = async (duration = 0) => {
381
- if (this.isConnected()) {
382
- // Reset download packets
383
- emptyDownloadPackets();
384
- // Device specific logic
385
- // Read calibration data if not already available
386
- if (!this.CALIBRATION[0].length) {
387
- await this.calibration();
388
- }
389
- // Start streaming data
390
- await this.write("uart", "tx", this.commands.START_WEIGHT_MEAS, duration);
391
- // Stop streaming if duration is set
392
- if (duration !== 0) {
393
- await this.stop();
394
- }
346
+ // Reset download packets
347
+ emptyDownloadPackets();
348
+ // Read calibration data if not already available
349
+ if (!this.CALIBRATION[0].length) {
350
+ await this.calibration();
351
+ }
352
+ // Start streaming data
353
+ await this.write("uart", "tx", this.commands.START_WEIGHT_MEAS, duration);
354
+ // Stop streaming if duration is set
355
+ if (duration !== 0) {
356
+ await this.stop();
395
357
  }
396
358
  };
397
359
  /**
@@ -404,16 +366,10 @@ export class Motherboard extends Device {
404
366
  * @returns {Promise<string>} A Promise that resolves with the 320-byte memory content as a string,
405
367
  */
406
368
  text = async () => {
407
- // Check if the device is connected
408
- if (this.isConnected()) {
409
- // Write text information command to the Motherboard and read output
410
- let response = undefined;
411
- await this.write("uart", "tx", this.commands.GET_TEXT, 250, (data) => {
412
- response = data;
413
- });
414
- return response;
415
- }
416
- // If device is not found, return undefined
417
- return undefined;
369
+ let response = undefined;
370
+ await this.write("uart", "tx", this.commands.GET_TEXT, 250, (data) => {
371
+ response = data;
372
+ });
373
+ return response;
418
374
  };
419
375
  }
@@ -16,7 +16,7 @@ export declare class Progressor extends Device implements IProgressor {
16
16
  */
17
17
  firmware: () => Promise<string | undefined>;
18
18
  /**
19
- * Handles data received from the Progressor device, processes weight measurements,
19
+ * Handles data received from the device, processes weight measurements,
20
20
  * and updates mass data including maximum and average values.
21
21
  * It also handles command responses for retrieving device information.
22
22
  *