@hangtime/grip-connect 0.6.0 → 0.6.1

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
@@ -102,10 +102,10 @@ document.querySelector("#motherboard").addEventListener("click", async () => {
102
102
  // await motherboard.stop()
103
103
 
104
104
  // Download data as CSV, JSON, or XML (default: CSV) format => timestamp, frame, battery, samples, masses
105
- // motherboard.download('json')
105
+ // await motherboard.download('json')
106
106
 
107
107
  // Optionally disconnect from device after we are done
108
- motherboard.disconnect(Motherboard)
108
+ motherboard.disconnect()
109
109
  },
110
110
  (error) => {
111
111
  // Optinal custom error handeling
package/deno.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hangtime/grip-connect",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "license": "BSD-2-Clause",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
+ export type { IClimbro, IEntralpi, IForceBoard, IKilterBoard, IMotherboard, ImySmartBoard, IProgressor, IWHC06, } from "./interfaces/index.js";
1
2
  export { Climbro, Entralpi, ForceBoard, KilterBoard, Motherboard, mySmartBoard, Progressor, WHC06, } from "./models/index.js";
package/dist/index.js CHANGED
@@ -1,2 +1 @@
1
- // @ts-types="npm:@types/web-bluetooth@^0.0.20"
2
1
  export { Climbro, Entralpi, ForceBoard, KilterBoard, Motherboard, mySmartBoard, Progressor, WHC06, } from "./models/index.js";
@@ -0,0 +1,8 @@
1
+ export type { IClimbro } from "./device/climbro.interface.js";
2
+ export type { IEntralpi } from "./device/entralpi.interface.js";
3
+ export type { IForceBoard } from "./device/forceboard.interface.js";
4
+ export type { IKilterBoard } from "./device/kilterboard.interface.js";
5
+ export type { IMotherboard } from "./device/motherboard.interface.js";
6
+ export type { ImySmartBoard } from "./device/mysmartboard.interface.js";
7
+ export type { IProgressor } from "./device/progressor.interface.js";
8
+ export type { IWHC06 } from "./device/wh-c06.interface.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -74,13 +74,13 @@ export declare class KilterBoard extends Device implements IKilterBoard {
74
74
  /**
75
75
  * Calculates the checksum for a byte array by summing up all bytes ot hre packet in a single-byte variable.
76
76
  * @param data - The array of bytes to calculate the checksum for.
77
- * @returns The calculated checksum value.
77
+ * @returns {number} The calculated checksum value.
78
78
  */
79
79
  private checksum;
80
80
  /**
81
81
  * Wraps a byte array with header and footer bytes for transmission.
82
82
  * @param data - The array of bytes to wrap.
83
- * @returns The wrapped byte array.
83
+ * @returns {number[]} The wrapped byte array.
84
84
  */
85
85
  private wrapBytes;
86
86
  /**
@@ -88,7 +88,7 @@ export declare class KilterBoard extends Device implements IKilterBoard {
88
88
  * The lowest 8 bits of the position get put in the first byte of the group.
89
89
  * The highest 8 bits of the position get put in the second byte of the group.
90
90
  * @param position - The position to encode.
91
- * @returns The encoded byte array representing the position.
91
+ * @returns {number[]} The encoded byte array representing the position.
92
92
  */
93
93
  private encodePosition;
94
94
  /**
@@ -116,7 +116,7 @@ export declare class KilterBoard extends Device implements IKilterBoard {
116
116
  * https://github.com/ramda/ramda/blob/master/source/splitEvery.js
117
117
  * @param {Number} n
118
118
  * @param {Array} list
119
- * @return {Array}
119
+ * @return {Array<number[]>}
120
120
  */
121
121
  private splitEvery;
122
122
  /**
@@ -130,7 +130,7 @@ export class KilterBoard extends Device {
130
130
  /**
131
131
  * Calculates the checksum for a byte array by summing up all bytes ot hre packet in a single-byte variable.
132
132
  * @param data - The array of bytes to calculate the checksum for.
133
- * @returns The calculated checksum value.
133
+ * @returns {number} The calculated checksum value.
134
134
  */
135
135
  checksum(data) {
136
136
  let i = 0;
@@ -142,7 +142,7 @@ export class KilterBoard extends Device {
142
142
  /**
143
143
  * Wraps a byte array with header and footer bytes for transmission.
144
144
  * @param data - The array of bytes to wrap.
145
- * @returns The wrapped byte array.
145
+ * @returns {number[]} The wrapped byte array.
146
146
  */
147
147
  wrapBytes(data) {
148
148
  if (data.length > KilterBoard.messageBodyMaxLength) {
@@ -165,7 +165,7 @@ export class KilterBoard extends Device {
165
165
  * The lowest 8 bits of the position get put in the first byte of the group.
166
166
  * The highest 8 bits of the position get put in the second byte of the group.
167
167
  * @param position - The position to encode.
168
- * @returns The encoded byte array representing the position.
168
+ * @returns {number[]} The encoded byte array representing the position.
169
169
  */
170
170
  encodePosition(position) {
171
171
  const position1 = position & 255;
@@ -237,7 +237,7 @@ export class KilterBoard extends Device {
237
237
  * https://github.com/ramda/ramda/blob/master/source/splitEvery.js
238
238
  * @param {Number} n
239
239
  * @param {Array} list
240
- * @return {Array}
240
+ * @return {Array<number[]>}
241
241
  */
242
242
  splitEvery(n, list) {
243
243
  if (n <= 0) {
@@ -2,6 +2,7 @@ import { Device } from "../device.model.js";
2
2
  import type { IProgressor } from "../../interfaces/device/progressor.interface.js";
3
3
  /**
4
4
  * Represents a Tindeq Progressor device.
5
+ * {@link https://tindeq.com}
5
6
  */
6
7
  export declare class Progressor extends Device implements IProgressor {
7
8
  constructor();
@@ -1,7 +1,6 @@
1
1
  import { Device } from "../device.model.js";
2
2
  /**
3
- * Represents a Tindeq Progressor device.
4
- * {@link https://tindeq.com}
3
+ * Progressor responses
5
4
  */
6
5
  var ProgressorResponses;
7
6
  (function (ProgressorResponses) {
@@ -33,6 +32,7 @@ var ProgressorResponses;
33
32
  })(ProgressorResponses || (ProgressorResponses = {}));
34
33
  /**
35
34
  * Represents a Tindeq Progressor device.
35
+ * {@link https://tindeq.com}
36
36
  */
37
37
  export class Progressor extends Device {
38
38
  constructor() {
@@ -257,13 +257,13 @@ export declare abstract class Device extends BaseModel implements IDevice {
257
257
  * @param {('csv' | 'json' | 'xml')} [format='csv'] - The format in which to download the data.
258
258
  * Defaults to 'csv'. Accepted values are 'csv', 'json', and 'xml'.
259
259
  *
260
- * @returns {void} Initiates a download of the data in the specified format.
261
- * @private
260
+ * @returns {Promise<void>} Resolves when the data has been downloaded/written
261
+ * @public
262
262
  *
263
263
  * @example
264
- * device.download('json');
264
+ * await device.download('json');
265
265
  */
266
- download: (format?: "csv" | "json" | "xml") => void;
266
+ download: (format?: "csv" | "json" | "xml") => Promise<void>;
267
267
  /**
268
268
  * Returns UUIDs of all services associated with the device.
269
269
  * @returns {string[]} Array of service UUIDs.
@@ -372,54 +372,57 @@ export class Device extends BaseModel {
372
372
  * @param {('csv' | 'json' | 'xml')} [format='csv'] - The format in which to download the data.
373
373
  * Defaults to 'csv'. Accepted values are 'csv', 'json', and 'xml'.
374
374
  *
375
- * @returns {void} Initiates a download of the data in the specified format.
376
- * @private
375
+ * @returns {Promise<void>} Resolves when the data has been downloaded/written
376
+ * @public
377
377
  *
378
378
  * @example
379
- * device.download('json');
379
+ * await device.download('json');
380
380
  */
381
- download = (format = "csv") => {
382
- if (typeof document === "undefined" || typeof window === "undefined") {
383
- console.warn("Download is not supported outside a browser environment.");
384
- return;
385
- }
381
+ download = async (format = "csv") => {
386
382
  let content = "";
387
- let mimeType = "";
388
- let fileName = "";
389
383
  if (format === "csv") {
390
384
  content = this.downloadToCSV();
391
- mimeType = "text/csv";
392
385
  }
393
386
  else if (format === "json") {
394
387
  content = this.downloadToJSON();
395
- mimeType = "application/json";
396
388
  }
397
389
  else if (format === "xml") {
398
390
  content = this.downloadToXML();
399
- mimeType = "application/xml";
400
391
  }
401
392
  const now = new Date();
402
393
  // YYYY-MM-DD
403
394
  const date = now.toISOString().split("T")[0];
404
395
  // HH-MM-SS
405
396
  const time = now.toTimeString().split(" ")[0].replace(/:/g, "-");
406
- fileName = `data-export-${date}-${time}.${format}`;
407
- // Create a Blob object containing the data
408
- const blob = new Blob([content], { type: mimeType });
409
- // Create a URL for the Blob
410
- const url = globalThis.URL.createObjectURL(blob);
411
- // Create a link element
412
- const link = document.createElement("a");
413
- // Set link attributes
414
- link.href = url;
415
- link.setAttribute("download", fileName);
416
- // Append link to document body
417
- document.body.appendChild(link);
418
- // Programmatically click the link to trigger the download
419
- link.click();
420
- // Clean up: remove the link and revoke the URL
421
- document.body.removeChild(link);
422
- globalThis.URL.revokeObjectURL(url);
397
+ const fileName = `data-export-${date}-${time}.${format}`;
398
+ if (typeof window !== "undefined" && typeof document !== "undefined") {
399
+ const mimeTypes = {
400
+ csv: "text/csv",
401
+ json: "application/json",
402
+ xml: "application/xml",
403
+ };
404
+ // Create a Blob object containing the data
405
+ const blob = new Blob([content], { type: mimeTypes[format] });
406
+ // Create a URL for the Blob
407
+ const url = globalThis.URL.createObjectURL(blob);
408
+ // Create a link element
409
+ const link = document.createElement("a");
410
+ // Set link attributes
411
+ link.href = url;
412
+ link.setAttribute("download", fileName);
413
+ // Append link to document body
414
+ document.body.appendChild(link);
415
+ // Programmatically click the link to trigger the download
416
+ link.click();
417
+ // Clean up: remove the link and revoke the URL
418
+ document.body.removeChild(link);
419
+ globalThis.URL.revokeObjectURL(url);
420
+ }
421
+ else {
422
+ const { writeFile } = await import("node:fs/promises");
423
+ await writeFile(fileName, content);
424
+ console.log(`File saved as ${fileName}`);
425
+ }
423
426
  };
424
427
  /**
425
428
  * Returns UUIDs of all services associated with the device.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hangtime/grip-connect",
3
- "version": "0.6.0",
4
- "description": "Griptonite Motherboard, Tindeq Progressor, PitchSix Force Board, WHC-06, Entralpi, Climbro, mySmartBoard: Web Bluetooth API Force-Sensing strength analysis for climbers",
3
+ "version": "0.6.1",
4
+ "description": "Griptonite Motherboard, Tindeq Progressor, PitchSix Force Board, WHC-06, Entralpi, Climbro, mySmartBoard: Web + Node Bluetooth API Force-Sensing strength analysis for climbers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -1,4 +1,13 @@
1
- // @ts-types="npm:@types/web-bluetooth@^0.0.20"
1
+ export type {
2
+ IClimbro,
3
+ IEntralpi,
4
+ IForceBoard,
5
+ IKilterBoard,
6
+ IMotherboard,
7
+ ImySmartBoard,
8
+ IProgressor,
9
+ IWHC06,
10
+ } from "./interfaces/index.js"
2
11
 
3
12
  export {
4
13
  Climbro,
@@ -0,0 +1,15 @@
1
+ export type { IClimbro } from "./device/climbro.interface.js"
2
+
3
+ export type { IEntralpi } from "./device/entralpi.interface.js"
4
+
5
+ export type { IForceBoard } from "./device/forceboard.interface.js"
6
+
7
+ export type { IKilterBoard } from "./device/kilterboard.interface.js"
8
+
9
+ export type { IMotherboard } from "./device/motherboard.interface.js"
10
+
11
+ export type { ImySmartBoard } from "./device/mysmartboard.interface.js"
12
+
13
+ export type { IProgressor } from "./device/progressor.interface.js"
14
+
15
+ export type { IWHC06 } from "./device/wh-c06.interface.js"
@@ -136,9 +136,9 @@ export class KilterBoard extends Device implements IKilterBoard {
136
136
  /**
137
137
  * Calculates the checksum for a byte array by summing up all bytes ot hre packet in a single-byte variable.
138
138
  * @param data - The array of bytes to calculate the checksum for.
139
- * @returns The calculated checksum value.
139
+ * @returns {number} The calculated checksum value.
140
140
  */
141
- private checksum(data: number[]) {
141
+ private checksum(data: number[]): number {
142
142
  let i = 0
143
143
  for (const value of data) {
144
144
  i = (i + value) & 255
@@ -149,9 +149,9 @@ export class KilterBoard extends Device implements IKilterBoard {
149
149
  /**
150
150
  * Wraps a byte array with header and footer bytes for transmission.
151
151
  * @param data - The array of bytes to wrap.
152
- * @returns The wrapped byte array.
152
+ * @returns {number[]} The wrapped byte array.
153
153
  */
154
- private wrapBytes(data: number[]) {
154
+ private wrapBytes(data: number[]): number[] {
155
155
  if (data.length > KilterBoard.messageBodyMaxLength) {
156
156
  return []
157
157
  }
@@ -173,9 +173,9 @@ export class KilterBoard extends Device implements IKilterBoard {
173
173
  * The lowest 8 bits of the position get put in the first byte of the group.
174
174
  * The highest 8 bits of the position get put in the second byte of the group.
175
175
  * @param position - The position to encode.
176
- * @returns The encoded byte array representing the position.
176
+ * @returns {number[]} The encoded byte array representing the position.
177
177
  */
178
- private encodePosition(position: number) {
178
+ private encodePosition(position: number): number[] {
179
179
  const position1 = position & 255
180
180
  const position2 = (position & 65280) >> 8
181
181
 
@@ -188,7 +188,7 @@ export class KilterBoard extends Device implements IKilterBoard {
188
188
  * @param color - The color string in hexadecimal format (e.g., 'FFFFFF').
189
189
  * @returns The encoded /compressed color value.
190
190
  */
191
- private encodeColor(color: string) {
191
+ private encodeColor(color: string): number {
192
192
  const substring = color.substring(0, 2)
193
193
  const substring2 = color.substring(2, 4)
194
194
 
@@ -209,7 +209,7 @@ export class KilterBoard extends Device implements IKilterBoard {
209
209
  * @param ledColor - The color of the LED in hexadecimal format (e.g., 'FFFFFF').
210
210
  * @returns The encoded byte array representing the placement.
211
211
  */
212
- private encodePlacement(position: number, ledColor: string) {
212
+ private encodePlacement(position: number, ledColor: string): number[] {
213
213
  return [...this.encodePosition(position), this.encodeColor(ledColor)]
214
214
  }
215
215
 
@@ -218,7 +218,7 @@ export class KilterBoard extends Device implements IKilterBoard {
218
218
  * @param {{ position: number; role_id: number }[]} climbPlacementList - The list of climb placements containing position and role ID.
219
219
  * @returns {number[]} The final byte array ready for transmission.
220
220
  */
221
- private prepBytesV3(climbPlacementList: { position: number; role_id: number }[]) {
221
+ private prepBytesV3(climbPlacementList: { position: number; role_id: number }[]): number[] {
222
222
  const resultArray: number[][] = []
223
223
  let tempArray: number[] = [KilterBoardPacket.V3_MIDDLE]
224
224
 
@@ -257,9 +257,9 @@ export class KilterBoard extends Device implements IKilterBoard {
257
257
  * https://github.com/ramda/ramda/blob/master/source/splitEvery.js
258
258
  * @param {Number} n
259
259
  * @param {Array} list
260
- * @return {Array}
260
+ * @return {Array<number[]>}
261
261
  */
262
- private splitEvery(n: number, list: number[]) {
262
+ private splitEvery(n: number, list: number[]): number[][] {
263
263
  if (n <= 0) {
264
264
  throw new Error("First argument to splitEvery must be a positive integer")
265
265
  }
@@ -2,8 +2,7 @@ import { Device } from "../device.model.js"
2
2
  import type { IProgressor } from "../../interfaces/device/progressor.interface.js"
3
3
 
4
4
  /**
5
- * Represents a Tindeq Progressor device.
6
- * {@link https://tindeq.com}
5
+ * Progressor responses
7
6
  */
8
7
  enum ProgressorResponses {
9
8
  /**
@@ -39,6 +38,7 @@ enum ProgressorResponses {
39
38
 
40
39
  /**
41
40
  * Represents a Tindeq Progressor device.
41
+ * {@link https://tindeq.com}
42
42
  */
43
43
  export class Progressor extends Device implements IProgressor {
44
44
  constructor() {
@@ -420,30 +420,21 @@ export abstract class Device extends BaseModel implements IDevice {
420
420
  * @param {('csv' | 'json' | 'xml')} [format='csv'] - The format in which to download the data.
421
421
  * Defaults to 'csv'. Accepted values are 'csv', 'json', and 'xml'.
422
422
  *
423
- * @returns {void} Initiates a download of the data in the specified format.
424
- * @private
423
+ * @returns {Promise<void>} Resolves when the data has been downloaded/written
424
+ * @public
425
425
  *
426
426
  * @example
427
- * device.download('json');
427
+ * await device.download('json');
428
428
  */
429
- download = (format: "csv" | "json" | "xml" = "csv"): void => {
430
- if (typeof document === "undefined" || typeof window === "undefined") {
431
- console.warn("Download is not supported outside a browser environment.")
432
- return
433
- }
429
+ download = async (format: "csv" | "json" | "xml" = "csv"): Promise<void> => {
434
430
  let content = ""
435
- let mimeType = ""
436
- let fileName = ""
437
431
 
438
432
  if (format === "csv") {
439
433
  content = this.downloadToCSV()
440
- mimeType = "text/csv"
441
434
  } else if (format === "json") {
442
435
  content = this.downloadToJSON()
443
- mimeType = "application/json"
444
436
  } else if (format === "xml") {
445
437
  content = this.downloadToXML()
446
- mimeType = "application/xml"
447
438
  }
448
439
 
449
440
  const now = new Date()
@@ -452,30 +443,41 @@ export abstract class Device extends BaseModel implements IDevice {
452
443
  // HH-MM-SS
453
444
  const time = now.toTimeString().split(" ")[0].replace(/:/g, "-")
454
445
 
455
- fileName = `data-export-${date}-${time}.${format}`
446
+ const fileName = `data-export-${date}-${time}.${format}`
456
447
 
457
- // Create a Blob object containing the data
458
- const blob = new Blob([content], { type: mimeType })
448
+ if (typeof window !== "undefined" && typeof document !== "undefined") {
449
+ const mimeTypes = {
450
+ csv: "text/csv",
451
+ json: "application/json",
452
+ xml: "application/xml",
453
+ }
459
454
 
460
- // Create a URL for the Blob
461
- const url = globalThis.URL.createObjectURL(blob)
455
+ // Create a Blob object containing the data
456
+ const blob = new Blob([content], { type: mimeTypes[format] })
457
+ // Create a URL for the Blob
458
+ const url = globalThis.URL.createObjectURL(blob)
462
459
 
463
- // Create a link element
464
- const link = document.createElement("a")
460
+ // Create a link element
461
+ const link = document.createElement("a")
465
462
 
466
- // Set link attributes
467
- link.href = url
468
- link.setAttribute("download", fileName)
463
+ // Set link attributes
464
+ link.href = url
465
+ link.setAttribute("download", fileName)
469
466
 
470
- // Append link to document body
471
- document.body.appendChild(link)
467
+ // Append link to document body
468
+ document.body.appendChild(link)
472
469
 
473
- // Programmatically click the link to trigger the download
474
- link.click()
470
+ // Programmatically click the link to trigger the download
471
+ link.click()
475
472
 
476
- // Clean up: remove the link and revoke the URL
477
- document.body.removeChild(link)
478
- globalThis.URL.revokeObjectURL(url)
473
+ // Clean up: remove the link and revoke the URL
474
+ document.body.removeChild(link)
475
+ globalThis.URL.revokeObjectURL(url)
476
+ } else {
477
+ const { writeFile } = await import("node:fs/promises")
478
+ await writeFile(fileName, content)
479
+ console.log(`File saved as ${fileName}`)
480
+ }
479
481
  }
480
482
 
481
483
  /**