@hangtime/grip-connect 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -155,6 +155,7 @@ A special thank you to:
155
155
  - [@ecstrema](https://github.com/ecstrema) for providing [examples](https://github.com/ecstrema/entralpi-games) on how
156
156
  to play games with the Entralpi.
157
157
  - [Tindeq](https://tindeq.com/) for providing an open [Progressor API](https://tindeq.com/progressor_api/).
158
+ - [PitchSix](https://pitchsix.com/) for the [Force Board Portable Public API](https://pitchsix.com/pages/downloads).
158
159
  - [@StuartLittlefair](https://github.com/StuartLittlefair) for his
159
160
  [PyTindeq](https://github.com/StuartLittlefair/PyTindeq) implementation.
160
161
  - [@Phil9l](https://github.com/phil9l) for his research and providing a [blog](https://bazun.me/blog/kiterboard/) on how
package/deno.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hangtime/grip-connect",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "license": "BSD-2-Clause",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
@@ -37,6 +37,12 @@ export interface Commands {
37
37
  * Used to ensure accurate measurements by applying calibration points.
38
38
  */
39
39
  GET_CALIBRATION?: string;
40
+ /**
41
+ * Sets the Force Board into Quick Start mode.
42
+ * In this mode, data transmission starts when force exceeds the threshold
43
+ * and stops when force drops below the threshold.
44
+ */
45
+ START_QUICK_MEAS?: string;
40
46
  /**
41
47
  * Tares the scale, zeroing the current weight measurement.
42
48
  * Used to reset the baseline for weight data.
@@ -19,19 +19,45 @@ export interface IForceBoard extends IDevice {
19
19
  */
20
20
  manufacturer(): Promise<string | undefined>;
21
21
  /**
22
- * Stops the data stream on the specified device.
22
+ * Stops the data stream on the specified device by setting it to Idle mode.
23
+ * Writes 0x07 to the Device Mode characteristic.
23
24
  * @returns {Promise<void>} A promise that resolves when the stream is stopped.
24
25
  */
25
26
  stop(): Promise<void>;
26
27
  /**
27
- * Starts streaming data from the specified device.
28
+ * Starts streaming data from the specified device in Streaming Data Mode.
29
+ * Writes 0x04 to the Device Mode characteristic.
28
30
  * @param {number} [duration=0] - The duration of the stream in milliseconds. If set to 0, stream will continue indefinitely.
29
31
  * @returns {Promise<void>} A promise that resolves when the streaming operation is completed.
30
32
  */
31
33
  stream(duration?: number): Promise<void>;
34
+ /**
35
+ * Tares the Force Board device using a characteristic to zero out the current load value.
36
+ * @returns {Promise<void>} A promise that resolves when the tare operation is completed.
37
+ */
38
+ tareByCharacteristic(): Promise<void>;
39
+ /**
40
+ * Tares the Force Board device using the Device Mode characteristic.
41
+ * Writes 0x05 to the Device Mode characteristic to zero out the current load value.
42
+ * @returns {Promise<void>} A promise that resolves when the tare operation is completed.
43
+ */
44
+ tareByMode(): Promise<void>;
45
+ /**
46
+ * Sets the threshold for the Quick Start mode.
47
+ * @param {number} thresholdLbs - The threshold value in pounds.
48
+ * @returns {Promise<void>} A promise that resolves when the threshold is set.
49
+ */
50
+ threshold(thresholdLbs: number): Promise<void>;
32
51
  /**
33
52
  * Retrieves temperature information from the device.
34
- * @returns {Promise<string | undefined>} A Promise that resolves with the humidity level.
53
+ * @returns {Promise<string | undefined>} A Promise that resolves with the temperature information.
35
54
  */
36
55
  temperature(): Promise<string | undefined>;
56
+ /**
57
+ * Starts the Force Board in Quick Start mode.
58
+ * Writes 0x06 to the Device Mode characteristic.
59
+ * @param {number} [duration=0] - The duration in milliseconds. If set to 0, mode will continue indefinitely.
60
+ * @returns {Promise<void>} A promise that resolves when the operation is completed.
61
+ */
62
+ quick(duration?: number): Promise<void>;
37
63
  }
@@ -30,19 +30,43 @@ export declare class ForceBoard extends Device implements IForceBoard {
30
30
  */
31
31
  manufacturer: () => Promise<string | undefined>;
32
32
  /**
33
- * Stops the data stream on the specified device.
33
+ * Stops the data stream on the specified device by setting it to Idle mode.
34
34
  * @returns {Promise<void>} A promise that resolves when the stream is stopped.
35
35
  */
36
36
  stop: () => Promise<void>;
37
37
  /**
38
- * Starts streaming data from the specified device.
38
+ * Starts streaming data from the specified device in Streaming Data Mode.
39
39
  * @param {number} [duration=0] - The duration of the stream in milliseconds. If set to 0, stream will continue indefinitely.
40
40
  * @returns {Promise<void>} A promise that resolves when the streaming operation is completed.
41
41
  */
42
42
  stream: (duration?: number) => Promise<void>;
43
+ /**
44
+ * Sets the threshold in Lbs for the Quick Start mode.
45
+ * @param {number} thresholdLbs - The threshold value in pounds.
46
+ * @returns {Promise<void>} A promise that resolves when the threshold is set.
47
+ */
48
+ threshold: (thresholdLbs: number) => Promise<void>;
49
+ /**
50
+ * Tares the Force Board device using a characteristic to zero out the current load value.
51
+ * @returns {Promise<void>} A promise that resolves when the tare operation is completed.
52
+ */
53
+ tareByCharacteristic: () => Promise<void>;
54
+ /**
55
+ * Initiates a tare routine via the Device Mode characteristic.
56
+ * Writes 0x05 to the Device Mode characteristic to zero out the current load value.
57
+ * @returns {Promise<void>} A promise that resolves when the tare operation is completed.
58
+ */
59
+ tareByMode: () => Promise<void>;
43
60
  /**
44
61
  * Retrieves temperature information from the device.
45
- * @returns {Promise<string>} A Promise that resolves with the manufacturer information,
62
+ * @returns {Promise<string>} A Promise that resolves with the temperature information,
46
63
  */
47
64
  temperature: () => Promise<string | undefined>;
65
+ /**
66
+ * Starts the Force Board in Quick Start mode.
67
+ * Writes 0x06 to the Device Mode characteristic.
68
+ * @param {number} [duration=0] - The duration in milliseconds. If set to 0, mode will continue indefinitely.
69
+ * @returns {Promise<void>} A promise that resolves when the operation is completed.
70
+ */
71
+ quick: (duration?: number) => Promise<void>;
48
72
  }
@@ -106,13 +106,13 @@ export class ForceBoard extends Device {
106
106
  uuid: "9a88d681-8df2-4afe-9e0d-c2bbbe773dd0",
107
107
  },
108
108
  {
109
- name: "Read + Notify",
109
+ name: "Force Data",
110
110
  id: "rx",
111
111
  uuid: "9a88d682-8df2-4afe-9e0d-c2bbbe773dd0",
112
112
  },
113
113
  {
114
- name: "Write",
115
- id: "",
114
+ name: "Tare",
115
+ id: "tare",
116
116
  uuid: "9a88d683-8df2-4afe-9e0d-c2bbbe773dd0",
117
117
  },
118
118
  {
@@ -121,8 +121,8 @@ export class ForceBoard extends Device {
121
121
  uuid: "9a88d685-8df2-4afe-9e0d-c2bbbe773dd0",
122
122
  },
123
123
  {
124
- name: "Write",
125
- id: "",
124
+ name: "Threshold",
125
+ id: "threshold",
126
126
  uuid: "9a88d686-8df2-4afe-9e0d-c2bbbe773dd0",
127
127
  },
128
128
  {
@@ -143,12 +143,12 @@ export class ForceBoard extends Device {
143
143
  ],
144
144
  },
145
145
  {
146
- name: "Weight Serivce",
146
+ name: "Weight Service",
147
147
  id: "weight",
148
148
  uuid: "467a8516-6e39-11eb-9439-0242ac130002",
149
149
  characteristics: [
150
150
  {
151
- name: "Read + Write",
151
+ name: "Device Mode",
152
152
  id: "tx",
153
153
  uuid: "467a8517-6e39-11eb-9439-0242ac130002",
154
154
  },
@@ -161,7 +161,10 @@ export class ForceBoard extends Device {
161
161
  },
162
162
  ],
163
163
  commands: {
164
- STOP_WEIGHT_MEAS: "",
164
+ START_WEIGHT_MEAS: String.fromCharCode(0x04), // Streaming Data Mode: continuously streams force data.
165
+ TARE_SCALE: String.fromCharCode(0x05), // Tare function: zeroes out the current load value
166
+ START_QUICK_MEAS: String.fromCharCode(0x06), // Quick Start Mode: Starts data transmission when a force value exceeds the Threshold and stops data transmission when the force data drops below the Threshold.
167
+ STOP_WEIGHT_MEAS: String.fromCharCode(0x07), // Idle Mode: Force Board is idle.
165
168
  },
166
169
  });
167
170
  }
@@ -187,38 +190,43 @@ export class ForceBoard extends Device {
187
190
  if (value.buffer) {
188
191
  const receivedTime = Date.now();
189
192
  const dataArray = new Uint8Array(value.buffer);
190
- // Skip the first 2 bytes, which are the command and length
191
- // The data is sent in groups of 3 bytes
192
- for (let i = 2; i < dataArray.length; i += 3) {
193
- const receivedData = (dataArray[i] << 16) | (dataArray[i + 1] << 8) | dataArray[i + 2];
194
- // Convert from LBS to KG
195
- const convertedReceivedData = receivedData * 0.453592;
196
- // Tare correction
197
- const numericData = convertedReceivedData - this.applyTare(convertedReceivedData);
198
- // Add data to downloadable Array
199
- this.downloadPackets.push({
200
- received: receivedTime,
201
- sampleNum: this.dataPointCount,
202
- battRaw: 0,
203
- samples: [convertedReceivedData],
204
- masses: [numericData],
205
- });
206
- // Update massMax
207
- this.massMax = Math.max(Number(this.massMax), numericData).toFixed(1);
208
- // Update running sum and count
209
- const currentMassTotal = Math.max(-1000, numericData);
210
- this.massTotalSum += currentMassTotal;
211
- this.dataPointCount++;
212
- // Calculate the average dynamically
213
- this.massAverage = (this.massTotalSum / this.dataPointCount).toFixed(1);
214
- // Check if device is being used
215
- this.activityCheck(numericData);
216
- // Notify with weight data
217
- this.notifyCallback({
218
- massMax: this.massMax,
219
- massAverage: this.massAverage,
220
- massTotal: Math.max(-1000, numericData).toFixed(1),
221
- });
193
+ // First two bytes contain the number of samples in the packet
194
+ const numSamples = (dataArray[0] << 8) | dataArray[1];
195
+ // Process each sample (3 bytes per sample)
196
+ for (let i = 0; i < numSamples; i++) {
197
+ const offset = 2 + i * 3; // Skip the first 2 bytes which indicate number of samples
198
+ if (offset + 2 < dataArray.length) {
199
+ // Sample = byte1*32768 + byte2*256 + byte3
200
+ const receivedData = dataArray[offset] * 32768 + dataArray[offset + 1] * 256 + dataArray[offset + 2];
201
+ // Convert from LBS to KG
202
+ const convertedReceivedData = receivedData * 0.453592;
203
+ // Tare correction
204
+ const numericData = convertedReceivedData - this.applyTare(convertedReceivedData);
205
+ // Add data to downloadable Array
206
+ this.downloadPackets.push({
207
+ received: receivedTime,
208
+ sampleNum: this.dataPointCount,
209
+ battRaw: 0,
210
+ samples: [convertedReceivedData],
211
+ masses: [numericData],
212
+ });
213
+ // Update massMax
214
+ this.massMax = Math.max(Number(this.massMax), numericData).toFixed(1);
215
+ // Update running sum and count
216
+ const currentMassTotal = Math.max(-1000, numericData);
217
+ this.massTotalSum += currentMassTotal;
218
+ this.dataPointCount++;
219
+ // Calculate the average dynamically
220
+ this.massAverage = (this.massTotalSum / this.dataPointCount).toFixed(1);
221
+ // Check if device is being used
222
+ this.activityCheck(numericData);
223
+ // Notify with weight data
224
+ this.notifyCallback({
225
+ massMax: this.massMax,
226
+ massAverage: this.massAverage,
227
+ massTotal: Math.max(-1000, numericData).toFixed(1),
228
+ });
229
+ }
222
230
  }
223
231
  }
224
232
  }
@@ -238,32 +246,67 @@ export class ForceBoard extends Device {
238
246
  return await this.read("device", "manufacturer", 250);
239
247
  };
240
248
  /**
241
- * Stops the data stream on the specified device.
249
+ * Stops the data stream on the specified device by setting it to Idle mode.
242
250
  * @returns {Promise<void>} A promise that resolves when the stream is stopped.
243
251
  */
244
252
  stop = async () => {
245
253
  await this.write("weight", "tx", this.commands.STOP_WEIGHT_MEAS, 0);
246
254
  };
247
255
  /**
248
- * Starts streaming data from the specified device.
256
+ * Starts streaming data from the specified device in Streaming Data Mode.
249
257
  * @param {number} [duration=0] - The duration of the stream in milliseconds. If set to 0, stream will continue indefinitely.
250
258
  * @returns {Promise<void>} A promise that resolves when the streaming operation is completed.
251
259
  */
252
260
  stream = async (duration = 0) => {
253
- // Reset download packets
254
- this.downloadPackets.length = 0;
255
- // Start streaming data
256
- await this.write("weight", "tx", new Uint8Array([0x04]), duration); // ASCII control character EOT (End of Transmission)
257
- // Stop streaming if duration is set
258
- if (duration !== 0) {
259
- await this.stop();
260
- }
261
+ // Start streaming data - Streaming Data Mode
262
+ await this.write("weight", "tx", this.commands.START_WEIGHT_MEAS, duration);
263
+ };
264
+ /**
265
+ * Sets the threshold in Lbs for the Quick Start mode.
266
+ * @param {number} thresholdLbs - The threshold value in pounds.
267
+ * @returns {Promise<void>} A promise that resolves when the threshold is set.
268
+ */
269
+ threshold = async (thresholdLbs) => {
270
+ const thresholdHex = thresholdLbs.toString(16).padStart(6, "0");
271
+ // 3-byte array from the hex string
272
+ const bytes = new Uint8Array(3);
273
+ bytes[0] = parseInt(thresholdHex.substring(0, 2), 16);
274
+ bytes[1] = parseInt(thresholdHex.substring(2, 4), 16);
275
+ bytes[2] = parseInt(thresholdHex.substring(4, 6), 16);
276
+ await this.write("forceboard", "threshold", String.fromCharCode(...bytes), 0);
277
+ };
278
+ /**
279
+ * Tares the Force Board device using a characteristic to zero out the current load value.
280
+ * @returns {Promise<void>} A promise that resolves when the tare operation is completed.
281
+ */
282
+ tareByCharacteristic = async () => {
283
+ // Send tare command (0x01) to the tare characteristic
284
+ const tareValue = String.fromCharCode(0x01);
285
+ await this.write("forceboard", "tare", tareValue, 0);
286
+ };
287
+ /**
288
+ * Initiates a tare routine via the Device Mode characteristic.
289
+ * Writes 0x05 to the Device Mode characteristic to zero out the current load value.
290
+ * @returns {Promise<void>} A promise that resolves when the tare operation is completed.
291
+ */
292
+ tareByMode = async () => {
293
+ await this.write("weight", "tx", this.commands.TARE_SCALE, 0);
261
294
  };
262
295
  /**
263
296
  * Retrieves temperature information from the device.
264
- * @returns {Promise<string>} A Promise that resolves with the manufacturer information,
297
+ * @returns {Promise<string>} A Promise that resolves with the temperature information,
265
298
  */
266
299
  temperature = async () => {
267
300
  return await this.read("temperature", "level", 250);
268
301
  };
302
+ /**
303
+ * Starts the Force Board in Quick Start mode.
304
+ * Writes 0x06 to the Device Mode characteristic.
305
+ * @param {number} [duration=0] - The duration in milliseconds. If set to 0, mode will continue indefinitely.
306
+ * @returns {Promise<void>} A promise that resolves when the operation is completed.
307
+ */
308
+ quick = async (duration = 0) => {
309
+ // Start in Quick Start mode
310
+ await this.write("weight", "tx", this.commands.START_QUICK_MEAS, duration);
311
+ };
269
312
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hangtime/grip-connect",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "Griptonite Motherboard, Tindeq Progressor, PitchSix Force Board, WHC-06, Entralpi, Climbro, mySmartBoard: Bluetooth API Force-Sensing strength analysis for climbers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -48,6 +48,15 @@ export interface Commands {
48
48
  */
49
49
  GET_CALIBRATION?: string
50
50
 
51
+ // Force Board Portable
52
+
53
+ /**
54
+ * Sets the Force Board into Quick Start mode.
55
+ * In this mode, data transmission starts when force exceeds the threshold
56
+ * and stops when force drops below the threshold.
57
+ */
58
+ START_QUICK_MEAS?: string
59
+
51
60
  // Tindeq Progressor
52
61
 
53
62
  /**
@@ -23,21 +23,51 @@ export interface IForceBoard extends IDevice {
23
23
  manufacturer(): Promise<string | undefined>
24
24
 
25
25
  /**
26
- * Stops the data stream on the specified device.
26
+ * Stops the data stream on the specified device by setting it to Idle mode.
27
+ * Writes 0x07 to the Device Mode characteristic.
27
28
  * @returns {Promise<void>} A promise that resolves when the stream is stopped.
28
29
  */
29
30
  stop(): Promise<void>
30
31
 
31
32
  /**
32
- * Starts streaming data from the specified device.
33
+ * Starts streaming data from the specified device in Streaming Data Mode.
34
+ * Writes 0x04 to the Device Mode characteristic.
33
35
  * @param {number} [duration=0] - The duration of the stream in milliseconds. If set to 0, stream will continue indefinitely.
34
36
  * @returns {Promise<void>} A promise that resolves when the streaming operation is completed.
35
37
  */
36
38
  stream(duration?: number): Promise<void>
37
39
 
40
+ /**
41
+ * Tares the Force Board device using a characteristic to zero out the current load value.
42
+ * @returns {Promise<void>} A promise that resolves when the tare operation is completed.
43
+ */
44
+ tareByCharacteristic(): Promise<void>
45
+
46
+ /**
47
+ * Tares the Force Board device using the Device Mode characteristic.
48
+ * Writes 0x05 to the Device Mode characteristic to zero out the current load value.
49
+ * @returns {Promise<void>} A promise that resolves when the tare operation is completed.
50
+ */
51
+ tareByMode(): Promise<void>
52
+
53
+ /**
54
+ * Sets the threshold for the Quick Start mode.
55
+ * @param {number} thresholdLbs - The threshold value in pounds.
56
+ * @returns {Promise<void>} A promise that resolves when the threshold is set.
57
+ */
58
+ threshold(thresholdLbs: number): Promise<void>
59
+
38
60
  /**
39
61
  * Retrieves temperature information from the device.
40
- * @returns {Promise<string | undefined>} A Promise that resolves with the humidity level.
62
+ * @returns {Promise<string | undefined>} A Promise that resolves with the temperature information.
41
63
  */
42
64
  temperature(): Promise<string | undefined>
65
+
66
+ /**
67
+ * Starts the Force Board in Quick Start mode.
68
+ * Writes 0x06 to the Device Mode characteristic.
69
+ * @param {number} [duration=0] - The duration in milliseconds. If set to 0, mode will continue indefinitely.
70
+ * @returns {Promise<void>} A promise that resolves when the operation is completed.
71
+ */
72
+ quick(duration?: number): Promise<void>
43
73
  }
@@ -108,13 +108,13 @@ export class ForceBoard extends Device implements IForceBoard {
108
108
  uuid: "9a88d681-8df2-4afe-9e0d-c2bbbe773dd0",
109
109
  },
110
110
  {
111
- name: "Read + Notify",
111
+ name: "Force Data",
112
112
  id: "rx",
113
113
  uuid: "9a88d682-8df2-4afe-9e0d-c2bbbe773dd0",
114
114
  },
115
115
  {
116
- name: "Write",
117
- id: "",
116
+ name: "Tare",
117
+ id: "tare",
118
118
  uuid: "9a88d683-8df2-4afe-9e0d-c2bbbe773dd0",
119
119
  },
120
120
  {
@@ -123,8 +123,8 @@ export class ForceBoard extends Device implements IForceBoard {
123
123
  uuid: "9a88d685-8df2-4afe-9e0d-c2bbbe773dd0",
124
124
  },
125
125
  {
126
- name: "Write",
127
- id: "",
126
+ name: "Threshold",
127
+ id: "threshold",
128
128
  uuid: "9a88d686-8df2-4afe-9e0d-c2bbbe773dd0",
129
129
  },
130
130
  {
@@ -145,12 +145,12 @@ export class ForceBoard extends Device implements IForceBoard {
145
145
  ],
146
146
  },
147
147
  {
148
- name: "Weight Serivce",
148
+ name: "Weight Service",
149
149
  id: "weight",
150
150
  uuid: "467a8516-6e39-11eb-9439-0242ac130002",
151
151
  characteristics: [
152
152
  {
153
- name: "Read + Write",
153
+ name: "Device Mode",
154
154
  id: "tx",
155
155
  uuid: "467a8517-6e39-11eb-9439-0242ac130002",
156
156
  },
@@ -163,7 +163,10 @@ export class ForceBoard extends Device implements IForceBoard {
163
163
  },
164
164
  ],
165
165
  commands: {
166
- STOP_WEIGHT_MEAS: "",
166
+ START_WEIGHT_MEAS: String.fromCharCode(0x04), // Streaming Data Mode: continuously streams force data.
167
+ TARE_SCALE: String.fromCharCode(0x05), // Tare function: zeroes out the current load value
168
+ START_QUICK_MEAS: String.fromCharCode(0x06), // Quick Start Mode: Starts data transmission when a force value exceeds the Threshold and stops data transmission when the force data drops below the Threshold.
169
+ STOP_WEIGHT_MEAS: String.fromCharCode(0x07), // Idle Mode: Force Board is idle.
167
170
  },
168
171
  })
169
172
  }
@@ -191,43 +194,51 @@ export class ForceBoard extends Device implements IForceBoard {
191
194
  if (value.buffer) {
192
195
  const receivedTime: number = Date.now()
193
196
  const dataArray = new Uint8Array(value.buffer)
194
- // Skip the first 2 bytes, which are the command and length
195
- // The data is sent in groups of 3 bytes
196
- for (let i = 2; i < dataArray.length; i += 3) {
197
- const receivedData = (dataArray[i] << 16) | (dataArray[i + 1] << 8) | dataArray[i + 2]
198
- // Convert from LBS to KG
199
- const convertedReceivedData = receivedData * 0.453592
200
- // Tare correction
201
- const numericData = convertedReceivedData - this.applyTare(convertedReceivedData)
202
- // Add data to downloadable Array
203
- this.downloadPackets.push({
204
- received: receivedTime,
205
- sampleNum: this.dataPointCount,
206
- battRaw: 0,
207
- samples: [convertedReceivedData],
208
- masses: [numericData],
209
- })
210
197
 
211
- // Update massMax
212
- this.massMax = Math.max(Number(this.massMax), numericData).toFixed(1)
198
+ // First two bytes contain the number of samples in the packet
199
+ const numSamples = (dataArray[0] << 8) | dataArray[1]
200
+
201
+ // Process each sample (3 bytes per sample)
202
+ for (let i = 0; i < numSamples; i++) {
203
+ const offset = 2 + i * 3 // Skip the first 2 bytes which indicate number of samples
204
+ if (offset + 2 < dataArray.length) {
205
+ // Sample = byte1*32768 + byte2*256 + byte3
206
+ const receivedData = dataArray[offset] * 32768 + dataArray[offset + 1] * 256 + dataArray[offset + 2]
207
+
208
+ // Convert from LBS to KG
209
+ const convertedReceivedData = receivedData * 0.453592
210
+ // Tare correction
211
+ const numericData = convertedReceivedData - this.applyTare(convertedReceivedData)
212
+ // Add data to downloadable Array
213
+ this.downloadPackets.push({
214
+ received: receivedTime,
215
+ sampleNum: this.dataPointCount,
216
+ battRaw: 0,
217
+ samples: [convertedReceivedData],
218
+ masses: [numericData],
219
+ })
213
220
 
214
- // Update running sum and count
215
- const currentMassTotal = Math.max(-1000, numericData)
216
- this.massTotalSum += currentMassTotal
217
- this.dataPointCount++
221
+ // Update massMax
222
+ this.massMax = Math.max(Number(this.massMax), numericData).toFixed(1)
218
223
 
219
- // Calculate the average dynamically
220
- this.massAverage = (this.massTotalSum / this.dataPointCount).toFixed(1)
224
+ // Update running sum and count
225
+ const currentMassTotal = Math.max(-1000, numericData)
226
+ this.massTotalSum += currentMassTotal
227
+ this.dataPointCount++
221
228
 
222
- // Check if device is being used
223
- this.activityCheck(numericData)
229
+ // Calculate the average dynamically
230
+ this.massAverage = (this.massTotalSum / this.dataPointCount).toFixed(1)
224
231
 
225
- // Notify with weight data
226
- this.notifyCallback({
227
- massMax: this.massMax,
228
- massAverage: this.massAverage,
229
- massTotal: Math.max(-1000, numericData).toFixed(1),
230
- })
232
+ // Check if device is being used
233
+ this.activityCheck(numericData)
234
+
235
+ // Notify with weight data
236
+ this.notifyCallback({
237
+ massMax: this.massMax,
238
+ massAverage: this.massAverage,
239
+ massTotal: Math.max(-1000, numericData).toFixed(1),
240
+ })
241
+ }
231
242
  }
232
243
  }
233
244
  }
@@ -250,7 +261,7 @@ export class ForceBoard extends Device implements IForceBoard {
250
261
  }
251
262
 
252
263
  /**
253
- * Stops the data stream on the specified device.
264
+ * Stops the data stream on the specified device by setting it to Idle mode.
254
265
  * @returns {Promise<void>} A promise that resolves when the stream is stopped.
255
266
  */
256
267
  stop = async (): Promise<void> => {
@@ -258,26 +269,66 @@ export class ForceBoard extends Device implements IForceBoard {
258
269
  }
259
270
 
260
271
  /**
261
- * Starts streaming data from the specified device.
272
+ * Starts streaming data from the specified device in Streaming Data Mode.
262
273
  * @param {number} [duration=0] - The duration of the stream in milliseconds. If set to 0, stream will continue indefinitely.
263
274
  * @returns {Promise<void>} A promise that resolves when the streaming operation is completed.
264
275
  */
265
276
  stream = async (duration = 0): Promise<void> => {
266
- // Reset download packets
267
- this.downloadPackets.length = 0
268
- // Start streaming data
269
- await this.write("weight", "tx", new Uint8Array([0x04]), duration) // ASCII control character EOT (End of Transmission)
270
- // Stop streaming if duration is set
271
- if (duration !== 0) {
272
- await this.stop()
273
- }
277
+ // Start streaming data - Streaming Data Mode
278
+ await this.write("weight", "tx", this.commands.START_WEIGHT_MEAS, duration)
279
+ }
280
+
281
+ /**
282
+ * Sets the threshold in Lbs for the Quick Start mode.
283
+ * @param {number} thresholdLbs - The threshold value in pounds.
284
+ * @returns {Promise<void>} A promise that resolves when the threshold is set.
285
+ */
286
+ threshold = async (thresholdLbs: number): Promise<void> => {
287
+ const thresholdHex = thresholdLbs.toString(16).padStart(6, "0")
288
+ // 3-byte array from the hex string
289
+ const bytes = new Uint8Array(3)
290
+ bytes[0] = parseInt(thresholdHex.substring(0, 2), 16)
291
+ bytes[1] = parseInt(thresholdHex.substring(2, 4), 16)
292
+ bytes[2] = parseInt(thresholdHex.substring(4, 6), 16)
293
+
294
+ await this.write("forceboard", "threshold", String.fromCharCode(...bytes), 0)
295
+ }
296
+
297
+ /**
298
+ * Tares the Force Board device using a characteristic to zero out the current load value.
299
+ * @returns {Promise<void>} A promise that resolves when the tare operation is completed.
300
+ */
301
+ tareByCharacteristic = async (): Promise<void> => {
302
+ // Send tare command (0x01) to the tare characteristic
303
+ const tareValue = String.fromCharCode(0x01)
304
+ await this.write("forceboard", "tare", tareValue, 0)
305
+ }
306
+
307
+ /**
308
+ * Initiates a tare routine via the Device Mode characteristic.
309
+ * Writes 0x05 to the Device Mode characteristic to zero out the current load value.
310
+ * @returns {Promise<void>} A promise that resolves when the tare operation is completed.
311
+ */
312
+ tareByMode = async (): Promise<void> => {
313
+ await this.write("weight", "tx", this.commands.TARE_SCALE, 0)
274
314
  }
275
315
 
276
316
  /**
277
317
  * Retrieves temperature information from the device.
278
- * @returns {Promise<string>} A Promise that resolves with the manufacturer information,
318
+ * @returns {Promise<string>} A Promise that resolves with the temperature information,
279
319
  */
280
320
  temperature = async (): Promise<string | undefined> => {
281
321
  return await this.read("temperature", "level", 250)
282
322
  }
323
+
324
+ /**
325
+ * Starts the Force Board in Quick Start mode.
326
+ * Writes 0x06 to the Device Mode characteristic.
327
+ * @param {number} [duration=0] - The duration in milliseconds. If set to 0, mode will continue indefinitely.
328
+ * @returns {Promise<void>} A promise that resolves when the operation is completed.
329
+ */
330
+ quick = async (duration = 0): Promise<void> => {
331
+ // Start in Quick Start mode
332
+ await this.write("weight", "tx", this.commands.START_QUICK_MEAS, duration)
333
+ }
283
334
  }