@hangtime/grip-connect 0.3.10 → 0.4.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.
Files changed (58) hide show
  1. package/README.md +32 -23
  2. package/dist/battery.d.ts +8 -3
  3. package/dist/battery.js +19 -7
  4. package/dist/calibration.js +5 -3
  5. package/dist/commands/kilterboard.js +1 -1
  6. package/dist/connect.js +4 -3
  7. package/dist/data/motherboard.d.ts +6 -2
  8. package/dist/data/motherboard.js +8 -3
  9. package/dist/data/progressor.d.ts +6 -2
  10. package/dist/data/progressor.js +10 -7
  11. package/dist/devices/kilterboard.d.ts +4 -0
  12. package/dist/devices/kilterboard.js +5 -1
  13. package/dist/firmware.d.ts +12 -0
  14. package/dist/firmware.js +37 -0
  15. package/dist/hardware.d.ts +11 -0
  16. package/dist/hardware.js +25 -0
  17. package/dist/index.d.ts +7 -2
  18. package/dist/index.js +10 -4
  19. package/dist/is-device.d.ts +31 -0
  20. package/dist/is-device.js +33 -0
  21. package/dist/led.d.ts +7 -3
  22. package/dist/led.js +32 -31
  23. package/dist/manufacturer.d.ts +11 -0
  24. package/dist/manufacturer.js +25 -0
  25. package/dist/read.d.ts +2 -2
  26. package/dist/read.js +3 -5
  27. package/dist/serial.d.ts +11 -0
  28. package/dist/serial.js +30 -0
  29. package/dist/stop.js +5 -5
  30. package/dist/stream.js +8 -8
  31. package/dist/text.d.ts +14 -0
  32. package/dist/text.js +33 -0
  33. package/dist/write.d.ts +26 -8
  34. package/dist/write.js +50 -47
  35. package/package.json +1 -1
  36. package/src/battery.ts +20 -8
  37. package/src/calibration.ts +5 -3
  38. package/src/commands/kilterboard.ts +1 -1
  39. package/src/connect.ts +4 -3
  40. package/src/data/motherboard.ts +8 -3
  41. package/src/data/progressor.ts +10 -7
  42. package/src/devices/kilterboard.ts +6 -1
  43. package/src/firmware.ts +39 -0
  44. package/src/hardware.ts +27 -0
  45. package/src/index.ts +10 -4
  46. package/src/is-device.ts +43 -0
  47. package/src/led.ts +35 -31
  48. package/src/manufacturer.ts +27 -0
  49. package/src/read.ts +5 -7
  50. package/src/serial.ts +32 -0
  51. package/src/stop.ts +5 -5
  52. package/src/stream.ts +8 -8
  53. package/src/text.ts +35 -0
  54. package/src/types/download.ts +1 -1
  55. package/src/write.ts +57 -45
  56. package/dist/info.d.ts +0 -7
  57. package/dist/info.js +0 -30
  58. package/src/info.ts +0 -32
package/dist/led.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { write } from "./write";
2
2
  import { isConnected } from "./is-connected";
3
- import { KilterBoard, Motherboard } from "./devices";
4
3
  import { KilterBoardPacket, KilterBoardPlacementRoles } from "./commands/kilterboard";
4
+ import { isKilterboard, isMotherboard } from "./is-device";
5
5
  /**
6
6
  * Maximum length of the message body for byte wrapping.
7
7
  */
@@ -152,44 +152,45 @@ const splitMessages = (buffer) => splitEvery(MAX_BLUETOOTH_MESSAGE_SIZE, buffer)
152
152
  /**
153
153
  * Sends a series of messages to a device.
154
154
  */
155
- async function writeMessageSeries(messages) {
155
+ async function writeMessageSeries(board, messages) {
156
156
  for (const message of messages) {
157
- await write(KilterBoard, "uart", "tx", message);
157
+ await write(board, "uart", "tx", message);
158
158
  }
159
159
  }
160
160
  /**
161
161
  * Sets the LEDs on the specified device.
162
+ *
163
+ * - For Kilter Board: Configures the LEDs based on an array of climb placements. If a configuration is provided, it prepares and sends a payload to the device.
164
+ * - For Motherboard: Sets the LED color based on a single color option. Defaults to turning the LEDs off if no configuration is provided.
165
+ *
162
166
  * @param {Device} board - The device on which to set the LEDs.
163
- * @param {ClimbPlacement[]} [placement] - An optional array of climb placements for LED positioning.
164
- * @returns {Promise<number[] | undefined>} A promise that resolves with the payload array if LED settings were applied, or `undefined` if no action was taken.
167
+ * @param {"green" | "red" | "orange" | ClimbPlacement[]} [config] - Optional color or array of climb placements for the LEDs. Ignored if placements are provided.
168
+ * @returns {Promise<number[] | undefined>} A promise that resolves with the payload array for the Kilter Board if LED settings were applied, or `undefined` if no action was taken or for the Motherboard.
165
169
  */
166
- export const led = async (board, placement) => {
167
- // Check if the filter contains the Aurora Climbing Advertising service
168
- const AuroraUUID = "4488b571-7806-4df6-bcff-a2897e4953ff";
169
- if (board.filters.some((filter) => filter.services?.includes(AuroraUUID))) {
170
- // The Aurora Boards needs a LED / Postion Placememnet Array
171
- if (placement) {
172
- // Prepares byte arrays for transmission based on a list of climb placements.
173
- const payload = prepBytesV3(placement);
174
- // Sends the payload to the device by splitting it into messages and writing each message.
175
- if (isConnected(board)) {
176
- writeMessageSeries(splitMessages(payload));
177
- }
178
- return payload;
170
+ export const led = async (board, config) => {
171
+ // Handle Kilterboard logic: process placements and send payload if connected
172
+ if (isKilterboard(board) && Array.isArray(config)) {
173
+ // Prepares byte arrays for transmission based on a list of climb placements.
174
+ const payload = prepBytesV3(config);
175
+ if (isConnected(board)) {
176
+ await writeMessageSeries(board, splitMessages(payload));
179
177
  }
178
+ return payload;
180
179
  }
181
- if (board.filters.some((filter) => filter.name === "Motherboard")) {
182
- console.log("Green");
183
- await write(Motherboard, "led", "red", new Uint8Array([0x00]));
184
- await write(Motherboard, "led", "green", new Uint8Array([0x01]), 2500);
185
- console.log("Red");
186
- await write(Motherboard, "led", "red", new Uint8Array([0x01]));
187
- await write(Motherboard, "led", "green", new Uint8Array([0x00]), 2500);
188
- console.log("Orage");
189
- await write(Motherboard, "led", "red", new Uint8Array([0x01]));
190
- await write(Motherboard, "led", "green", new Uint8Array([0x01]), 2500);
191
- console.log("Off");
192
- await write(Motherboard, "led", "red", new Uint8Array([0x00]));
193
- await write(Motherboard, "led", "green", new Uint8Array([0x00]), 2500);
180
+ // Handle Motherboard logic: set color if provided
181
+ if (isMotherboard(board)) {
182
+ const colorMapping = {
183
+ green: [[0x00], [0x01]],
184
+ red: [[0x01], [0x00]],
185
+ orange: [[0x01], [0x01]],
186
+ off: [[0x00], [0x00]],
187
+ };
188
+ // Default to "off" color if config is not set or not found in colorMapping
189
+ const color = typeof config === "string" && colorMapping[config] ? config : "off";
190
+ const [redValue, greenValue] = colorMapping[color];
191
+ await write(board, "led", "red", new Uint8Array(redValue));
192
+ await write(board, "led", "green", new Uint8Array(greenValue), 1250);
193
+ return;
194
194
  }
195
+ return;
195
196
  };
@@ -0,0 +1,11 @@
1
+ import type { Device } from "./types/devices";
2
+ /**
3
+ * Retrieves manufacturer information from the device.
4
+ * - For Motherboard devices, it reads the manufacturer information.
5
+ *
6
+ * @param {Device} board - The device from which to retrieve manufacturer information.
7
+ * @returns {Promise<string>} A Promise that resolves with the manufacturer information,
8
+ * or rejects with an error if the device is not connected.
9
+ * @throws {Error} Throws an error if the device is not connected.
10
+ */
11
+ export declare const manufacturer: (board: Device) => Promise<string | undefined>;
@@ -0,0 +1,25 @@
1
+ import { read } from "./read";
2
+ import { isConnected } from "./is-connected";
3
+ import { isMotherboard } from "./is-device";
4
+ /**
5
+ * Retrieves manufacturer information from the device.
6
+ * - For Motherboard devices, it reads the manufacturer information.
7
+ *
8
+ * @param {Device} board - The device from which to retrieve manufacturer information.
9
+ * @returns {Promise<string>} A Promise that resolves with the manufacturer information,
10
+ * or rejects with an error if the device is not connected.
11
+ * @throws {Error} Throws an error if the device is not connected.
12
+ */
13
+ export const manufacturer = async (board) => {
14
+ // Check if the device is connected
15
+ if (isConnected(board)) {
16
+ // If the device is connected and it is a Motherboard device
17
+ if (isMotherboard(board)) {
18
+ // Read manufacturer information from the Motherboard
19
+ return await read(board, "device", "manufacturer", 250);
20
+ }
21
+ // If device is not found, return undefined
22
+ return;
23
+ }
24
+ throw new Error("Not connected.");
25
+ };
package/dist/read.d.ts CHANGED
@@ -5,6 +5,6 @@ import type { Device } from "./types/devices";
5
5
  * @param {string} serviceId - The service ID where the characteristic belongs.
6
6
  * @param {string} characteristicId - The characteristic ID to read from.
7
7
  * @param {number} [duration=0] - The duration to wait before resolving the promise, in milliseconds.
8
- * @returns {Promise<void>} A promise that resolves when the read operation is completed.
8
+ * @returns {Promise<string>} A promise that resolves when the read operation is completed.
9
9
  */
10
- export declare const read: (board: Device, serviceId: string, characteristicId: string, duration?: number) => Promise<void>;
10
+ export declare const read: (board: Device, serviceId: string, characteristicId: string, duration?: number) => Promise<string>;
package/dist/read.js CHANGED
@@ -6,7 +6,7 @@ import { isConnected } from "./is-connected";
6
6
  * @param {string} serviceId - The service ID where the characteristic belongs.
7
7
  * @param {string} characteristicId - The characteristic ID to read from.
8
8
  * @param {number} [duration=0] - The duration to wait before resolving the promise, in milliseconds.
9
- * @returns {Promise<void>} A promise that resolves when the read operation is completed.
9
+ * @returns {Promise<string>} A promise that resolves when the read operation is completed.
10
10
  */
11
11
  export const read = (board, serviceId, characteristicId, duration = 0) => {
12
12
  return new Promise((resolve, reject) => {
@@ -21,17 +21,15 @@ export const read = (board, serviceId, characteristicId, duration = 0) => {
21
21
  switch (characteristicId) {
22
22
  case "level":
23
23
  // TODO: This is Motherboard specific.
24
- decodedValue = value.getUint8(0);
24
+ decodedValue = value.getUint8(0).toString();
25
25
  break;
26
26
  default:
27
27
  decodedValue = decoder.decode(value);
28
28
  break;
29
29
  }
30
- // TODO: Create Read callback
31
- console.log(decodedValue);
32
30
  // Resolve after specified duration
33
31
  setTimeout(() => {
34
- resolve();
32
+ return resolve(decodedValue);
35
33
  }, duration);
36
34
  })
37
35
  .catch((error) => {
@@ -0,0 +1,11 @@
1
+ import type { Device } from "./types/devices";
2
+ /**
3
+ * Retrieves serial number from the device.
4
+ * - For Motherboard devices, it reads the serial number.
5
+ *
6
+ * @param {Device} board - The device from which to retrieve serial number.
7
+ * @returns {Promise<string>} A Promise that resolves with the serial number,
8
+ * or rejects with an error if the device is not connected.
9
+ * @throws {Error} Throws an error if the device is not connected.
10
+ */
11
+ export declare const serial: (board: Device) => Promise<string | undefined>;
package/dist/serial.js ADDED
@@ -0,0 +1,30 @@
1
+ import { write } from "./write";
2
+ import { isConnected } from "./is-connected";
3
+ import { MotherboardCommands } from "./commands";
4
+ import { isMotherboard } from "./is-device";
5
+ /**
6
+ * Retrieves serial number from the device.
7
+ * - For Motherboard devices, it reads the serial number.
8
+ *
9
+ * @param {Device} board - The device from which to retrieve serial number.
10
+ * @returns {Promise<string>} A Promise that resolves with the serial number,
11
+ * or rejects with an error if the device is not connected.
12
+ * @throws {Error} Throws an error if the device is not connected.
13
+ */
14
+ export const serial = async (board) => {
15
+ // Check if the device is connected
16
+ if (isConnected(board)) {
17
+ // If the device is connected and it is a Motherboard device
18
+ if (isMotherboard(board)) {
19
+ // Write serial number command to the Motherboard and read output
20
+ let response = undefined;
21
+ await write(board, "uart", "tx", MotherboardCommands.GET_SERIAL, 250, (data) => {
22
+ response = data;
23
+ });
24
+ return response;
25
+ }
26
+ // If device is not found, return undefined
27
+ return;
28
+ }
29
+ throw new Error("Not connected.");
30
+ };
package/dist/stop.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { write } from "./write";
2
2
  import { isConnected } from "./is-connected";
3
- import { Motherboard, Progressor } from "./devices";
4
3
  import { MotherboardCommands, ProgressorCommands } from "./commands";
4
+ import { isMotherboard, isProgressor } from "./is-device";
5
5
  /**
6
6
  * Stops the data stream on the specified device.
7
7
  * @param {Device} board - The device to stop the stream on.
@@ -9,13 +9,13 @@ import { MotherboardCommands, ProgressorCommands } from "./commands";
9
9
  */
10
10
  export const stop = async (board) => {
11
11
  if (isConnected(board)) {
12
- if (board.filters.some((filter) => filter.name === "Motherboard")) {
12
+ if (isMotherboard(board)) {
13
13
  // Stop stream on Motherboard
14
- await write(Motherboard, "uart", "tx", MotherboardCommands.STOP_WEIGHT_MEAS, 0);
14
+ await write(board, "uart", "tx", MotherboardCommands.STOP_WEIGHT_MEAS, 0);
15
15
  }
16
- if (board.filters.some((filter) => filter.namePrefix === "Progressor")) {
16
+ if (isProgressor(board)) {
17
17
  // Stop stream on Progressor
18
- await write(Progressor, "progressor", "tx", ProgressorCommands.STOP_WEIGHT_MEAS, 0);
18
+ await write(board, "progressor", "tx", ProgressorCommands.STOP_WEIGHT_MEAS, 0);
19
19
  }
20
20
  }
21
21
  };
package/dist/stream.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { isConnected } from "./is-connected";
2
2
  import { write } from "./write";
3
3
  import { stop } from "./stop";
4
- import { Motherboard, Progressor } from "./devices";
4
+ import { isMotherboard, isProgressor } from "./is-device";
5
5
  import { MotherboardCommands, ProgressorCommands } from "./commands";
6
6
  import { emptyDownloadPackets } from "./download";
7
7
  import { CALIBRATION } from "./data/motherboard";
@@ -17,24 +17,24 @@ export const stream = async (board, duration = 0) => {
17
17
  // Reset download packets
18
18
  emptyDownloadPackets();
19
19
  // Device specific logic
20
- if (board.filters.some((filter) => filter.name === "Motherboard")) {
20
+ if (isMotherboard(board)) {
21
21
  // Read calibration data if not already available
22
22
  if (!CALIBRATION[0].length) {
23
- await calibration(Motherboard);
23
+ await calibration(board);
24
24
  }
25
25
  // Start streaming data
26
- await write(Motherboard, "uart", "tx", MotherboardCommands.START_WEIGHT_MEAS, duration);
26
+ await write(board, "uart", "tx", MotherboardCommands.START_WEIGHT_MEAS, duration);
27
27
  // Stop streaming if duration is set
28
28
  if (duration !== 0) {
29
- await stop(Motherboard);
29
+ await stop(board);
30
30
  }
31
31
  }
32
- if (board.filters.some((filter) => filter.namePrefix === "Progressor")) {
32
+ if (isProgressor(board)) {
33
33
  // Start streaming data
34
- await write(Progressor, "progressor", "tx", ProgressorCommands.START_WEIGHT_MEAS, duration);
34
+ await write(board, "progressor", "tx", ProgressorCommands.START_WEIGHT_MEAS, duration);
35
35
  // Stop streaming if duration is set
36
36
  if (duration !== 0) {
37
- await stop(Progressor);
37
+ await stop(board);
38
38
  }
39
39
  }
40
40
  }
package/dist/text.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { Device } from "./types/devices";
2
+ /**
3
+ * Retrieves the entire 320 bytes of non-volatile memory from the device.
4
+ *
5
+ * The memory consists of 10 segments, each 32 bytes long. If any segment was previously written,
6
+ * the corresponding data will appear in the response. Unused portions of the memory are
7
+ * padded with whitespace.
8
+ *
9
+ * @param {Device} board - The device from which to retrieve text information.
10
+ * @returns {Promise<string>} A Promise that resolves with the 320-byte memory content as a string,
11
+ * which includes both the written data and any unused, whitespace-padded segments.
12
+ * @throws {Error} Throws an error if the device is not connected.
13
+ */
14
+ export declare const text: (board: Device) => Promise<string | undefined>;
package/dist/text.js ADDED
@@ -0,0 +1,33 @@
1
+ import { write } from "./write";
2
+ import { isConnected } from "./is-connected";
3
+ import { isMotherboard } from "./is-device";
4
+ import { MotherboardCommands } from "./commands";
5
+ /**
6
+ * Retrieves the entire 320 bytes of non-volatile memory from the device.
7
+ *
8
+ * The memory consists of 10 segments, each 32 bytes long. If any segment was previously written,
9
+ * the corresponding data will appear in the response. Unused portions of the memory are
10
+ * padded with whitespace.
11
+ *
12
+ * @param {Device} board - The device from which to retrieve text information.
13
+ * @returns {Promise<string>} A Promise that resolves with the 320-byte memory content as a string,
14
+ * which includes both the written data and any unused, whitespace-padded segments.
15
+ * @throws {Error} Throws an error if the device is not connected.
16
+ */
17
+ export const text = async (board) => {
18
+ // Check if the device is connected
19
+ if (isConnected(board)) {
20
+ // If the device is connected and it is a Motherboard device
21
+ if (isMotherboard(board)) {
22
+ // Write text information command to the Motherboard and read output
23
+ let response = undefined;
24
+ await write(board, "uart", "tx", MotherboardCommands.GET_TEXT, 250, (data) => {
25
+ response = data;
26
+ });
27
+ return response;
28
+ }
29
+ // If device is not found, return undefined
30
+ return;
31
+ }
32
+ throw new Error("Not connected.");
33
+ };
package/dist/write.d.ts CHANGED
@@ -4,13 +4,31 @@ import type { Device } from "./types/devices";
4
4
  * @type {string | Uint8Array | null}
5
5
  */
6
6
  export declare let lastWrite: string | Uint8Array | null;
7
+ /** Define the type for the callback function */
8
+ type WriteCallback = (data: string) => void;
7
9
  /**
8
- * Writes a message to the specified characteristic of the device.
9
- * @param {Device} board - The device board to write to.
10
- * @param {string} serviceId - The service ID where the characteristic belongs.
11
- * @param {string} characteristicId - The characteristic ID to write to.
12
- * @param {string | Uint8Array | undefined} message - The message to write.
13
- * @param {number} [duration=0] - The duration to wait before resolving the promise, in milliseconds.
14
- * @returns {Promise<void>} A promise that resolves when the write operation is completed.
10
+ * A default write callback that logs the response
15
11
  */
16
- export declare const write: (board: Device, serviceId: string, characteristicId: string, message: string | Uint8Array | undefined, duration?: number) => Promise<void>;
12
+ export declare let writeCallback: WriteCallback;
13
+ /**
14
+ * Writes a message to the specified characteristic of a Bluetooth device and optionally provides a callback to handle responses.
15
+ *
16
+ * @param {Device} board - The Bluetooth device to which the message will be written.
17
+ * @param {string} serviceId - The service UUID of the Bluetooth device containing the target characteristic.
18
+ * @param {string} characteristicId - The characteristic UUID where the message will be written.
19
+ * @param {string | Uint8Array | undefined} message - The message to be written to the characteristic. It can be a string or a Uint8Array.
20
+ * @param {number} [duration=0] - Optional. The time in milliseconds to wait before resolving the promise. Defaults to 0 for immediate resolution.
21
+ * @param {WriteCallback} [callback=writeCallback] - Optional. A custom callback to handle the response after the write operation is successful.
22
+ *
23
+ * @returns {Promise<void>} A promise that resolves once the write operation is complete.
24
+ *
25
+ * @throws {Error} Throws an error if the characteristic is undefined or if the device is not connected.
26
+ *
27
+ * @example
28
+ * // Example usage of the write function with a custom callback
29
+ * await write(device, "serviceId", "characteristicId", "Hello World", 250, (data) => {
30
+ * console.log(`Custom response: ${data}`);
31
+ * });
32
+ */
33
+ export declare const write: (board: Device, serviceId: string, characteristicId: string, message: string | Uint8Array | undefined, duration?: number, callback?: WriteCallback) => Promise<void>;
34
+ export {};
package/dist/write.js CHANGED
@@ -6,52 +6,55 @@ import { getCharacteristic } from "./characteristic";
6
6
  */
7
7
  export let lastWrite = null;
8
8
  /**
9
- * Writes a message to the specified characteristic of the device.
10
- * @param {Device} board - The device board to write to.
11
- * @param {string} serviceId - The service ID where the characteristic belongs.
12
- * @param {string} characteristicId - The characteristic ID to write to.
13
- * @param {string | Uint8Array | undefined} message - The message to write.
14
- * @param {number} [duration=0] - The duration to wait before resolving the promise, in milliseconds.
15
- * @returns {Promise<void>} A promise that resolves when the write operation is completed.
9
+ * A default write callback that logs the response
16
10
  */
17
- export const write = (board, serviceId, characteristicId, message, duration = 0) => {
18
- return new Promise((resolve, reject) => {
19
- if (isConnected(board)) {
20
- // Check if message is provided
21
- if (message === undefined) {
22
- // If not provided, return without performing write operation
23
- return;
24
- }
25
- // Get the characteristic from the device using serviceId and characteristicId
26
- const characteristic = getCharacteristic(board, serviceId, characteristicId);
27
- if (characteristic) {
28
- // Convert the message to Uint8Array if it's a string
29
- const valueToWrite = typeof message === "string" ? new TextEncoder().encode(message) : message;
30
- // Write the value to the characteristic
31
- characteristic
32
- .writeValue(valueToWrite)
33
- .then(() => {
34
- // Update the last written message
35
- lastWrite = message;
36
- // If a duration is specified, resolve the promise after the duration
37
- if (duration > 0) {
38
- setTimeout(() => {
39
- resolve();
40
- }, duration);
41
- }
42
- else {
43
- // Otherwise, resolve the promise immediately
44
- resolve();
45
- }
46
- })
47
- .catch((error) => {
48
- reject(error);
49
- });
50
- }
51
- else {
52
- // Reject if characteristic is undefined
53
- reject(new Error("Characteristics is undefined"));
54
- }
55
- }
56
- });
11
+ export let writeCallback = (data) => {
12
+ console.log(data);
13
+ };
14
+ /**
15
+ * Writes a message to the specified characteristic of a Bluetooth device and optionally provides a callback to handle responses.
16
+ *
17
+ * @param {Device} board - The Bluetooth device to which the message will be written.
18
+ * @param {string} serviceId - The service UUID of the Bluetooth device containing the target characteristic.
19
+ * @param {string} characteristicId - The characteristic UUID where the message will be written.
20
+ * @param {string | Uint8Array | undefined} message - The message to be written to the characteristic. It can be a string or a Uint8Array.
21
+ * @param {number} [duration=0] - Optional. The time in milliseconds to wait before resolving the promise. Defaults to 0 for immediate resolution.
22
+ * @param {WriteCallback} [callback=writeCallback] - Optional. A custom callback to handle the response after the write operation is successful.
23
+ *
24
+ * @returns {Promise<void>} A promise that resolves once the write operation is complete.
25
+ *
26
+ * @throws {Error} Throws an error if the characteristic is undefined or if the device is not connected.
27
+ *
28
+ * @example
29
+ * // Example usage of the write function with a custom callback
30
+ * await write(device, "serviceId", "characteristicId", "Hello World", 250, (data) => {
31
+ * console.log(`Custom response: ${data}`);
32
+ * });
33
+ */
34
+ export const write = async (board, serviceId, characteristicId, message, duration = 0, callback = writeCallback) => {
35
+ if (!isConnected(board)) {
36
+ throw new Error("Device is not connected");
37
+ }
38
+ // Check if message is provided
39
+ if (message === undefined) {
40
+ // If not provided, return without performing write operation
41
+ return;
42
+ }
43
+ // Get the characteristic from the device using serviceId and characteristicId
44
+ const characteristic = getCharacteristic(board, serviceId, characteristicId);
45
+ if (!characteristic) {
46
+ throw new Error("Characteristic is undefined");
47
+ }
48
+ // Convert the message to Uint8Array if it's a string
49
+ const valueToWrite = typeof message === "string" ? new TextEncoder().encode(message) : message;
50
+ // Write the value to the characteristic
51
+ await characteristic.writeValue(valueToWrite);
52
+ // Update the last written message
53
+ lastWrite = message;
54
+ // Assign the provided callback to `writeCallback`
55
+ writeCallback = callback;
56
+ // If a duration is specified, resolve the promise after the duration
57
+ if (duration > 0) {
58
+ await new Promise((resolve) => setTimeout(resolve, duration));
59
+ }
57
60
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hangtime/grip-connect",
3
- "version": "0.3.10",
3
+ "version": "0.4.1",
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": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/battery.ts CHANGED
@@ -2,26 +2,38 @@ import type { Device } from "./types/devices"
2
2
  import { write } from "./write"
3
3
  import { read } from "./read"
4
4
  import { isConnected } from "./is-connected"
5
- import { Motherboard, Progressor } from "./devices"
5
+ import { isMotherboard, isProgressor } from "./is-device"
6
6
  import { ProgressorCommands } from "./commands"
7
7
 
8
8
  /**
9
9
  * Retrieves battery or voltage information from the device.
10
- * @param {Device} board - The device.
11
- * @returns {Promise<void>} A Promise that resolves when the information is successfully retrieved.
10
+ * - For Motherboard devices, it reads the battery level.
11
+ * - For Progressor devices, it sends a command to retrieve battery voltage information.
12
+ *
13
+ * @param {Device} board - The device from which to retrieve battery information.
14
+ * @returns {Promise<string | undefined>} A Promise that resolves with the battery or voltage information,
15
+ * or rejects with an error if the device is not connected.
16
+ * @throws {Error} Throws an error if the device is not connected.
12
17
  */
13
- export const battery = async (board: Device): Promise<void> => {
18
+ export const battery = async (board: Device): Promise<string | undefined> => {
14
19
  // Check if the device is connected
15
20
  if (isConnected(board)) {
16
21
  // If the device is connected and it is a Motherboard device
17
- if (board.filters.some((filter) => filter.name === "Motherboard")) {
22
+ if (isMotherboard(board)) {
18
23
  // Read battery level information from the Motherboard
19
- await read(Motherboard, "battery", "level", 250)
24
+ return await read(board, "battery", "level", 250)
20
25
  }
21
26
  // If the device is connected and its name starts with "Progressor"
22
- if (board.filters.some((filter) => filter.namePrefix === "Progressor")) {
27
+ if (isProgressor(board)) {
23
28
  // Write command to get battery voltage information to the Progressor
24
- await write(Progressor, "progressor", "tx", ProgressorCommands.GET_BATT_VLTG, 250)
29
+ let response: string | undefined = undefined
30
+ await write(board, "progressor", "tx", ProgressorCommands.GET_BATT_VLTG, 250, (data) => {
31
+ response = data
32
+ })
33
+ return response
25
34
  }
35
+ // If device is not found, return undefined
36
+ return
26
37
  }
38
+ throw new Error("Not connected.")
27
39
  }
@@ -1,7 +1,7 @@
1
1
  import type { Device } from "./types/devices"
2
2
  import { isConnected } from "./is-connected"
3
3
  import { write } from "./write"
4
- import { Motherboard } from "./devices"
4
+ import { isMotherboard } from "./is-device"
5
5
  import { MotherboardCommands } from "./commands"
6
6
 
7
7
  /**
@@ -13,9 +13,11 @@ export const calibration = async (board: Device): Promise<void> => {
13
13
  // Check if the device is connected
14
14
  if (isConnected(board)) {
15
15
  // If the device is connected, and it is a Motherboard device
16
- if (board.filters.some((filter) => filter.name === "Motherboard")) {
16
+ if (isMotherboard(board)) {
17
17
  // Write the command to get calibration data to the device
18
- await write(Motherboard, "uart", "tx", MotherboardCommands.GET_CALIBRATION, 2500)
18
+ await write(board, "uart", "tx", MotherboardCommands.GET_CALIBRATION, 2500, (data) => {
19
+ console.log(data)
20
+ })
19
21
  }
20
22
  }
21
23
  }
@@ -58,7 +58,7 @@ export const KilterBoardPlacementRoles = [
58
58
  position: 4,
59
59
  name: "foot",
60
60
  full_name: "Foot Only",
61
- led_color: "FFA500",
61
+ led_color: "FFB600",
62
62
  screen_color: "FFA500",
63
63
  },
64
64
  ]
package/src/connect.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Device } from "./types/devices"
2
2
  import { handleEntralpiData, handleMotherboardData, handleProgressorData, handleWHC06Data } from "./data"
3
+ import { isEntralpi, isMotherboard, isProgressor } from "./is-device"
3
4
 
4
5
  let server: BluetoothRemoteGATTServer
5
6
  const receiveBuffer: number[] = []
@@ -25,7 +26,7 @@ const handleNotifications = (event: Event, board: Device): void => {
25
26
 
26
27
  if (value) {
27
28
  // If the device is connected and it is a Motherboard device
28
- if (board.filters.some((filter) => filter.name === "Motherboard")) {
29
+ if (isMotherboard(board)) {
29
30
  for (let i = 0; i < value.byteLength; i++) {
30
31
  receiveBuffer.push(value.getUint8(i))
31
32
  }
@@ -38,14 +39,14 @@ const handleNotifications = (event: Event, board: Device): void => {
38
39
  const receivedData: string = decoder.decode(new Uint8Array(line))
39
40
  handleMotherboardData(receivedData)
40
41
  }
41
- } else if (board.filters.some((filter) => filter.name === "ENTRALPI")) {
42
+ } else if (isEntralpi(board)) {
42
43
  if (value.buffer) {
43
44
  const buffer: ArrayBuffer = value.buffer
44
45
  const rawData: DataView = new DataView(buffer)
45
46
  const receivedData: string = (rawData.getUint16(0) / 100).toFixed(1)
46
47
  handleEntralpiData(receivedData)
47
48
  }
48
- } else if (board.filters.some((filter) => filter.namePrefix === "Progressor")) {
49
+ } else if (isProgressor(board)) {
49
50
  if (value.buffer) {
50
51
  const buffer: ArrayBuffer = value.buffer
51
52
  const rawData: DataView = new DataView(buffer)
@@ -1,4 +1,5 @@
1
1
  import { notifyCallback } from "./../notify"
2
+ import { writeCallback } from "./../write"
2
3
  import { applyTare } from "./../tare"
3
4
  import { MotherboardCommands } from "./../commands"
4
5
  import { checkActivity } from "./../is-active"
@@ -57,8 +58,12 @@ const applyCalibration = (sample: number, calibration: number[][]): number => {
57
58
  return sign * final
58
59
  }
59
60
  /**
60
- * Handles data received from the Motherboard device.
61
- * @param {string} receivedData - The received data string.
61
+ * Handles data received from the Motherboard device. Processes hex-encoded streaming packets
62
+ * to extract samples, calibrate masses, and update running averages of mass data.
63
+ * If the received data is not a valid hex packet, it returns the unprocessed data.
64
+ *
65
+ * @param {string} receivedData - The raw data received from the Motherboard device.
66
+ * @returns {void}
62
67
  */
63
68
  export const handleMotherboardData = (receivedData: string): void => {
64
69
  const receivedTime: number = Date.now()
@@ -153,6 +158,6 @@ export const handleMotherboardData = (receivedData: string): void => {
153
158
  }
154
159
  } else {
155
160
  // unhandled data
156
- console.log(receivedData)
161
+ writeCallback(receivedData)
157
162
  }
158
163
  }