@hangtime/grip-connect 0.0.5 → 0.0.7

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 (52) hide show
  1. package/README.md +10 -8
  2. package/build/characteristic.d.ts +9 -0
  3. package/build/characteristic.js +15 -0
  4. package/build/connect.d.ts +7 -0
  5. package/build/connect.js +172 -0
  6. package/build/devices/entralpi.d.ts +2 -0
  7. package/build/devices/entralpi.js +52 -0
  8. package/build/devices/index.d.ts +3 -0
  9. package/build/devices/index.js +3 -0
  10. package/build/devices/moterboard.d.ts +2 -0
  11. package/build/devices/moterboard.js +79 -0
  12. package/build/devices/tindeq.d.ts +17 -0
  13. package/build/devices/tindeq.js +37 -0
  14. package/build/devices/types.d.ts +20 -0
  15. package/build/devices/types.js +1 -0
  16. package/build/disconnect.d.ts +6 -0
  17. package/build/disconnect.js +11 -0
  18. package/build/index.d.ts +6 -18
  19. package/build/index.js +6 -175
  20. package/build/notify.d.ts +4 -0
  21. package/build/notify.js +6 -0
  22. package/build/read.d.ts +6 -0
  23. package/build/read.js +44 -0
  24. package/build/write.d.ts +7 -0
  25. package/build/write.js +32 -0
  26. package/package.json +1 -1
  27. package/src/characteristic.d.ts +9 -0
  28. package/src/characteristic.js +15 -0
  29. package/src/connect.d.ts +7 -0
  30. package/src/connect.js +172 -0
  31. package/src/connect.ts +64 -37
  32. package/src/devices/entralpi.d.ts +2 -0
  33. package/src/devices/entralpi.js +52 -0
  34. package/src/devices/index.d.ts +3 -0
  35. package/src/devices/index.js +3 -0
  36. package/src/devices/moterboard.d.ts +2 -0
  37. package/src/devices/moterboard.js +79 -0
  38. package/src/devices/tindeq.d.ts +17 -0
  39. package/src/devices/tindeq.js +37 -0
  40. package/src/devices/types.d.ts +20 -0
  41. package/src/devices/types.js +1 -0
  42. package/src/disconnect.d.ts +6 -0
  43. package/src/disconnect.js +11 -0
  44. package/src/index.d.ts +6 -0
  45. package/src/index.js +6 -0
  46. package/src/notify.d.ts +4 -0
  47. package/src/notify.js +6 -0
  48. package/src/read.d.ts +6 -0
  49. package/src/read.js +44 -0
  50. package/src/read.ts +7 -3
  51. package/src/write.d.ts +7 -0
  52. package/src/write.js +32 -0
package/README.md CHANGED
@@ -1,7 +1,9 @@
1
- # Force-Sensing Climbing Training
1
+ # Grip Connect
2
2
 
3
- The objective of this project is to create a client that can establish connections with various Force-Sensing
4
- Hangboards/Plates used by climbers for strength measurement. Examples of such hangboards include the
3
+ **Force-Sensing Climbing Training**
4
+
5
+ The objective of this project is to create a client that can establish connections with various Force-Sensing Hangboards
6
+ / Plates used by climbers for strength measurement. Examples of such hangboards include the
5
7
  [Motherboard](https://griptonite.io/shop/motherboard/), [Climbro](https://climbro.com/),
6
8
  [SmartBoard](https://www.smartboard-climbing.com/), [Entralpi](https://entralpi.com/) or
7
9
  [Tindeq Progressor](https://tindeq.com/)
@@ -54,13 +56,13 @@ motherboardButton.addEventListener("click", () => {
54
56
  })
55
57
 
56
58
  // read battery + device info
57
- await read(Motherboard, "battery", "level")
58
- await read(Motherboard, "device", "manufacturer")
59
- await read(Motherboard, "device", "hardware")
60
- await read(Motherboard, "device", "firmware")
59
+ await read(Motherboard, "battery", "level", 1000)
60
+ await read(Motherboard, "device", "manufacturer", 1000)
61
+ await read(Motherboard, "device", "hardware", 1000)
62
+ await read(Motherboard, "device", "firmware", 1000)
61
63
 
62
64
  // Calibrate?
63
- await write(Motherboard, "uart", "tx", "C", 5000)
65
+ await write(Motherboard, "uart", "tx", "C", 10000)
64
66
 
65
67
  // Read stream?
66
68
  await write(Motherboard, "unknown", "01", "1", 2500)
@@ -0,0 +1,9 @@
1
+ /// <reference types="web-bluetooth" />
2
+ import { Device } from "./devices/types";
3
+ /**
4
+ * getCharacteristic
5
+ * @param board
6
+ * @param serviceId
7
+ * @param characteristicId
8
+ */
9
+ export declare const getCharacteristic: (board: Device, serviceId: string, characteristicId: string) => BluetoothRemoteGATTCharacteristic | undefined;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * getCharacteristic
3
+ * @param board
4
+ * @param serviceId
5
+ * @param characteristicId
6
+ */
7
+ export const getCharacteristic = (board, serviceId, characteristicId) => {
8
+ const boardService = board.services.find((service) => service.id === serviceId);
9
+ if (boardService) {
10
+ const boardCharacteristic = boardService.characteristics.find((characteristic) => characteristic.id === characteristicId);
11
+ if (boardCharacteristic) {
12
+ return boardCharacteristic.characteristic;
13
+ }
14
+ }
15
+ };
@@ -0,0 +1,7 @@
1
+ import { Device } from "./devices/types";
2
+ /**
3
+ * Connect to the BluetoothDevice
4
+ * @param device
5
+ * @param onSuccess
6
+ */
7
+ export declare const connect: (board: Device, onSuccess: () => void) => Promise<void>;
@@ -0,0 +1,172 @@
1
+ import { notifyCallback } from "./notify";
2
+ let server;
3
+ /**
4
+ * onDisconnected
5
+ * @param board
6
+ * @param event
7
+ */
8
+ const onDisconnected = (event, board) => {
9
+ board.device = undefined;
10
+ const device = event.target;
11
+ console.log(`Device ${device.name} is disconnected.`);
12
+ };
13
+ /**
14
+ * handleNotifications
15
+ * @param event
16
+ * @param onNotify
17
+ */
18
+ const handleNotifications = (event, board) => {
19
+ const characteristic = event.target;
20
+ const receivedData = new Uint8Array(characteristic.value.buffer);
21
+ // Create an array to store the parsed decimal values
22
+ const decimalArray = [];
23
+ // Iterate through each byte and convert to decimal
24
+ for (let i = 0; i < receivedData.length; i++) {
25
+ decimalArray.push(receivedData[i]);
26
+ }
27
+ // Convert the decimal array to a string representation
28
+ const receivedString = String.fromCharCode(...decimalArray);
29
+ if (board.name === "Motherboard") {
30
+ // Split the string into pairs of characters
31
+ const hexPairs = receivedString.match(/.{1,2}/g);
32
+ // Convert each hexadecimal pair to decimal
33
+ const parsedDecimalArray = hexPairs?.map((hexPair) => parseInt(hexPair, 16));
34
+ // Handle different types of data
35
+ if (characteristic.value.byteLength === 20) {
36
+ const elementKeys = [
37
+ "frames",
38
+ "cycle",
39
+ "unknown",
40
+ "eleven",
41
+ "dynamic1",
42
+ "pressure1",
43
+ "left",
44
+ "dynamic2",
45
+ "pressure2",
46
+ "right",
47
+ ];
48
+ const dataObject = {};
49
+ if (parsedDecimalArray) {
50
+ elementKeys.forEach((key, index) => {
51
+ dataObject[key] = parsedDecimalArray[index];
52
+ });
53
+ }
54
+ if (notifyCallback) {
55
+ notifyCallback({ uuid: characteristic.uuid, value: dataObject });
56
+ }
57
+ }
58
+ else if (characteristic.value.byteLength === 14) {
59
+ // TODO: handle 14 byte data
60
+ // notifyCallback({ uuid: characteristic.uuid, value: characteristic.value!.getInt8(0) / 100 })
61
+ }
62
+ }
63
+ else if (board.name === "ENTRALPI") {
64
+ // TODO: handle Entralpi notify
65
+ // characteristic.value!.getInt16(0) / 100;
66
+ if (notifyCallback) {
67
+ notifyCallback({ uuid: characteristic.uuid, value: receivedString });
68
+ }
69
+ }
70
+ else if (board.name === "Tindeq") {
71
+ // TODO: handle Tindeq notify
72
+ }
73
+ else {
74
+ if (notifyCallback) {
75
+ notifyCallback({ uuid: characteristic.uuid, value: receivedString });
76
+ }
77
+ }
78
+ };
79
+ /**
80
+ * onConnected
81
+ * @param event
82
+ * @param board
83
+ */
84
+ const onConnected = async (board, onSuccess) => {
85
+ try {
86
+ const services = await server?.getPrimaryServices();
87
+ if (!services || services.length === 0) {
88
+ console.error("No services found");
89
+ return;
90
+ }
91
+ for (const service of services) {
92
+ const matchingService = board.services.find((boardService) => boardService.uuid === service.uuid);
93
+ if (matchingService) {
94
+ // Android bug: Introduce a delay before getting characteristics
95
+ await new Promise((resolve) => setTimeout(resolve, 100));
96
+ const characteristics = await service.getCharacteristics();
97
+ for (const characteristic of matchingService.characteristics) {
98
+ const matchingCharacteristic = characteristics.find((char) => char.uuid === characteristic.uuid);
99
+ if (matchingCharacteristic) {
100
+ const element = matchingService.characteristics.find((char) => char.uuid === matchingCharacteristic.uuid);
101
+ if (element) {
102
+ element.characteristic = matchingCharacteristic;
103
+ // notify
104
+ if (element.id === "rx") {
105
+ matchingCharacteristic.startNotifications();
106
+ matchingCharacteristic.addEventListener("characteristicvaluechanged", (event) => handleNotifications(event, board));
107
+ }
108
+ }
109
+ }
110
+ else {
111
+ console.warn(`Characteristic ${characteristic.uuid} not found in service ${service.uuid}`);
112
+ }
113
+ }
114
+ }
115
+ }
116
+ // Call the onSuccess callback after successful connection and setup
117
+ onSuccess();
118
+ }
119
+ catch (error) {
120
+ console.error(error);
121
+ }
122
+ };
123
+ /**
124
+ * Return all service UUIDs
125
+ * @param device
126
+ */
127
+ function getAllServiceUUIDs(device) {
128
+ return device.services.map((service) => service.uuid);
129
+ }
130
+ /**
131
+ * Connect to the BluetoothDevice
132
+ * @param device
133
+ * @param onSuccess
134
+ */
135
+ export const connect = async (board, onSuccess) => {
136
+ try {
137
+ const deviceServices = getAllServiceUUIDs(board);
138
+ // setup filter list
139
+ const filters = [];
140
+ if (board.name) {
141
+ filters.push({
142
+ name: board.name,
143
+ });
144
+ }
145
+ if (board.companyId) {
146
+ filters.push({
147
+ manufacturerData: [
148
+ {
149
+ companyIdentifier: board.companyId,
150
+ },
151
+ ],
152
+ });
153
+ }
154
+ const device = await navigator.bluetooth.requestDevice({
155
+ filters: filters,
156
+ optionalServices: deviceServices
157
+ });
158
+ board.device = device;
159
+ if (!board.device.gatt) {
160
+ console.error("GATT is not available on this device");
161
+ return;
162
+ }
163
+ server = await board.device?.gatt?.connect();
164
+ board.device.addEventListener("gattserverdisconnected", (event) => onDisconnected(event, board));
165
+ if (server.connected) {
166
+ await onConnected(board, onSuccess);
167
+ }
168
+ }
169
+ catch (error) {
170
+ console.error(error);
171
+ }
172
+ };
@@ -0,0 +1,2 @@
1
+ import { Device } from "./types";
2
+ export declare const Entralpi: Device;
@@ -0,0 +1,52 @@
1
+ export const Entralpi = {
2
+ name: "ENTRALPI",
3
+ services: [
4
+ {
5
+ name: "Device Information",
6
+ id: "device",
7
+ uuid: "0000180a-0000-1000-8000-00805f9b34fb",
8
+ characteristics: [],
9
+ },
10
+ {
11
+ name: "Battery Service",
12
+ id: "battery",
13
+ uuid: "0000180f-0000-1000-8000-00805f9b34fb",
14
+ characteristics: [],
15
+ },
16
+ {
17
+ name: "Generic Attribute",
18
+ id: "attribute",
19
+ uuid: "00001801-0000-1000-8000-00805f9b34fb",
20
+ characteristics: [],
21
+ },
22
+ {
23
+ name: "UART ISSC Transparent Service",
24
+ id: "uart",
25
+ uuid: "0000fff0-0000-1000-8000-00805f9b34fb",
26
+ characteristics: [
27
+ {
28
+ name: "TX",
29
+ id: "tx",
30
+ uuid: "0000fff5-0000-1000-8000-00805f9b34fb",
31
+ },
32
+ {
33
+ name: "RX",
34
+ id: "rx",
35
+ uuid: "0000fff4-0000-1000-8000-00805f9b34fb",
36
+ },
37
+ ],
38
+ },
39
+ {
40
+ name: "Weight Scale",
41
+ id: "weight",
42
+ uuid: "0000181d-0000-1000-8000-00805f9b34fb",
43
+ characteristics: [],
44
+ },
45
+ {
46
+ name: "Generic Access",
47
+ id: "access",
48
+ uuid: "00001800-0000-1000-8000-00805f9b34fb",
49
+ characteristics: [],
50
+ },
51
+ ],
52
+ };
@@ -0,0 +1,3 @@
1
+ export { Motherboard } from "./moterboard";
2
+ export { Entralpi } from "./entralpi";
3
+ export { Tindeq } from "./tindeq";
@@ -0,0 +1,3 @@
1
+ export { Motherboard } from "./moterboard";
2
+ export { Entralpi } from "./entralpi";
3
+ export { Tindeq } from "./tindeq";
@@ -0,0 +1,2 @@
1
+ import { Device } from "./types";
2
+ export declare const Motherboard: Device;
@@ -0,0 +1,79 @@
1
+ export const Motherboard = {
2
+ name: "Motherboard",
3
+ companyId: 0x2a29,
4
+ services: [
5
+ {
6
+ name: "Device Information",
7
+ id: "device",
8
+ uuid: "0000180a-0000-1000-8000-00805f9b34fb",
9
+ characteristics: [
10
+ // {
11
+ // name: 'Serial Number (Blocked)',
12
+ // id: 'serial'
13
+ // uuid: '00002a25-0000-1000-8000-00805f9b34fb'
14
+ // },
15
+ {
16
+ name: "Firmware Revision",
17
+ id: "firmware",
18
+ uuid: "00002a26-0000-1000-8000-00805f9b34fb",
19
+ },
20
+ {
21
+ name: "Hardware Revision",
22
+ id: "hardware",
23
+ uuid: "00002a27-0000-1000-8000-00805f9b34fb",
24
+ },
25
+ {
26
+ name: "Manufacturer Name",
27
+ id: "manufacturer",
28
+ uuid: "00002a29-0000-1000-8000-00805f9b34fb",
29
+ },
30
+ ],
31
+ },
32
+ {
33
+ name: "Battery Service",
34
+ id: "battery",
35
+ uuid: "0000180f-0000-1000-8000-00805f9b34fb",
36
+ characteristics: [
37
+ {
38
+ name: "Battery Level",
39
+ id: "level",
40
+ uuid: "00002a19-0000-1000-8000-00805f9b34fb",
41
+ },
42
+ ],
43
+ },
44
+ {
45
+ name: "Unknown Service",
46
+ id: "unknown",
47
+ uuid: "10ababcd-15e1-28ff-de13-725bea03b127",
48
+ characteristics: [
49
+ {
50
+ name: "Unknown 01",
51
+ id: "01",
52
+ uuid: "10ab1524-15e1-28ff-de13-725bea03b127",
53
+ },
54
+ {
55
+ name: "Unknown 02",
56
+ id: "02",
57
+ uuid: "10ab1525-15e1-28ff-de13-725bea03b127",
58
+ },
59
+ ],
60
+ },
61
+ {
62
+ name: "UART Nordic Service",
63
+ id: "uart",
64
+ uuid: "6e400001-b5a3-f393-e0a9-e50e24dcca9e",
65
+ characteristics: [
66
+ {
67
+ name: "TX",
68
+ id: "tx",
69
+ uuid: "6e400002-b5a3-f393-e0a9-e50e24dcca9e",
70
+ },
71
+ {
72
+ name: "RX",
73
+ id: "rx",
74
+ uuid: "6e400003-b5a3-f393-e0a9-e50e24dcca9e",
75
+ },
76
+ ],
77
+ },
78
+ ],
79
+ };
@@ -0,0 +1,17 @@
1
+ import { Device } from "./types";
2
+ export declare const Tindeq: Device;
3
+ export declare const Commands: {
4
+ TARE_SCALE: number;
5
+ START_MEASURING: number;
6
+ STOP_MEASURING: number;
7
+ GET_APP_VERSION: number;
8
+ GET_ERROR_INFO: number;
9
+ CLEAR_ERR_INFO: number;
10
+ GET_BATTERY_LEVEL: number;
11
+ SLEEP: number;
12
+ };
13
+ export declare const NotificationTypes: {
14
+ COMMAND_RESPONSE: number;
15
+ WEIGHT_MEASURE: number;
16
+ LOW_BATTERY_WARNING: number;
17
+ };
@@ -0,0 +1,37 @@
1
+ export const Tindeq = {
2
+ name: "Tindeq",
3
+ services: [
4
+ {
5
+ name: "Progressor Service",
6
+ id: "progressor",
7
+ uuid: "7e4e1701-1ea6-40c9-9dcc-13d34ffead57",
8
+ characteristics: [
9
+ {
10
+ name: "Write",
11
+ id: "tx",
12
+ uuid: "7e4e1703-1ea6-40c9-9dcc-13d34ffead57",
13
+ },
14
+ {
15
+ name: "Notify",
16
+ id: "rx",
17
+ uuid: "7e4e1702-1ea6-40c9-9dcc-13d34ffead57",
18
+ },
19
+ ],
20
+ },
21
+ ],
22
+ };
23
+ export const Commands = {
24
+ TARE_SCALE: 0x64,
25
+ START_MEASURING: 0x65,
26
+ STOP_MEASURING: 0x66,
27
+ GET_APP_VERSION: 0x6b,
28
+ GET_ERROR_INFO: 0x6c,
29
+ CLEAR_ERR_INFO: 0x6d,
30
+ GET_BATTERY_LEVEL: 0x6f,
31
+ SLEEP: 0x6e,
32
+ };
33
+ export const NotificationTypes = {
34
+ COMMAND_RESPONSE: 0,
35
+ WEIGHT_MEASURE: 1,
36
+ LOW_BATTERY_WARNING: 2,
37
+ };
@@ -0,0 +1,20 @@
1
+ /// <reference types="web-bluetooth" />
2
+ interface Characteristic {
3
+ name: string;
4
+ id: string;
5
+ uuid: string;
6
+ characteristic?: BluetoothRemoteGATTCharacteristic;
7
+ }
8
+ interface Service {
9
+ name: string;
10
+ id: string;
11
+ uuid: string;
12
+ characteristics: Characteristic[];
13
+ }
14
+ export interface Device {
15
+ name: string;
16
+ companyId?: number;
17
+ services: Service[];
18
+ device?: BluetoothDevice;
19
+ }
20
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ import { Device } from "./devices/types";
2
+ /**
3
+ * disconnect
4
+ * @param board
5
+ */
6
+ export declare const disconnect: (board: Device) => void;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * disconnect
3
+ * @param board
4
+ */
5
+ export const disconnect = (board) => {
6
+ if (!board.device)
7
+ return;
8
+ if (board.device.gatt?.connected) {
9
+ board.device.gatt?.disconnect();
10
+ }
11
+ };
package/build/index.d.ts CHANGED
@@ -1,18 +1,6 @@
1
- /// <reference types="web-bluetooth" />
2
- interface Motherboard {
3
- device?: BluetoothDevice
4
- devSn?: BluetoothRemoteGATTCharacteristic
5
- devFr?: BluetoothRemoteGATTCharacteristic
6
- devHr?: BluetoothRemoteGATTCharacteristic
7
- devMn?: BluetoothRemoteGATTCharacteristic
8
- bat?: BluetoothRemoteGATTCharacteristic
9
- led01?: BluetoothRemoteGATTCharacteristic
10
- led02?: BluetoothRemoteGATTCharacteristic
11
- uartTx?: BluetoothRemoteGATTCharacteristic
12
- uartRx?: BluetoothRemoteGATTCharacteristic
13
- }
14
- declare const motherboard: Motherboard
15
- declare const connect: () => void
16
- declare const disconnect: () => void
17
- export default motherboard
18
- export { disconnect, connect }
1
+ export { Motherboard, Entralpi, Tindeq } from "./devices/index";
2
+ export { connect } from "./connect";
3
+ export { disconnect } from "./disconnect";
4
+ export { notify } from "./notify";
5
+ export { read } from "./read";
6
+ export { write } from "./write";