@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.
- package/README.md +10 -8
- package/build/characteristic.d.ts +9 -0
- package/build/characteristic.js +15 -0
- package/build/connect.d.ts +7 -0
- package/build/connect.js +172 -0
- package/build/devices/entralpi.d.ts +2 -0
- package/build/devices/entralpi.js +52 -0
- package/build/devices/index.d.ts +3 -0
- package/build/devices/index.js +3 -0
- package/build/devices/moterboard.d.ts +2 -0
- package/build/devices/moterboard.js +79 -0
- package/build/devices/tindeq.d.ts +17 -0
- package/build/devices/tindeq.js +37 -0
- package/build/devices/types.d.ts +20 -0
- package/build/devices/types.js +1 -0
- package/build/disconnect.d.ts +6 -0
- package/build/disconnect.js +11 -0
- package/build/index.d.ts +6 -18
- package/build/index.js +6 -175
- package/build/notify.d.ts +4 -0
- package/build/notify.js +6 -0
- package/build/read.d.ts +6 -0
- package/build/read.js +44 -0
- package/build/write.d.ts +7 -0
- package/build/write.js +32 -0
- package/package.json +1 -1
- package/src/characteristic.d.ts +9 -0
- package/src/characteristic.js +15 -0
- package/src/connect.d.ts +7 -0
- package/src/connect.js +172 -0
- package/src/connect.ts +64 -37
- package/src/devices/entralpi.d.ts +2 -0
- package/src/devices/entralpi.js +52 -0
- package/src/devices/index.d.ts +3 -0
- package/src/devices/index.js +3 -0
- package/src/devices/moterboard.d.ts +2 -0
- package/src/devices/moterboard.js +79 -0
- package/src/devices/tindeq.d.ts +17 -0
- package/src/devices/tindeq.js +37 -0
- package/src/devices/types.d.ts +20 -0
- package/src/devices/types.js +1 -0
- package/src/disconnect.d.ts +6 -0
- package/src/disconnect.js +11 -0
- package/src/index.d.ts +6 -0
- package/src/index.js +6 -0
- package/src/notify.d.ts +4 -0
- package/src/notify.js +6 -0
- package/src/read.d.ts +6 -0
- package/src/read.js +44 -0
- package/src/read.ts +7 -3
- package/src/write.d.ts +7 -0
- package/src/write.js +32 -0
package/build/index.js
CHANGED
|
@@ -1,175 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
// Battery service (Read / Notify)
|
|
8
|
-
const BATTERY_SERVICE_UUID = "0000180f-0000-1000-8000-00805f9b34fb"
|
|
9
|
-
const BATTERY_CHARACTERISTIC_UUID = "00002a19-0000-1000-8000-00805f9b34fb"
|
|
10
|
-
// Led service
|
|
11
|
-
const LED_SERVICE_UUID = "10ababcd-15e1-28ff-de13-725bea03b127"
|
|
12
|
-
const LED_01_CHARACTERISTIC_UUID = "10ab1524-15e1-28ff-de13-725bea03b127"
|
|
13
|
-
const LED_02_CHARACTERISTIC_UUID = "10ab1525-15e1-28ff-de13-725bea03b127"
|
|
14
|
-
// An implementation of Nordic Semicondutor's UART/Serial Port Emulation over Bluetooth low energy
|
|
15
|
-
const UART_SERVICE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e"
|
|
16
|
-
const UART_TX_CHARACTERISTIC_UUID = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"
|
|
17
|
-
const UART_RX_CHARACTERISTIC_UUID = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
|
|
18
|
-
// https://github.com/sepp89117/GoPro_Web_RC/blob/main/GoPro_Web_RC.html
|
|
19
|
-
const motherboard = {}
|
|
20
|
-
const connect = () => {
|
|
21
|
-
navigator.bluetooth
|
|
22
|
-
.requestDevice({
|
|
23
|
-
filters: [
|
|
24
|
-
{
|
|
25
|
-
name: "Motherboard",
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
manufacturerData: [
|
|
29
|
-
{
|
|
30
|
-
companyIdentifier: 0x2a29,
|
|
31
|
-
},
|
|
32
|
-
],
|
|
33
|
-
},
|
|
34
|
-
],
|
|
35
|
-
optionalServices: [DEVICE_SERVICE_UUID, BATTERY_SERVICE_UUID, UART_SERVICE_UUID, LED_SERVICE_UUID],
|
|
36
|
-
})
|
|
37
|
-
.then(async (device) => {
|
|
38
|
-
motherboard.device = device
|
|
39
|
-
device.addEventListener("gattserverdisconnected", onDisconnected)
|
|
40
|
-
return device.gatt?.connect()
|
|
41
|
-
})
|
|
42
|
-
.then((server) => {
|
|
43
|
-
return server?.getPrimaryServices()
|
|
44
|
-
})
|
|
45
|
-
.then((services) => {
|
|
46
|
-
// console.log(services)
|
|
47
|
-
if (services === null) {
|
|
48
|
-
console.error("getPrimaryServices is 'null'")
|
|
49
|
-
} else {
|
|
50
|
-
if (services) {
|
|
51
|
-
for (const service of services) {
|
|
52
|
-
switch (service.uuid) {
|
|
53
|
-
case DEVICE_SERVICE_UUID:
|
|
54
|
-
// getCharacteristic(service, DEVICE_SN_CHARACTERISTIC_UUID) getCharacteristic(s) called with blocklisted UUID
|
|
55
|
-
getCharacteristic(service, DEVICE_FR_CHARACTERISTIC_UUID)
|
|
56
|
-
getCharacteristic(service, DEVICE_HR_CHARACTERISTIC_UUID)
|
|
57
|
-
getCharacteristic(service, DEVICE_MN_CHARACTERISTIC_UUID)
|
|
58
|
-
break
|
|
59
|
-
case BATTERY_SERVICE_UUID:
|
|
60
|
-
getCharacteristic(service, BATTERY_CHARACTERISTIC_UUID)
|
|
61
|
-
break
|
|
62
|
-
case LED_SERVICE_UUID:
|
|
63
|
-
getCharacteristic(service, LED_01_CHARACTERISTIC_UUID)
|
|
64
|
-
getCharacteristic(service, LED_02_CHARACTERISTIC_UUID)
|
|
65
|
-
break
|
|
66
|
-
case UART_SERVICE_UUID:
|
|
67
|
-
getCharacteristic(service, UART_TX_CHARACTERISTIC_UUID)
|
|
68
|
-
getCharacteristic(service, UART_RX_CHARACTERISTIC_UUID)
|
|
69
|
-
break
|
|
70
|
-
default:
|
|
71
|
-
break
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
})
|
|
77
|
-
.catch((error) => {
|
|
78
|
-
console.log(error)
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
const disconnect = () => {
|
|
82
|
-
if (!motherboard.device) return
|
|
83
|
-
if (motherboard.device.gatt?.connected) {
|
|
84
|
-
motherboard.device.gatt?.disconnect()
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
const onDisconnected = (event) => {
|
|
88
|
-
motherboard.device = undefined
|
|
89
|
-
const device = event.target
|
|
90
|
-
console.log(`Device ${device.name} is disconnected.`)
|
|
91
|
-
}
|
|
92
|
-
const handleNotifications = (event) => {
|
|
93
|
-
const characteristic = event.target
|
|
94
|
-
const receivedData = new Uint8Array(characteristic.value.buffer)
|
|
95
|
-
// Create an array to store the parsed decimal values
|
|
96
|
-
const decimalArray = []
|
|
97
|
-
// Iterate through each byte and convert to decimal
|
|
98
|
-
for (let i = 0; i < receivedData.length; i++) {
|
|
99
|
-
decimalArray.push(receivedData[i])
|
|
100
|
-
}
|
|
101
|
-
// Convert the decimal array to a string representation
|
|
102
|
-
const receivedString = String.fromCharCode(...decimalArray)
|
|
103
|
-
// Split the string into pairs of characters
|
|
104
|
-
const hexPairs = receivedString.match(/.{1,2}/g)
|
|
105
|
-
// Convert each hexadecimal pair to decimal
|
|
106
|
-
const parsedDecimalArray = hexPairs?.map((hexPair) => parseInt(hexPair, 16))
|
|
107
|
-
// Handle different types of data
|
|
108
|
-
if (characteristic.value.byteLength === 20) {
|
|
109
|
-
// Define keys for the elements
|
|
110
|
-
const elementKeys = [
|
|
111
|
-
"frames",
|
|
112
|
-
"cycle",
|
|
113
|
-
"unknown",
|
|
114
|
-
"eleven",
|
|
115
|
-
"trippin1",
|
|
116
|
-
"pressure1",
|
|
117
|
-
"left",
|
|
118
|
-
"trippin2",
|
|
119
|
-
"pressure2",
|
|
120
|
-
"right",
|
|
121
|
-
]
|
|
122
|
-
// Create a single object with keys and values
|
|
123
|
-
const dataObject = {}
|
|
124
|
-
if (parsedDecimalArray) {
|
|
125
|
-
elementKeys.forEach((key, index) => {
|
|
126
|
-
dataObject[key] = parsedDecimalArray[index]
|
|
127
|
-
})
|
|
128
|
-
}
|
|
129
|
-
// Print the formatted string on the screen
|
|
130
|
-
console.log(dataObject)
|
|
131
|
-
} else if (characteristic.value.byteLength === 14) {
|
|
132
|
-
console.log(characteristic.value.byteLength, parsedDecimalArray)
|
|
133
|
-
} else {
|
|
134
|
-
console.log(characteristic.value.byteLength, parsedDecimalArray)
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
const getCharacteristic = (service, uuid) => {
|
|
138
|
-
service.getCharacteristic(uuid).then((characteristic) => {
|
|
139
|
-
switch (characteristic.uuid) {
|
|
140
|
-
case DEVICE_SN_CHARACTERISTIC_UUID:
|
|
141
|
-
motherboard.devSn = characteristic
|
|
142
|
-
break
|
|
143
|
-
case DEVICE_FR_CHARACTERISTIC_UUID:
|
|
144
|
-
motherboard.devFr = characteristic
|
|
145
|
-
break
|
|
146
|
-
case DEVICE_HR_CHARACTERISTIC_UUID:
|
|
147
|
-
motherboard.devHr = characteristic
|
|
148
|
-
break
|
|
149
|
-
case DEVICE_MN_CHARACTERISTIC_UUID:
|
|
150
|
-
motherboard.devMn = characteristic
|
|
151
|
-
break
|
|
152
|
-
case BATTERY_CHARACTERISTIC_UUID:
|
|
153
|
-
motherboard.bat = characteristic
|
|
154
|
-
break
|
|
155
|
-
case LED_01_CHARACTERISTIC_UUID:
|
|
156
|
-
motherboard.led01 = characteristic
|
|
157
|
-
break
|
|
158
|
-
case LED_02_CHARACTERISTIC_UUID:
|
|
159
|
-
motherboard.led02 = characteristic
|
|
160
|
-
break
|
|
161
|
-
case UART_TX_CHARACTERISTIC_UUID:
|
|
162
|
-
motherboard.uartTx = characteristic
|
|
163
|
-
break
|
|
164
|
-
case UART_RX_CHARACTERISTIC_UUID:
|
|
165
|
-
motherboard.uartRx = characteristic
|
|
166
|
-
motherboard.uartRx.startNotifications()
|
|
167
|
-
motherboard.uartRx.addEventListener("characteristicvaluechanged", handleNotifications)
|
|
168
|
-
break
|
|
169
|
-
default:
|
|
170
|
-
break
|
|
171
|
-
}
|
|
172
|
-
})
|
|
173
|
-
}
|
|
174
|
-
export default motherboard
|
|
175
|
-
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";
|
package/build/notify.js
ADDED
package/build/read.d.ts
ADDED
package/build/read.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { notifyCallback } from "./notify";
|
|
2
|
+
import { getCharacteristic } from "./characteristic";
|
|
3
|
+
/**
|
|
4
|
+
* read
|
|
5
|
+
* @param characteristic
|
|
6
|
+
*/
|
|
7
|
+
export const read = (board, serviceId, characteristicId, duration = 0) => {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
if (board.device?.gatt?.connected) {
|
|
10
|
+
const characteristic = getCharacteristic(board, serviceId, characteristicId);
|
|
11
|
+
if (characteristic) {
|
|
12
|
+
characteristic
|
|
13
|
+
.readValue()
|
|
14
|
+
.then((value) => {
|
|
15
|
+
let decodedValue;
|
|
16
|
+
const decoder = new TextDecoder("utf-8");
|
|
17
|
+
switch (characteristicId) {
|
|
18
|
+
case "level":
|
|
19
|
+
decodedValue = value.getUint8(0);
|
|
20
|
+
break;
|
|
21
|
+
default:
|
|
22
|
+
decodedValue = decoder.decode(value);
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
if (notifyCallback) {
|
|
26
|
+
notifyCallback({ uuid: characteristic.uuid, value: decodedValue });
|
|
27
|
+
}
|
|
28
|
+
setTimeout(() => {
|
|
29
|
+
resolve();
|
|
30
|
+
}, duration);
|
|
31
|
+
})
|
|
32
|
+
.catch((error) => {
|
|
33
|
+
reject(error);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
reject(new Error("Characteristic is undefined"));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
reject(new Error("Device is not connected"));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
};
|
package/build/write.d.ts
ADDED
package/build/write.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getCharacteristic } from "./characteristic";
|
|
2
|
+
/**
|
|
3
|
+
* write
|
|
4
|
+
* @param characteristic
|
|
5
|
+
* @param message
|
|
6
|
+
*/
|
|
7
|
+
export const write = (board, serviceId, characteristicId, message, duration = 0) => {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
if (board.device?.gatt?.connected) {
|
|
10
|
+
const encoder = new TextEncoder();
|
|
11
|
+
const characteristic = getCharacteristic(board, serviceId, characteristicId);
|
|
12
|
+
if (characteristic) {
|
|
13
|
+
characteristic
|
|
14
|
+
.writeValue(encoder.encode(message))
|
|
15
|
+
.then(() => {
|
|
16
|
+
setTimeout(() => {
|
|
17
|
+
resolve();
|
|
18
|
+
}, duration);
|
|
19
|
+
})
|
|
20
|
+
.catch((error) => {
|
|
21
|
+
reject(error);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
reject(new Error("Characteristics is undefined"));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
reject(new Error("Device is not connected"));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hangtime/grip-connect",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
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 Motherboard, Climbro, SmartBoard, Entralpi or Tindeq Progressor",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -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
|
+
};
|
package/src/connect.d.ts
ADDED
package/src/connect.js
ADDED
|
@@ -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
|
+
};
|
package/src/connect.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Device } from "./devices/types"
|
|
2
2
|
import { notifyCallback } from "./notify"
|
|
3
3
|
|
|
4
|
+
let server: BluetoothRemoteGATTServer
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* onDisconnected
|
|
6
8
|
* @param board
|
|
@@ -48,10 +50,10 @@ const handleNotifications = (event: Event, board: Device): void => {
|
|
|
48
50
|
"pressure2",
|
|
49
51
|
"right",
|
|
50
52
|
]
|
|
51
|
-
const dataObject = {}
|
|
53
|
+
const dataObject: { [key: string]: number } = {}
|
|
52
54
|
|
|
53
55
|
if (parsedDecimalArray) {
|
|
54
|
-
elementKeys.forEach((key, index) => {
|
|
56
|
+
elementKeys.forEach((key: string, index: number) => {
|
|
55
57
|
dataObject[key] = parsedDecimalArray[index]
|
|
56
58
|
})
|
|
57
59
|
}
|
|
@@ -76,6 +78,58 @@ const handleNotifications = (event: Event, board: Device): void => {
|
|
|
76
78
|
}
|
|
77
79
|
}
|
|
78
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* onConnected
|
|
83
|
+
* @param event
|
|
84
|
+
* @param board
|
|
85
|
+
*/
|
|
86
|
+
const onConnected = async (board: Device, onSuccess: () => void): Promise<void> => {
|
|
87
|
+
try {
|
|
88
|
+
const services = await server?.getPrimaryServices()
|
|
89
|
+
|
|
90
|
+
if (!services || services.length === 0) {
|
|
91
|
+
console.error("No services found")
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const service of services) {
|
|
96
|
+
const matchingService = board.services.find((boardService) => boardService.uuid === service.uuid)
|
|
97
|
+
|
|
98
|
+
if (matchingService) {
|
|
99
|
+
// Android bug: Introduce a delay before getting characteristics
|
|
100
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
101
|
+
|
|
102
|
+
const characteristics = await service.getCharacteristics()
|
|
103
|
+
|
|
104
|
+
for (const characteristic of matchingService.characteristics) {
|
|
105
|
+
const matchingCharacteristic = characteristics.find((char) => char.uuid === characteristic.uuid)
|
|
106
|
+
|
|
107
|
+
if (matchingCharacteristic) {
|
|
108
|
+
const element = matchingService.characteristics.find((char) => char.uuid === matchingCharacteristic.uuid)
|
|
109
|
+
if (element) {
|
|
110
|
+
element.characteristic = matchingCharacteristic
|
|
111
|
+
|
|
112
|
+
// notify
|
|
113
|
+
if (element.id === "rx") {
|
|
114
|
+
matchingCharacteristic.startNotifications()
|
|
115
|
+
matchingCharacteristic.addEventListener("characteristicvaluechanged", (event) =>
|
|
116
|
+
handleNotifications(event, board),
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
console.warn(`Characteristic ${characteristic.uuid} not found in service ${service.uuid}`)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Call the onSuccess callback after successful connection and setup
|
|
128
|
+
onSuccess()
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error(error)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
79
133
|
/**
|
|
80
134
|
* Return all service UUIDs
|
|
81
135
|
* @param device
|
|
@@ -84,7 +138,7 @@ function getAllServiceUUIDs(device: Device) {
|
|
|
84
138
|
return device.services.map((service) => service.uuid)
|
|
85
139
|
}
|
|
86
140
|
/**
|
|
87
|
-
*
|
|
141
|
+
* Connect to the BluetoothDevice
|
|
88
142
|
* @param device
|
|
89
143
|
* @param onSuccess
|
|
90
144
|
*/
|
|
@@ -112,50 +166,23 @@ export const connect = async (board: Device, onSuccess: () => void): Promise<voi
|
|
|
112
166
|
|
|
113
167
|
const device = await navigator.bluetooth.requestDevice({
|
|
114
168
|
filters: filters,
|
|
115
|
-
optionalServices: deviceServices
|
|
169
|
+
optionalServices: deviceServices
|
|
116
170
|
})
|
|
117
171
|
|
|
118
172
|
board.device = device
|
|
119
173
|
|
|
120
|
-
device.
|
|
121
|
-
|
|
122
|
-
const server = await device.gatt?.connect()
|
|
123
|
-
const services = await server?.getPrimaryServices()
|
|
124
|
-
|
|
125
|
-
if (!services || services.length === 0) {
|
|
126
|
-
console.error("No services found")
|
|
174
|
+
if (!board.device.gatt) {
|
|
175
|
+
console.error("GATT is not available on this device")
|
|
127
176
|
return
|
|
128
177
|
}
|
|
129
178
|
|
|
130
|
-
|
|
131
|
-
const matchingService = board.services.find((boardService) => boardService.uuid === service.uuid)
|
|
132
|
-
|
|
133
|
-
if (matchingService) {
|
|
134
|
-
const characteristics = await service.getCharacteristics()
|
|
179
|
+
server = await board.device?.gatt?.connect()
|
|
135
180
|
|
|
136
|
-
|
|
137
|
-
const matchingCharacteristic = characteristics.find((char) => char.uuid === characteristic.uuid)
|
|
181
|
+
board.device.addEventListener("gattserverdisconnected", (event) => onDisconnected(event, board))
|
|
138
182
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (element) {
|
|
142
|
-
element.characteristic = matchingCharacteristic
|
|
143
|
-
|
|
144
|
-
// notify
|
|
145
|
-
if (element.id === "rx") {
|
|
146
|
-
matchingCharacteristic.startNotifications()
|
|
147
|
-
matchingCharacteristic.addEventListener("characteristicvaluechanged", (event) =>
|
|
148
|
-
handleNotifications(event, board),
|
|
149
|
-
)
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
} else {
|
|
153
|
-
console.warn(`Characteristic ${characteristic.uuid} not found in service ${service.uuid}`)
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
183
|
+
if (server.connected) {
|
|
184
|
+
await onConnected(board, onSuccess);
|
|
157
185
|
}
|
|
158
|
-
onSuccess()
|
|
159
186
|
} catch (error) {
|
|
160
187
|
console.error(error)
|
|
161
188
|
}
|