@hangtime/grip-connect 0.2.7 → 0.3.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.
Files changed (41) hide show
  1. package/README.md +15 -12
  2. package/package.json +1 -1
  3. package/src/commands/index.d.ts +2 -1
  4. package/src/commands/index.js +2 -1
  5. package/src/commands/index.ts +3 -1
  6. package/src/commands/{smartboard.d.ts → musclemeter.d.ts} +1 -1
  7. package/src/commands/{smartboard.js → musclemeter.js} +1 -1
  8. package/src/commands/{smartboard.ts → musclemeter.ts} +1 -1
  9. package/src/commands/mysmartboard.d.ts +6 -0
  10. package/src/commands/mysmartboard.js +5 -0
  11. package/src/commands/mysmartboard.ts +6 -0
  12. package/src/commands/progressor.d.ts +2 -0
  13. package/src/commands/progressor.js +3 -1
  14. package/src/commands/progressor.ts +3 -1
  15. package/src/data.js +23 -2
  16. package/src/data.ts +25 -13
  17. package/src/devices/climbro.d.ts +1 -1
  18. package/src/devices/climbro.js +1 -1
  19. package/src/devices/climbro.ts +1 -1
  20. package/src/devices/index.d.ts +2 -1
  21. package/src/devices/index.js +2 -1
  22. package/src/devices/index.ts +3 -1
  23. package/src/devices/musclemeter.d.ts +6 -0
  24. package/src/devices/musclemeter.js +8 -0
  25. package/src/devices/musclemeter.ts +10 -0
  26. package/src/devices/mysmartboard.d.ts +6 -0
  27. package/src/devices/mysmartboard.js +8 -0
  28. package/src/devices/mysmartboard.ts +10 -0
  29. package/src/download.d.ts +19 -0
  30. package/src/download.js +50 -0
  31. package/src/download.ts +73 -0
  32. package/src/index.d.ts +2 -1
  33. package/src/index.js +3 -1
  34. package/src/index.ts +4 -1
  35. package/src/stream.js +4 -0
  36. package/src/stream.ts +4 -0
  37. package/src/write.js +1 -1
  38. package/src/write.ts +1 -1
  39. package/src/devices/smartboard.d.ts +0 -6
  40. package/src/devices/smartboard.js +0 -8
  41. package/src/devices/smartboard.ts +0 -10
package/README.md CHANGED
@@ -5,8 +5,8 @@
5
5
  The objective of this project is to create a Web Bluetooth API client that can establish connections with various
6
6
  Force-Sensing Hangboards / Plates used by climbers for strength measurement. Examples of such hangboards include the
7
7
  [Griptonite Motherboard](https://griptonite.io/shop/motherboard/), [Climbro](https://climbro.com/),
8
- [SmartBoard](https://www.smartboard-climbing.com/), [Entralpi](https://entralpi.com/) or
9
- [Tindeq Progressor](https://tindeq.com/)
8
+ [mySmartBoard](https://www.smartboard-climbing.com/), [Entralpi](https://entralpi.com/),
9
+ [Tindeq Progressor](https://tindeq.com/) or [MAT Muscle Meter](https://www.matassessment.com/musclemeter)
10
10
 
11
11
  Learn more: [Docs](https://stevie-ray.github.io/hangtime-grip-connect/) -
12
12
  [Browser Support](https://caniuse.com/web-bluetooth)
@@ -58,6 +58,9 @@ motherboardButton.addEventListener("click", () => {
58
58
  // Manually call stop method if stream is continues
59
59
  // await stop(Motherboard)
60
60
 
61
+ // Download data to CSV: format => timestamp, frame, battery, samples, masses
62
+ // download()
63
+
61
64
  // Disconnect from device after we are done
62
65
  disconnect(Motherboard)
63
66
  })
@@ -74,24 +77,24 @@ available services with us.
74
77
 
75
78
  - ✅ Griptonite Motherboard
76
79
  - ✅ Tindeq Progressor
77
- - Entralpi
80
+ - ☑️ Entralpi (not verified)
78
81
  - ➡️ Climbro
79
- - ➡️ SmartBoard
82
+ - ➡️ mySmartBoard
83
+ - ➡️ MAT Muscle Meter
80
84
 
81
85
  ### Features
82
86
 
83
- - ✅ Connect
84
- - ✅ Disconnect
85
- - ✅ Start data stream (live data)
86
- - ✅ Stop data stream
87
+ - ✅ Connect / Disconnect
88
+ - ✅ Start / Stop data stream
87
89
  - ✅ Battery status
88
90
  - ✅ Read calibration
89
- - ✅ Device info (firmware / serial etc.)
91
+ - ✅ Device info: firmware / serial etc.
90
92
  - ✅ Check if device is connected
91
- - ➡️ Peak load
93
+ - Peak / Average load
94
+ - ✅️ Tare / unladen weight
95
+ - ✅️ Download data to CVS
92
96
  - ➡️ Endurance
93
- - ➡️ Rate of Force Development (RFD)
94
- - ➡️ Repeaters
97
+ - ➡️ Rate of Force Development: RFD
95
98
  - ➡️ Critical Force
96
99
 
97
100
  ## Development
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hangtime/grip-connect",
3
- "version": "0.2.7",
3
+ "version": "0.3.0",
4
4
  "description": "A client that can establish connections with various Force-Sensing Hangboards/Plates used by climbers for strength measurement. Examples of such hangboards include the Griptonite Motherboard, Climbro, SmartBoard, Entralpi or Tindeq Progressor",
5
5
  "main": "src/index.ts",
6
6
  "scripts": {
@@ -1,5 +1,6 @@
1
1
  export { ClimbroCommands } from "./climbro";
2
2
  export { EntralpiCommands } from "./entralpi";
3
3
  export { MotherboardCommands } from "./motherboard";
4
+ export { MuscleMeterCommands } from "./musclemeter";
4
5
  export { ProgressorCommands } from "./progressor";
5
- export { SmartBoardCommands } from "./smartboard";
6
+ export { mySmartBoardCommands } from "./mysmartboard";
@@ -1,5 +1,6 @@
1
1
  export { ClimbroCommands } from "./climbro";
2
2
  export { EntralpiCommands } from "./entralpi";
3
3
  export { MotherboardCommands } from "./motherboard";
4
+ export { MuscleMeterCommands } from "./musclemeter";
4
5
  export { ProgressorCommands } from "./progressor";
5
- export { SmartBoardCommands } from "./smartboard";
6
+ export { mySmartBoardCommands } from "./mysmartboard";
@@ -4,6 +4,8 @@ export { EntralpiCommands } from "./entralpi"
4
4
 
5
5
  export { MotherboardCommands } from "./motherboard"
6
6
 
7
+ export { MuscleMeterCommands } from "./musclemeter"
8
+
7
9
  export { ProgressorCommands } from "./progressor"
8
10
 
9
- export { SmartBoardCommands } from "./smartboard"
11
+ export { mySmartBoardCommands } from "./mysmartboard"
@@ -3,4 +3,4 @@ import { Commands } from "../commands/types";
3
3
  * Warning:
4
4
  * Using other commands can seriously harm your device
5
5
  */
6
- export declare const SmartBoardCommands: Commands;
6
+ export declare const MuscleMeterCommands: Commands;
@@ -2,4 +2,4 @@
2
2
  * Warning:
3
3
  * Using other commands can seriously harm your device
4
4
  */
5
- export const SmartBoardCommands = {};
5
+ export const MuscleMeterCommands = {};
@@ -3,4 +3,4 @@ import { Commands } from "../commands/types"
3
3
  * Warning:
4
4
  * Using other commands can seriously harm your device
5
5
  */
6
- export const SmartBoardCommands: Commands = {}
6
+ export const MuscleMeterCommands: Commands = {}
@@ -0,0 +1,6 @@
1
+ import { Commands } from "../commands/types";
2
+ /**
3
+ * Warning:
4
+ * Using other commands can seriously harm your device
5
+ */
6
+ export declare const mySmartBoardCommands: Commands;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Warning:
3
+ * Using other commands can seriously harm your device
4
+ */
5
+ export const mySmartBoardCommands = {};
@@ -0,0 +1,6 @@
1
+ import { Commands } from "../commands/types"
2
+ /**
3
+ * Warning:
4
+ * Using other commands can seriously harm your device
5
+ */
6
+ export const mySmartBoardCommands: Commands = {}
@@ -11,5 +11,7 @@ export declare const ProgressorCommands: Commands;
11
11
  export declare const ProgressorResponses: {
12
12
  COMMAND_RESPONSE: number;
13
13
  WEIGHT_MEASURE: number;
14
+ PEAK_RFD_MEAS: number;
15
+ PEAK_RFD_MEAS_SERIES: number;
14
16
  LOW_BATTERY_WARNING: number;
15
17
  };
@@ -23,5 +23,7 @@ export const ProgressorCommands = {
23
23
  export const ProgressorResponses = {
24
24
  COMMAND_RESPONSE: 0,
25
25
  WEIGHT_MEASURE: 1,
26
- LOW_BATTERY_WARNING: 2,
26
+ PEAK_RFD_MEAS: 2,
27
+ PEAK_RFD_MEAS_SERIES: 3,
28
+ LOW_BATTERY_WARNING: 4,
27
29
  };
@@ -25,5 +25,7 @@ export const ProgressorCommands: Commands = {
25
25
  export const ProgressorResponses = {
26
26
  COMMAND_RESPONSE: 0,
27
27
  WEIGHT_MEASURE: 1,
28
- LOW_BATTERY_WARNING: 2,
28
+ PEAK_RFD_MEAS: 2,
29
+ PEAK_RFD_MEAS_SERIES: 3,
30
+ LOW_BATTERY_WARNING: 4,
29
31
  }
package/src/data.js CHANGED
@@ -3,6 +3,7 @@ import { applyTare } from "./tare";
3
3
  import { ProgressorCommands, ProgressorResponses } from "./commands/progressor";
4
4
  import { MotherboardCommands } from "./commands";
5
5
  import { lastWrite } from "./write";
6
+ import { DownloadPackets } from "./download";
6
7
  import struct from "./struct";
7
8
  // Constants
8
9
  const PACKET_LENGTH = 32;
@@ -87,6 +88,14 @@ export const handleMotherboardData = (receivedData) => {
87
88
  // invert center and right values
88
89
  packet.masses[1] *= -1;
89
90
  packet.masses[2] *= -1;
91
+ // Add data to downloadable Array
92
+ DownloadPackets.push({
93
+ received: packet.received,
94
+ sampleNum: packet.battRaw,
95
+ battRaw: packet.received,
96
+ samples: [...packet.samples],
97
+ masses: [...packet.masses],
98
+ });
90
99
  let left = packet.masses[0];
91
100
  let center = packet.masses[1];
92
101
  let right = packet.masses[2];
@@ -129,13 +138,25 @@ export const handleMotherboardData = (receivedData) => {
129
138
  * @param {DataView} data - The received data.
130
139
  */
131
140
  export const handleProgressorData = (data) => {
141
+ const receivedTime = Date.now();
132
142
  const [kind] = struct("<bb").unpack(data.buffer.slice(0, 2));
133
143
  if (kind === ProgressorResponses.WEIGHT_MEASURE) {
134
144
  const iterable = struct("<fi").iter_unpack(data.buffer.slice(2));
135
- for (let [weight] of iterable) {
136
- if (typeof weight === "number" && !isNaN(weight)) {
145
+ console.log(iterable);
146
+ // eslint-disable-next-line prefer-const
147
+ for (let [weight, seconds] of iterable) {
148
+ if (typeof weight === "number" && !isNaN(weight) && typeof seconds === "number" && !isNaN(seconds)) {
149
+ // Add data to downloadable Array: sample and mass are the same
150
+ DownloadPackets.push({
151
+ received: receivedTime,
152
+ sampleNum: seconds,
153
+ battRaw: 0,
154
+ samples: [weight],
155
+ masses: [weight],
156
+ });
137
157
  // Tare correction
138
158
  weight -= applyTare(weight);
159
+ // Check for max weight
139
160
  MASS_MAX = Math.max(Number(MASS_MAX), Number(weight)).toFixed(1);
140
161
  // Update running sum and count
141
162
  const currentMassTotal = Math.max(-1000, Number(weight));
package/src/data.ts CHANGED
@@ -3,17 +3,9 @@ import { applyTare } from "./tare"
3
3
  import { ProgressorCommands, ProgressorResponses } from "./commands/progressor"
4
4
  import { MotherboardCommands } from "./commands"
5
5
  import { lastWrite } from "./write"
6
+ import { DownloadPacket, DownloadPackets } from "./download"
6
7
  import struct from "./struct"
7
8
 
8
- // Interfaces
9
- interface MotherboardPacket {
10
- received: number
11
- sampleNum: number
12
- battRaw: number
13
- samples: number[]
14
- masses: number[]
15
- }
16
-
17
9
  // Constants
18
10
  const PACKET_LENGTH: number = 32
19
11
  const NUM_SAMPLES: number = 3
@@ -82,7 +74,7 @@ export const handleMotherboardData = (receivedData: string): void => {
82
74
  )
83
75
 
84
76
  // Translate header into packet, number of samples from the packet length
85
- const packet: MotherboardPacket = {
77
+ const packet: DownloadPacket = {
86
78
  received: receivedTime,
87
79
  sampleNum: new DataView(new Uint8Array(bytes).buffer).getUint16(0, true),
88
80
  battRaw: new DataView(new Uint8Array(bytes).buffer).getUint16(2, true),
@@ -112,6 +104,15 @@ export const handleMotherboardData = (receivedData: string): void => {
112
104
  packet.masses[1] *= -1
113
105
  packet.masses[2] *= -1
114
106
 
107
+ // Add data to downloadable Array
108
+ DownloadPackets.push({
109
+ received: packet.received,
110
+ sampleNum: packet.battRaw,
111
+ battRaw: packet.received,
112
+ samples: [...packet.samples],
113
+ masses: [...packet.masses],
114
+ })
115
+
115
116
  let left: number = packet.masses[0]
116
117
  let center: number = packet.masses[1]
117
118
  let right: number = packet.masses[2]
@@ -158,14 +159,25 @@ export const handleMotherboardData = (receivedData: string): void => {
158
159
  * @param {DataView} data - The received data.
159
160
  */
160
161
  export const handleProgressorData = (data: DataView): void => {
162
+ const receivedTime: number = Date.now()
161
163
  const [kind] = struct("<bb").unpack(data.buffer.slice(0, 2))
162
164
  if (kind === ProgressorResponses.WEIGHT_MEASURE) {
163
165
  const iterable: IterableIterator<unknown[]> = struct("<fi").iter_unpack(data.buffer.slice(2))
164
- for (let [weight] of iterable) {
165
- if (typeof weight === "number" && !isNaN(weight)) {
166
+ console.log(iterable)
167
+ // eslint-disable-next-line prefer-const
168
+ for (let [weight, seconds] of iterable) {
169
+ if (typeof weight === "number" && !isNaN(weight) && typeof seconds === "number" && !isNaN(seconds)) {
170
+ // Add data to downloadable Array: sample and mass are the same
171
+ DownloadPackets.push({
172
+ received: receivedTime,
173
+ sampleNum: seconds,
174
+ battRaw: 0,
175
+ samples: [weight],
176
+ masses: [weight],
177
+ })
166
178
  // Tare correction
167
179
  weight -= applyTare(weight)
168
-
180
+ // Check for max weight
169
181
  MASS_MAX = Math.max(Number(MASS_MAX), Number(weight)).toFixed(1)
170
182
  // Update running sum and count
171
183
  const currentMassTotal = Math.max(-1000, Number(weight))
@@ -1,6 +1,6 @@
1
1
  import { Device } from "./types";
2
2
  /**
3
3
  * Represents a Climbro device
4
- * TODO: Add services, do you own a SmartBoard? Help us!
4
+ * TODO: Add services, do you own a Climbro? Help us!
5
5
  */
6
6
  export declare const Climbro: Device;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Represents a Climbro device
3
- * TODO: Add services, do you own a SmartBoard? Help us!
3
+ * TODO: Add services, do you own a Climbro? Help us!
4
4
  */
5
5
  export const Climbro = {
6
6
  name: "Climbro",
@@ -2,7 +2,7 @@ import { Device } from "./types"
2
2
 
3
3
  /**
4
4
  * Represents a Climbro device
5
- * TODO: Add services, do you own a SmartBoard? Help us!
5
+ * TODO: Add services, do you own a Climbro? Help us!
6
6
  */
7
7
  export const Climbro: Device = {
8
8
  name: "Climbro",
@@ -1,5 +1,6 @@
1
1
  export { Climbro } from "./climbro";
2
2
  export { Entralpi } from "./entralpi";
3
3
  export { Motherboard } from "./motherboard";
4
- export { SmartBoard } from "./smartboard";
4
+ export { mySmartBoard } from "./mysmartboard";
5
+ export { MuscleMeter } from "./musclemeter";
5
6
  export { Progressor } from "./progressor";
@@ -1,5 +1,6 @@
1
1
  export { Climbro } from "./climbro";
2
2
  export { Entralpi } from "./entralpi";
3
3
  export { Motherboard } from "./motherboard";
4
- export { SmartBoard } from "./smartboard";
4
+ export { mySmartBoard } from "./mysmartboard";
5
+ export { MuscleMeter } from "./musclemeter";
5
6
  export { Progressor } from "./progressor";
@@ -4,6 +4,8 @@ export { Entralpi } from "./entralpi"
4
4
 
5
5
  export { Motherboard } from "./motherboard"
6
6
 
7
- export { SmartBoard } from "./smartboard"
7
+ export { mySmartBoard } from "./mysmartboard"
8
+
9
+ export { MuscleMeter } from "./musclemeter"
8
10
 
9
11
  export { Progressor } from "./progressor"
@@ -0,0 +1,6 @@
1
+ import { Device } from "./types";
2
+ /**
3
+ * Represents a MAT Muscle Meter device
4
+ * TODO: Add services, do you own a MAT Muscle Meter? Help us!
5
+ */
6
+ export declare const MuscleMeter: Device;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Represents a MAT Muscle Meter device
3
+ * TODO: Add services, do you own a MAT Muscle Meter? Help us!
4
+ */
5
+ export const MuscleMeter = {
6
+ name: "MAT",
7
+ services: [],
8
+ };
@@ -0,0 +1,10 @@
1
+ import { Device } from "./types"
2
+
3
+ /**
4
+ * Represents a MAT Muscle Meter device
5
+ * TODO: Add services, do you own a MAT Muscle Meter? Help us!
6
+ */
7
+ export const MuscleMeter: Device = {
8
+ name: "MAT",
9
+ services: [],
10
+ }
@@ -0,0 +1,6 @@
1
+ import { Device } from "./types";
2
+ /**
3
+ * Represents a mySmartBoard device
4
+ * TODO: Add services, do you own a mySmartBoard? Help us!
5
+ */
6
+ export declare const mySmartBoard: Device;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Represents a mySmartBoard device
3
+ * TODO: Add services, do you own a mySmartBoard? Help us!
4
+ */
5
+ export const mySmartBoard = {
6
+ name: "mySmartBoard",
7
+ services: [],
8
+ };
@@ -0,0 +1,10 @@
1
+ import { Device } from "./types"
2
+
3
+ /**
4
+ * Represents a mySmartBoard device
5
+ * TODO: Add services, do you own a mySmartBoard? Help us!
6
+ */
7
+ export const mySmartBoard: Device = {
8
+ name: "mySmartBoard",
9
+ services: [],
10
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Represents a single data packet.
3
+ */
4
+ export interface DownloadPacket {
5
+ received: number;
6
+ sampleNum: number;
7
+ battRaw: number;
8
+ samples: number[];
9
+ masses: number[];
10
+ }
11
+ /**
12
+ * Array of DownloadPacket entries.
13
+ */
14
+ export declare const DownloadPackets: DownloadPacket[];
15
+ export declare const emptyDownloadPackets: () => void;
16
+ /**
17
+ * Exports the data as a CSV file.
18
+ */
19
+ export declare const download: () => void;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Array of DownloadPacket entries.
3
+ */
4
+ export const DownloadPackets = []; // Initialize an empty array of DownloadPacket entries
5
+ // Function to empty DownloadPackets array
6
+ export const emptyDownloadPackets = () => {
7
+ DownloadPackets.length = 0; // Set the length of the array to 0 to empty it
8
+ };
9
+ /**
10
+ * Converts an array of DownloadPacket objects to a CSV string.
11
+ * @param data - Array of DownloadPacket objects.
12
+ * @returns CSV string representation of the data.
13
+ */
14
+ const packetsToCSV = (data) => {
15
+ return data
16
+ .map((packet) => [
17
+ packet.received.toString(),
18
+ packet.sampleNum.toString(),
19
+ packet.battRaw.toString(),
20
+ ...packet.samples.map(String),
21
+ ...packet.masses.map(String),
22
+ ]
23
+ .map((v) => v.replace(/"/g, '""'))
24
+ .map((v) => `"${v}"`)
25
+ .join(","))
26
+ .join("\r\n");
27
+ };
28
+ /**
29
+ * Exports the data as a CSV file.
30
+ */
31
+ export const download = () => {
32
+ // Generate CSV string from DownloadPackets array
33
+ const csvContent = packetsToCSV(DownloadPackets);
34
+ // Create a Blob object containing the CSV data
35
+ const blob = new Blob([csvContent], { type: "text/csv" });
36
+ // Create a URL for the Blob
37
+ const url = window.URL.createObjectURL(blob);
38
+ // Create a link element
39
+ const link = document.createElement("a");
40
+ // Set link attributes
41
+ link.href = url;
42
+ link.setAttribute("download", "data.csv");
43
+ // Append link to document body
44
+ document.body.appendChild(link);
45
+ // Programmatically click the link to trigger the download
46
+ link.click();
47
+ // Clean up: remove the link and revoke the URL
48
+ document.body.removeChild(link);
49
+ window.URL.revokeObjectURL(url);
50
+ };
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Represents a single data packet.
3
+ */
4
+ export interface DownloadPacket {
5
+ received: number // Timestamp of when the packet was received
6
+ sampleNum: number // Sample number
7
+ battRaw: number // Battery raw value
8
+ samples: number[] // Array of sample values
9
+ masses: number[] // Array of mass values
10
+ }
11
+
12
+ /**
13
+ * Array of DownloadPacket entries.
14
+ */
15
+ export const DownloadPackets: DownloadPacket[] = [] // Initialize an empty array of DownloadPacket entries
16
+
17
+ // Function to empty DownloadPackets array
18
+ export const emptyDownloadPackets = (): void => {
19
+ DownloadPackets.length = 0 // Set the length of the array to 0 to empty it
20
+ }
21
+
22
+ /**
23
+ * Converts an array of DownloadPacket objects to a CSV string.
24
+ * @param data - Array of DownloadPacket objects.
25
+ * @returns CSV string representation of the data.
26
+ */
27
+ const packetsToCSV = (data: DownloadPacket[]): string => {
28
+ return data
29
+ .map((packet) =>
30
+ [
31
+ packet.received.toString(),
32
+ packet.sampleNum.toString(),
33
+ packet.battRaw.toString(),
34
+ ...packet.samples.map(String),
35
+ ...packet.masses.map(String),
36
+ ]
37
+ .map((v) => v.replace(/"/g, '""'))
38
+ .map((v) => `"${v}"`)
39
+ .join(","),
40
+ )
41
+ .join("\r\n")
42
+ }
43
+
44
+ /**
45
+ * Exports the data as a CSV file.
46
+ */
47
+ export const download = (): void => {
48
+ // Generate CSV string from DownloadPackets array
49
+ const csvContent: string = packetsToCSV(DownloadPackets)
50
+
51
+ // Create a Blob object containing the CSV data
52
+ const blob = new Blob([csvContent], { type: "text/csv" })
53
+
54
+ // Create a URL for the Blob
55
+ const url = window.URL.createObjectURL(blob)
56
+
57
+ // Create a link element
58
+ const link = document.createElement("a")
59
+
60
+ // Set link attributes
61
+ link.href = url
62
+ link.setAttribute("download", "data.csv")
63
+
64
+ // Append link to document body
65
+ document.body.appendChild(link)
66
+
67
+ // Programmatically click the link to trigger the download
68
+ link.click()
69
+
70
+ // Clean up: remove the link and revoke the URL
71
+ document.body.removeChild(link)
72
+ window.URL.revokeObjectURL(url)
73
+ }
package/src/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- export { Climbro, Entralpi, Motherboard, SmartBoard, Progressor } from "./devices/index";
1
+ export { Climbro, Entralpi, Motherboard, mySmartBoard, MuscleMeter, Progressor } from "./devices/index";
2
2
  export { battery } from "./battery";
3
3
  export { calibration } from "./calibration";
4
+ export { download } from "./download";
4
5
  export { connect } from "./connect";
5
6
  export { disconnect } from "./disconnect";
6
7
  export { isConnected } from "./is-connected";
package/src/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  // Export device types
2
- export { Climbro, Entralpi, Motherboard, SmartBoard, Progressor } from "./devices/index";
2
+ export { Climbro, Entralpi, Motherboard, mySmartBoard, MuscleMeter, Progressor } from "./devices/index";
3
3
  // Export battery related functions
4
4
  export { battery } from "./battery";
5
5
  // Export calibration function
6
6
  export { calibration } from "./calibration";
7
+ // Export download function
8
+ export { download } from "./download";
7
9
  // Export connection related functions
8
10
  export { connect } from "./connect";
9
11
  export { disconnect } from "./disconnect";
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  // Export device types
2
- export { Climbro, Entralpi, Motherboard, SmartBoard, Progressor } from "./devices/index"
2
+ export { Climbro, Entralpi, Motherboard, mySmartBoard, MuscleMeter, Progressor } from "./devices/index"
3
3
 
4
4
  // Export battery related functions
5
5
  export { battery } from "./battery"
@@ -7,6 +7,9 @@ export { battery } from "./battery"
7
7
  // Export calibration function
8
8
  export { calibration } from "./calibration"
9
9
 
10
+ // Export download function
11
+ export { download } from "./download"
12
+
10
13
  // Export connection related functions
11
14
  export { connect } from "./connect"
12
15
  export { disconnect } from "./disconnect"
package/src/stream.js CHANGED
@@ -3,6 +3,7 @@ import { write } from "./write";
3
3
  import { stop } from "./stop";
4
4
  import { Motherboard, Progressor } from "./devices";
5
5
  import { MotherboardCommands, ProgressorCommands } from "./commands";
6
+ import { emptyDownloadPackets } from "./download";
6
7
  import { CALIBRATION } from "./data";
7
8
  import { calibration } from "./calibration";
8
9
  /**
@@ -13,6 +14,9 @@ import { calibration } from "./calibration";
13
14
  */
14
15
  export const stream = async (board, duration = 0) => {
15
16
  if (isConnected(board)) {
17
+ // Reset download packets
18
+ emptyDownloadPackets();
19
+ // Device specific logic
16
20
  if (board.name === "Motherboard") {
17
21
  // Read calibration data if not already available
18
22
  if (!CALIBRATION[0].length) {
package/src/stream.ts CHANGED
@@ -4,6 +4,7 @@ import { write } from "./write"
4
4
  import { stop } from "./stop"
5
5
  import { Motherboard, Progressor } from "./devices"
6
6
  import { MotherboardCommands, ProgressorCommands } from "./commands"
7
+ import { emptyDownloadPackets } from "./download"
7
8
  import { CALIBRATION } from "./data"
8
9
  import { calibration } from "./calibration"
9
10
 
@@ -15,6 +16,9 @@ import { calibration } from "./calibration"
15
16
  */
16
17
  export const stream = async (board: Device, duration: number = 0): Promise<void> => {
17
18
  if (isConnected(board)) {
19
+ // Reset download packets
20
+ emptyDownloadPackets()
21
+ // Device specific logic
18
22
  if (board.name === "Motherboard") {
19
23
  // Read calibration data if not already available
20
24
  if (!CALIBRATION[0].length) {
package/src/write.js CHANGED
@@ -18,7 +18,7 @@ export const write = (board, serviceId, characteristicId, message, duration = 0)
18
18
  return new Promise((resolve, reject) => {
19
19
  if (isConnected(board)) {
20
20
  // Check if message is provided
21
- if (!message) {
21
+ if (message === undefined) {
22
22
  // If not provided, return without performing write operation
23
23
  return;
24
24
  }
package/src/write.ts CHANGED
@@ -27,7 +27,7 @@ export const write = (
27
27
  return new Promise((resolve, reject) => {
28
28
  if (isConnected(board)) {
29
29
  // Check if message is provided
30
- if (!message) {
30
+ if (message === undefined) {
31
31
  // If not provided, return without performing write operation
32
32
  return
33
33
  }
@@ -1,6 +0,0 @@
1
- import { Device } from "./types";
2
- /**
3
- * Represents a SmartBoard device
4
- * TODO: Add services, do you own a SmartBoard? Help us!
5
- */
6
- export declare const SmartBoard: Device;
@@ -1,8 +0,0 @@
1
- /**
2
- * Represents a SmartBoard device
3
- * TODO: Add services, do you own a SmartBoard? Help us!
4
- */
5
- export const SmartBoard = {
6
- name: "SmartBoard",
7
- services: [],
8
- };
@@ -1,10 +0,0 @@
1
- import { Device } from "./types"
2
-
3
- /**
4
- * Represents a SmartBoard device
5
- * TODO: Add services, do you own a SmartBoard? Help us!
6
- */
7
- export const SmartBoard: Device = {
8
- name: "SmartBoard",
9
- services: [],
10
- }