@hangtime/grip-connect 0.9.0 → 0.10.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 +8 -4
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/interfaces/callback.interface.d.ts +37 -31
- package/dist/cjs/interfaces/callback.interface.d.ts.map +1 -1
- package/dist/cjs/interfaces/device/kilterboard.interface.d.ts +3 -2
- package/dist/cjs/interfaces/device/kilterboard.interface.d.ts.map +1 -1
- package/dist/cjs/interfaces/device.interface.d.ts +2 -2
- package/dist/cjs/interfaces/device.interface.d.ts.map +1 -1
- package/dist/cjs/models/device/climbro.model.d.ts.map +1 -1
- package/dist/cjs/models/device/climbro.model.js +4 -8
- package/dist/cjs/models/device/climbro.model.js.map +1 -1
- package/dist/cjs/models/device/entralpi.model.d.ts.map +1 -1
- package/dist/cjs/models/device/entralpi.model.js +5 -9
- package/dist/cjs/models/device/entralpi.model.js.map +1 -1
- package/dist/cjs/models/device/forceboard.model.d.ts.map +1 -1
- package/dist/cjs/models/device/forceboard.model.js +5 -9
- package/dist/cjs/models/device/forceboard.model.js.map +1 -1
- package/dist/cjs/models/device/kilterboard.model.d.ts +5 -3
- package/dist/cjs/models/device/kilterboard.model.d.ts.map +1 -1
- package/dist/cjs/models/device/kilterboard.model.js +52 -16
- package/dist/cjs/models/device/kilterboard.model.js.map +1 -1
- package/dist/cjs/models/device/motherboard.model.d.ts +7 -0
- package/dist/cjs/models/device/motherboard.model.d.ts.map +1 -1
- package/dist/cjs/models/device/motherboard.model.js +28 -15
- package/dist/cjs/models/device/motherboard.model.js.map +1 -1
- package/dist/cjs/models/device/pb-700bt.model.d.ts +63 -0
- package/dist/cjs/models/device/pb-700bt.model.d.ts.map +1 -0
- package/dist/cjs/models/device/pb-700bt.model.js +247 -0
- package/dist/cjs/models/device/pb-700bt.model.js.map +1 -0
- package/dist/cjs/models/device/progressor.model.d.ts.map +1 -1
- package/dist/cjs/models/device/progressor.model.js +4 -8
- package/dist/cjs/models/device/progressor.model.js.map +1 -1
- package/dist/cjs/models/device/smartboard-pro.model.d.ts +8 -0
- package/dist/cjs/models/device/smartboard-pro.model.d.ts.map +1 -1
- package/dist/cjs/models/device/smartboard-pro.model.js +62 -6
- package/dist/cjs/models/device/smartboard-pro.model.js.map +1 -1
- package/dist/cjs/models/device/wh-c06.model.d.ts.map +1 -1
- package/dist/cjs/models/device/wh-c06.model.js +5 -9
- package/dist/cjs/models/device/wh-c06.model.js.map +1 -1
- package/dist/cjs/models/device.model.d.ts +72 -12
- package/dist/cjs/models/device.model.d.ts.map +1 -1
- package/dist/cjs/models/device.model.js +127 -5
- package/dist/cjs/models/device.model.js.map +1 -1
- package/dist/cjs/models/index.d.ts +2 -1
- package/dist/cjs/models/index.d.ts.map +1 -1
- package/dist/cjs/models/index.js +4 -1
- package/dist/cjs/models/index.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/callback.interface.d.ts +37 -31
- package/dist/interfaces/callback.interface.d.ts.map +1 -1
- package/dist/interfaces/device/kilterboard.interface.d.ts +3 -2
- package/dist/interfaces/device/kilterboard.interface.d.ts.map +1 -1
- package/dist/interfaces/device.interface.d.ts +2 -2
- package/dist/interfaces/device.interface.d.ts.map +1 -1
- package/dist/models/device/climbro.model.d.ts.map +1 -1
- package/dist/models/device/climbro.model.js +4 -8
- package/dist/models/device/climbro.model.js.map +1 -1
- package/dist/models/device/entralpi.model.d.ts.map +1 -1
- package/dist/models/device/entralpi.model.js +5 -9
- package/dist/models/device/entralpi.model.js.map +1 -1
- package/dist/models/device/forceboard.model.d.ts.map +1 -1
- package/dist/models/device/forceboard.model.js +5 -9
- package/dist/models/device/forceboard.model.js.map +1 -1
- package/dist/models/device/kilterboard.model.d.ts +5 -3
- package/dist/models/device/kilterboard.model.d.ts.map +1 -1
- package/dist/models/device/kilterboard.model.js +52 -16
- package/dist/models/device/kilterboard.model.js.map +1 -1
- package/dist/models/device/motherboard.model.d.ts +7 -0
- package/dist/models/device/motherboard.model.d.ts.map +1 -1
- package/dist/models/device/motherboard.model.js +28 -15
- package/dist/models/device/motherboard.model.js.map +1 -1
- package/dist/models/device/pb-700bt.model.d.ts +63 -0
- package/dist/models/device/pb-700bt.model.d.ts.map +1 -0
- package/dist/models/device/pb-700bt.model.js +243 -0
- package/dist/models/device/pb-700bt.model.js.map +1 -0
- package/dist/models/device/progressor.model.d.ts.map +1 -1
- package/dist/models/device/progressor.model.js +4 -8
- package/dist/models/device/progressor.model.js.map +1 -1
- package/dist/models/device/smartboard-pro.model.d.ts +8 -0
- package/dist/models/device/smartboard-pro.model.d.ts.map +1 -1
- package/dist/models/device/smartboard-pro.model.js +62 -6
- package/dist/models/device/smartboard-pro.model.js.map +1 -1
- package/dist/models/device/wh-c06.model.d.ts.map +1 -1
- package/dist/models/device/wh-c06.model.js +5 -9
- package/dist/models/device/wh-c06.model.js.map +1 -1
- package/dist/models/device.model.d.ts +72 -12
- package/dist/models/device.model.d.ts.map +1 -1
- package/dist/models/device.model.js +149 -14
- package/dist/models/device.model.js.map +1 -1
- package/dist/models/index.d.ts +2 -1
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +2 -1
- package/dist/models/index.js.map +1 -1
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/package.json +4 -1
- package/src/index.ts +11 -0
- package/src/interfaces/callback.interface.ts +41 -31
- package/src/interfaces/device/kilterboard.interface.ts +2 -2
- package/src/interfaces/device.interface.ts +2 -2
- package/src/models/device/climbro.model.ts +4 -8
- package/src/models/device/entralpi.model.ts +5 -9
- package/src/models/device/forceboard.model.ts +5 -9
- package/src/models/device/kilterboard.model.ts +56 -19
- package/src/models/device/motherboard.model.ts +32 -15
- package/src/models/device/pb-700bt.model.ts +263 -0
- package/src/models/device/progressor.model.ts +4 -8
- package/src/models/device/smartboard-pro.model.ts +73 -6
- package/src/models/device/wh-c06.model.ts +5 -9
- package/src/models/device.model.ts +179 -16
- package/src/models/index.ts +3 -1
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { BaseModel } from "./../models/base.model.js"
|
|
2
2
|
import type { IDevice, Service } from "../interfaces/device.interface.js"
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
ActiveCallback,
|
|
5
|
+
ForceMeasurement,
|
|
6
|
+
ForceUnit,
|
|
7
|
+
NotifyCallback,
|
|
8
|
+
WriteCallback,
|
|
9
|
+
} from "../interfaces/callback.interface.js"
|
|
4
10
|
import type { DownloadPacket } from "../interfaces/download.interface.js"
|
|
5
11
|
import type { Commands } from "../interfaces/command.interface.js"
|
|
6
12
|
|
|
@@ -67,26 +73,55 @@ export abstract class Device extends BaseModel implements IDevice {
|
|
|
67
73
|
}
|
|
68
74
|
|
|
69
75
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
76
|
+
* Highest instantaneous force (peak) recorded in the session; may be negative.
|
|
77
|
+
* Initialized to Number.NEGATIVE_INFINITY so the first sample sets the peak.
|
|
78
|
+
* @type {number}
|
|
72
79
|
* @protected
|
|
73
80
|
*/
|
|
74
|
-
protected
|
|
81
|
+
protected peak: number
|
|
75
82
|
|
|
76
83
|
/**
|
|
77
|
-
*
|
|
78
|
-
* @type {
|
|
84
|
+
* Mean (average) force over the session, initialized to 0.
|
|
85
|
+
* @type {number}
|
|
79
86
|
* @protected
|
|
80
87
|
*/
|
|
81
|
-
protected
|
|
88
|
+
protected mean: number
|
|
82
89
|
|
|
83
90
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
91
|
+
* Display unit for force measurements.
|
|
92
|
+
* @type {ForceUnit}
|
|
93
|
+
* @protected
|
|
94
|
+
*/
|
|
95
|
+
protected unit: ForceUnit
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Optional sampling rate in Hz when known or calculated from notification timestamps.
|
|
99
|
+
* @type {number | undefined}
|
|
100
|
+
* @protected
|
|
101
|
+
*/
|
|
102
|
+
protected samplingRateHz?: number
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Start time of the current rate measurement interval.
|
|
106
|
+
* @type {number}
|
|
107
|
+
* @private
|
|
108
|
+
*/
|
|
109
|
+
private rateIntervalStart = 0
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Number of samples in the current rate measurement interval.
|
|
113
|
+
* @type {number}
|
|
114
|
+
* @private
|
|
115
|
+
*/
|
|
116
|
+
private rateIntervalSamples = 0
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Running sum of force values for the session.
|
|
120
|
+
* Used to calculate mean (average) force.
|
|
86
121
|
* @type {number}
|
|
87
122
|
* @protected
|
|
88
123
|
*/
|
|
89
|
-
protected
|
|
124
|
+
protected sum: number
|
|
90
125
|
|
|
91
126
|
/**
|
|
92
127
|
* Number of data points received from the device.
|
|
@@ -135,13 +170,13 @@ export abstract class Device extends BaseModel implements IDevice {
|
|
|
135
170
|
private tareDuration = 5000
|
|
136
171
|
|
|
137
172
|
/**
|
|
138
|
-
* Optional callback for handling
|
|
173
|
+
* Optional callback for handling mass/force data notifications.
|
|
139
174
|
* @callback NotifyCallback
|
|
140
|
-
* @param {
|
|
175
|
+
* @param {ForceMeasurement} data - The force measurement passed to the callback.
|
|
141
176
|
* @type {NotifyCallback | undefined}
|
|
142
177
|
* @protected
|
|
143
178
|
*/
|
|
144
|
-
protected notifyCallback: NotifyCallback = (data:
|
|
179
|
+
protected notifyCallback: NotifyCallback = (data: ForceMeasurement) => console.log(data)
|
|
145
180
|
|
|
146
181
|
/**
|
|
147
182
|
* Optional callback for handling write operations.
|
|
@@ -189,15 +224,121 @@ export abstract class Device extends BaseModel implements IDevice {
|
|
|
189
224
|
this.bluetooth = device.bluetooth
|
|
190
225
|
}
|
|
191
226
|
|
|
192
|
-
this.
|
|
193
|
-
this.
|
|
194
|
-
this.
|
|
227
|
+
this.peak = Number.NEGATIVE_INFINITY
|
|
228
|
+
this.mean = 0
|
|
229
|
+
this.sum = 0
|
|
195
230
|
this.dataPointCount = 0
|
|
231
|
+
this.unit = "kg"
|
|
232
|
+
|
|
233
|
+
// Reset sampling rate calculation state
|
|
234
|
+
this.rateIntervalStart = 0
|
|
235
|
+
this.rateIntervalSamples = 0
|
|
196
236
|
|
|
197
237
|
this.createdAt = new Date()
|
|
198
238
|
this.updatedAt = new Date()
|
|
199
239
|
}
|
|
200
240
|
|
|
241
|
+
/**
|
|
242
|
+
* Builds a ForceMeasurement for a single zone (e.g. left/center/right).
|
|
243
|
+
* With one argument, current/peak/mean are all set to that value.
|
|
244
|
+
* With three arguments, uses the given current, peak, and mean for the zone.
|
|
245
|
+
* @param valueOrCurrent - Force value, or current force for this zone
|
|
246
|
+
* @param peak - Optional peak for this zone (required if mean is provided)
|
|
247
|
+
* @param mean - Optional mean for this zone
|
|
248
|
+
* @returns ForceMeasurement (no nested distribution)
|
|
249
|
+
* @protected
|
|
250
|
+
*/
|
|
251
|
+
protected buildZoneMeasurement(valueOrCurrent: number, peak?: number, mean?: number): ForceMeasurement {
|
|
252
|
+
const useFullStats = peak !== undefined && mean !== undefined
|
|
253
|
+
const current = valueOrCurrent
|
|
254
|
+
const zonePeak = useFullStats ? (peak === 0 && current < 0 ? current : peak) : valueOrCurrent
|
|
255
|
+
const zoneMean = useFullStats ? mean : valueOrCurrent
|
|
256
|
+
const zone: ForceMeasurement = {
|
|
257
|
+
unit: this.unit,
|
|
258
|
+
timestamp: Date.now(),
|
|
259
|
+
current,
|
|
260
|
+
peak: zonePeak,
|
|
261
|
+
mean: zoneMean,
|
|
262
|
+
}
|
|
263
|
+
if (this.samplingRateHz !== undefined) {
|
|
264
|
+
zone.samplingRateHz = this.samplingRateHz
|
|
265
|
+
}
|
|
266
|
+
return zone
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Interval duration (ms) for sampling rate calculation.
|
|
271
|
+
* @private
|
|
272
|
+
* @readonly
|
|
273
|
+
*/
|
|
274
|
+
private static readonly RATE_INTERVAL_MS = 1000
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Calculates sampling rate: samples per second.
|
|
278
|
+
* Uses fixed intervals to avoid sliding window edge effects.
|
|
279
|
+
* @private
|
|
280
|
+
*/
|
|
281
|
+
private updateSamplingRate(): void {
|
|
282
|
+
const now = Date.now()
|
|
283
|
+
|
|
284
|
+
if (this.rateIntervalStart === 0) {
|
|
285
|
+
this.rateIntervalStart = now
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
this.rateIntervalSamples++
|
|
289
|
+
|
|
290
|
+
const elapsed = now - this.rateIntervalStart
|
|
291
|
+
if (elapsed >= Device.RATE_INTERVAL_MS) {
|
|
292
|
+
this.samplingRateHz = Math.round((this.rateIntervalSamples / elapsed) * 1000)
|
|
293
|
+
this.rateIntervalStart = now
|
|
294
|
+
this.rateIntervalSamples = 0
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Builds a ForceMeasurement payload with unit and timestamp for notify callbacks.
|
|
300
|
+
* @param current - Current force at this sample
|
|
301
|
+
* @param distribution - Optional zone distribution: numbers (converted via buildZoneMeasurement) or full ForceMeasurement per zone
|
|
302
|
+
* @returns ForceMeasurement
|
|
303
|
+
* @protected
|
|
304
|
+
*/
|
|
305
|
+
protected buildForceMeasurement(
|
|
306
|
+
current: number,
|
|
307
|
+
distribution?: {
|
|
308
|
+
left?: ForceMeasurement
|
|
309
|
+
center?: ForceMeasurement
|
|
310
|
+
right?: ForceMeasurement
|
|
311
|
+
},
|
|
312
|
+
): ForceMeasurement {
|
|
313
|
+
this.updateSamplingRate()
|
|
314
|
+
const payload: ForceMeasurement = {
|
|
315
|
+
unit: this.unit,
|
|
316
|
+
timestamp: Date.now(),
|
|
317
|
+
current,
|
|
318
|
+
peak: this.peak,
|
|
319
|
+
mean: this.mean,
|
|
320
|
+
}
|
|
321
|
+
if (this.samplingRateHz !== undefined) {
|
|
322
|
+
payload.samplingRateHz = this.samplingRateHz
|
|
323
|
+
}
|
|
324
|
+
if (
|
|
325
|
+
distribution !== undefined &&
|
|
326
|
+
(distribution.left !== undefined || distribution.center !== undefined || distribution.right !== undefined)
|
|
327
|
+
) {
|
|
328
|
+
payload.distribution = {}
|
|
329
|
+
if (distribution.left !== undefined) {
|
|
330
|
+
payload.distribution.left = distribution.left
|
|
331
|
+
}
|
|
332
|
+
if (distribution.center !== undefined) {
|
|
333
|
+
payload.distribution.center = distribution.center
|
|
334
|
+
}
|
|
335
|
+
if (distribution.right !== undefined) {
|
|
336
|
+
payload.distribution.right = distribution.right
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return payload
|
|
340
|
+
}
|
|
341
|
+
|
|
201
342
|
/**
|
|
202
343
|
* Sets the callback function to be called when the activity status changes,
|
|
203
344
|
* and optionally sets the configuration for threshold and duration.
|
|
@@ -276,6 +417,28 @@ export abstract class Device extends BaseModel implements IDevice {
|
|
|
276
417
|
|
|
277
418
|
const bluetooth = await this.getBluetooth()
|
|
278
419
|
|
|
420
|
+
// Experiment: Reconnect to known devices, enable these Chrome flags:
|
|
421
|
+
// - chrome://flags/#enable-experimental-web-platform-features → enables getDevices() API
|
|
422
|
+
// - chrome://flags/#enable-web-bluetooth-new-permissions-backend → ensures it returns all permitted devices, not just connected ones
|
|
423
|
+
// let reconnectDevice: BluetoothDevice | undefined
|
|
424
|
+
// if (typeof bluetooth.getDevices === "function") {
|
|
425
|
+
// const devices: BluetoothDevice[] = await bluetooth.getDevices()
|
|
426
|
+
// if (devices.length > 0 && this.filters.length > 0) {
|
|
427
|
+
// reconnectDevice = devices.find((device) => {
|
|
428
|
+
// if (!device.name) return false
|
|
429
|
+
// const d = device
|
|
430
|
+
// return this.filters.some(
|
|
431
|
+
// (f) => (f.name && d.name === f.name) || (f.namePrefix && d.name?.startsWith(f.namePrefix)),
|
|
432
|
+
// )
|
|
433
|
+
// })
|
|
434
|
+
// }
|
|
435
|
+
// if (reconnectDevice) {
|
|
436
|
+
// this.bluetooth = reconnectDevice
|
|
437
|
+
// // It's currently impossible to call this.bluetooth.gatt.connect() here.
|
|
438
|
+
// // After restarting the Browser, it will always give: "Bluetooth Device is no longer in range."
|
|
439
|
+
// }
|
|
440
|
+
// }
|
|
441
|
+
|
|
279
442
|
this.bluetooth = await bluetooth.requestDevice({
|
|
280
443
|
filters: this.filters,
|
|
281
444
|
optionalServices: deviceServices,
|
package/src/models/index.ts
CHANGED
|
@@ -4,12 +4,14 @@ export { Entralpi } from "./device/entralpi.model.js"
|
|
|
4
4
|
|
|
5
5
|
export { ForceBoard } from "./device/forceboard.model.js"
|
|
6
6
|
|
|
7
|
-
export { KilterBoard } from "./device/kilterboard.model.js"
|
|
7
|
+
export { KilterBoard, KilterBoardPlacementRoles } from "./device/kilterboard.model.js"
|
|
8
8
|
|
|
9
9
|
export { Motherboard } from "./device/motherboard.model.js"
|
|
10
10
|
|
|
11
11
|
export { mySmartBoard } from "./device/mysmartboard.model.js"
|
|
12
12
|
|
|
13
|
+
export { PB700BT } from "./device/pb-700bt.model.js"
|
|
14
|
+
|
|
13
15
|
export { Progressor } from "./device/progressor.model.js"
|
|
14
16
|
|
|
15
17
|
export { SmartBoardPro } from "./device/smartboard-pro.model.js"
|