@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 +1 -0
- package/deno.json +1 -1
- package/dist/interfaces/command.interface.d.ts +6 -0
- package/dist/interfaces/device/forceboard.interface.d.ts +29 -3
- package/dist/models/device/forceboard.model.d.ts +27 -3
- package/dist/models/device/forceboard.model.js +94 -51
- package/package.json +1 -1
- package/src/interfaces/command.interface.ts +9 -0
- package/src/interfaces/device/forceboard.interface.ts +33 -3
- package/src/models/device/forceboard.model.ts +102 -51
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
|
@@ -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
|
|
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
|
|
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: "
|
|
109
|
+
name: "Force Data",
|
|
110
110
|
id: "rx",
|
|
111
111
|
uuid: "9a88d682-8df2-4afe-9e0d-c2bbbe773dd0",
|
|
112
112
|
},
|
|
113
113
|
{
|
|
114
|
-
name: "
|
|
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: "
|
|
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
|
|
146
|
+
name: "Weight Service",
|
|
147
147
|
id: "weight",
|
|
148
148
|
uuid: "467a8516-6e39-11eb-9439-0242ac130002",
|
|
149
149
|
characteristics: [
|
|
150
150
|
{
|
|
151
|
-
name: "
|
|
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
|
-
|
|
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
|
-
//
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
-
//
|
|
254
|
-
this.
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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
|
|
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.
|
|
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
|
|
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: "
|
|
111
|
+
name: "Force Data",
|
|
112
112
|
id: "rx",
|
|
113
113
|
uuid: "9a88d682-8df2-4afe-9e0d-c2bbbe773dd0",
|
|
114
114
|
},
|
|
115
115
|
{
|
|
116
|
-
name: "
|
|
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: "
|
|
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
|
|
148
|
+
name: "Weight Service",
|
|
149
149
|
id: "weight",
|
|
150
150
|
uuid: "467a8516-6e39-11eb-9439-0242ac130002",
|
|
151
151
|
characteristics: [
|
|
152
152
|
{
|
|
153
|
-
name: "
|
|
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
|
-
|
|
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
|
-
|
|
212
|
-
|
|
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
|
-
|
|
215
|
-
|
|
216
|
-
this.massTotalSum += currentMassTotal
|
|
217
|
-
this.dataPointCount++
|
|
221
|
+
// Update massMax
|
|
222
|
+
this.massMax = Math.max(Number(this.massMax), numericData).toFixed(1)
|
|
218
223
|
|
|
219
|
-
|
|
220
|
-
|
|
224
|
+
// Update running sum and count
|
|
225
|
+
const currentMassTotal = Math.max(-1000, numericData)
|
|
226
|
+
this.massTotalSum += currentMassTotal
|
|
227
|
+
this.dataPointCount++
|
|
221
228
|
|
|
222
|
-
|
|
223
|
-
|
|
229
|
+
// Calculate the average dynamically
|
|
230
|
+
this.massAverage = (this.massTotalSum / this.dataPointCount).toFixed(1)
|
|
224
231
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
-
//
|
|
267
|
-
this.
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
|
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
|
}
|