@hangtime/grip-connect 0.0.8 → 0.0.10
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 +4 -8
- package/package.json +1 -1
- package/src/connect.js +14 -18
- package/src/connect.ts +13 -17
- package/src/devices/entralpi.d.ts +6 -0
- package/src/devices/entralpi.js +14 -0
- package/src/devices/entralpi.ts +15 -0
- package/src/devices/moterboard.d.ts +3 -2
- package/src/devices/moterboard.js +41 -21
- package/src/devices/moterboard.ts +48 -24
- package/src/write.js +1 -2
- package/src/write.ts +1 -2
- package/tsconfig.json +0 -2
- package/build/characteristic.d.ts +0 -9
- package/build/characteristic.js +0 -15
- package/build/connect.d.ts +0 -7
- package/build/connect.js +0 -150
- package/build/devices/entralpi.d.ts +0 -2
- package/build/devices/entralpi.js +0 -52
- package/build/devices/index.d.ts +0 -3
- package/build/devices/index.js +0 -3
- package/build/devices/moterboard.d.ts +0 -7
- package/build/devices/moterboard.js +0 -163
- package/build/devices/tindeq.d.ts +0 -17
- package/build/devices/tindeq.js +0 -37
- package/build/devices/types.d.ts +0 -20
- package/build/devices/types.js +0 -1
- package/build/disconnect.d.ts +0 -6
- package/build/disconnect.js +0 -11
- package/build/index.d.ts +0 -6
- package/build/index.js +0 -6
- package/build/notify.d.ts +0 -4
- package/build/notify.js +0 -6
- package/build/read.d.ts +0 -6
- package/build/read.js +0 -44
- package/build/write.d.ts +0 -7
- package/build/write.js +0 -33
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ Force-Sensing Hangboards / Plates used by climbers for strength measurement. Exa
|
|
|
13
13
|
|
|
14
14
|
## Roadmap
|
|
15
15
|
|
|
16
|
-
- ✅
|
|
16
|
+
- ✅ Griptonite Motherboard
|
|
17
17
|
- ✅️ Connect with devices
|
|
18
18
|
- ✅️ Read / Write / Notify using Bluetooth
|
|
19
19
|
- ➡️ Calibrate Devices
|
|
@@ -80,15 +80,11 @@ motherboardButton.addEventListener("click", () => {
|
|
|
80
80
|
await read(Motherboard, "device", "hardware", 1000)
|
|
81
81
|
await read(Motherboard, "device", "firmware", 1000)
|
|
82
82
|
|
|
83
|
-
//
|
|
84
|
-
await write(Motherboard, "uart", "tx", "",
|
|
85
|
-
await write(Motherboard, "uart", "tx", "", 0)
|
|
86
|
-
await write(Motherboard, "uart", "tx", "", 1000)
|
|
87
|
-
|
|
88
|
-
await write(Motherboard, "uart", "tx", "C3,0,0,0", 5000)
|
|
83
|
+
// read calibration (required before reading data)
|
|
84
|
+
await write(Motherboard, "uart", "tx", "C", 5000)
|
|
89
85
|
|
|
90
86
|
// start stream
|
|
91
|
-
await write(Motherboard, "uart", "tx", "
|
|
87
|
+
await write(Motherboard, "uart", "tx", "S30", 15000)
|
|
92
88
|
|
|
93
89
|
// end stream
|
|
94
90
|
await write(Motherboard, "uart", "tx", "", 0)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hangtime/grip-connect",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
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": {
|
package/src/connect.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { notifyCallback } from "./notify";
|
|
2
2
|
import { handleMotherboardData } from "./devices/moterboard";
|
|
3
|
+
import { handleEntralpiData } from "./devices/entralpi";
|
|
3
4
|
let server;
|
|
4
5
|
const receiveBuffer = [];
|
|
5
6
|
/**
|
|
@@ -22,27 +23,22 @@ const handleNotifications = (event, board) => {
|
|
|
22
23
|
const value = characteristic.value;
|
|
23
24
|
if (value) {
|
|
24
25
|
if (board.name === "Motherboard") {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
handleMotherboardData(characteristic.uuid, receivedString);
|
|
37
|
-
}
|
|
26
|
+
for (let i = 0; i < value.byteLength; i++) {
|
|
27
|
+
receiveBuffer.push(value.getUint8(i));
|
|
28
|
+
}
|
|
29
|
+
let idx;
|
|
30
|
+
while ((idx = receiveBuffer.indexOf(10)) >= 0) {
|
|
31
|
+
const line = receiveBuffer.splice(0, idx + 1).slice(0, -1); // Combine and remove LF
|
|
32
|
+
if (line.length > 0 && line[line.length - 1] === 13)
|
|
33
|
+
line.pop(); // Remove CR
|
|
34
|
+
const decoder = new TextDecoder("utf-8");
|
|
35
|
+
const receivedData = decoder.decode(new Uint8Array(line));
|
|
36
|
+
handleMotherboardData(characteristic.uuid, receivedData);
|
|
38
37
|
}
|
|
39
38
|
}
|
|
40
39
|
else if (board.name === "ENTRALPI") {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (notifyCallback) {
|
|
44
|
-
notifyCallback({ uuid: characteristic.uuid, value: value });
|
|
45
|
-
}
|
|
40
|
+
const receivedData = value.getInt16(0) / 100;
|
|
41
|
+
handleEntralpiData(characteristic.uuid, receivedData);
|
|
46
42
|
}
|
|
47
43
|
else if (board.name === "Tindeq") {
|
|
48
44
|
// TODO: handle Tindeq notify
|
package/src/connect.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Device } from "./devices/types"
|
|
2
2
|
import { notifyCallback } from "./notify"
|
|
3
3
|
import { handleMotherboardData } from "./devices/moterboard"
|
|
4
|
+
import { handleEntralpiData } from "./devices/entralpi"
|
|
4
5
|
|
|
5
6
|
let server: BluetoothRemoteGATTServer
|
|
6
7
|
const receiveBuffer: number[] = []
|
|
@@ -25,26 +26,21 @@ const handleNotifications = (event: Event, board: Device): void => {
|
|
|
25
26
|
const value = characteristic.value
|
|
26
27
|
if (value) {
|
|
27
28
|
if (board.name === "Motherboard") {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
29
|
+
for (let i = 0; i < value.byteLength; i++) {
|
|
30
|
+
receiveBuffer.push(value.getUint8(i))
|
|
31
|
+
}
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
33
|
+
let idx: number
|
|
34
|
+
while ((idx = receiveBuffer.indexOf(10)) >= 0) {
|
|
35
|
+
const line = receiveBuffer.splice(0, idx + 1).slice(0, -1) // Combine and remove LF
|
|
36
|
+
if (line.length > 0 && line[line.length - 1] === 13) line.pop() // Remove CR
|
|
37
|
+
const decoder = new TextDecoder("utf-8")
|
|
38
|
+
const receivedData = decoder.decode(new Uint8Array(line))
|
|
39
|
+
handleMotherboardData(characteristic.uuid, receivedData)
|
|
41
40
|
}
|
|
42
41
|
} else if (board.name === "ENTRALPI") {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (notifyCallback) {
|
|
46
|
-
notifyCallback({ uuid: characteristic.uuid, value: value })
|
|
47
|
-
}
|
|
42
|
+
const receivedData: number = value.getInt16(0) / 100
|
|
43
|
+
handleEntralpiData(characteristic.uuid, receivedData)
|
|
48
44
|
} else if (board.name === "Tindeq") {
|
|
49
45
|
// TODO: handle Tindeq notify
|
|
50
46
|
} else {
|
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
import { Device } from "./types";
|
|
2
2
|
export declare const Entralpi: Device;
|
|
3
|
+
/**
|
|
4
|
+
* handleEntralpiData
|
|
5
|
+
* @param uuid - Unique identifier
|
|
6
|
+
* @param receivedData - Received data string
|
|
7
|
+
*/
|
|
8
|
+
export declare function handleEntralpiData(uuid: string, receivedData: number): void;
|
package/src/devices/entralpi.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { notifyCallback } from "../notify";
|
|
1
2
|
export const Entralpi = {
|
|
2
3
|
name: "ENTRALPI",
|
|
3
4
|
services: [
|
|
@@ -50,3 +51,16 @@ export const Entralpi = {
|
|
|
50
51
|
},
|
|
51
52
|
],
|
|
52
53
|
};
|
|
54
|
+
/**
|
|
55
|
+
* handleEntralpiData
|
|
56
|
+
* @param uuid - Unique identifier
|
|
57
|
+
* @param receivedData - Received data string
|
|
58
|
+
*/
|
|
59
|
+
export function handleEntralpiData(uuid, receivedData) {
|
|
60
|
+
notifyCallback({
|
|
61
|
+
uuid,
|
|
62
|
+
value: {
|
|
63
|
+
massTotal: receivedData,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
package/src/devices/entralpi.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Device } from "./types"
|
|
2
|
+
import { notifyCallback } from "../notify"
|
|
2
3
|
|
|
3
4
|
export const Entralpi: Device = {
|
|
4
5
|
name: "ENTRALPI",
|
|
@@ -52,3 +53,17 @@ export const Entralpi: Device = {
|
|
|
52
53
|
},
|
|
53
54
|
],
|
|
54
55
|
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* handleEntralpiData
|
|
59
|
+
* @param uuid - Unique identifier
|
|
60
|
+
* @param receivedData - Received data string
|
|
61
|
+
*/
|
|
62
|
+
export function handleEntralpiData(uuid: string, receivedData: number): void {
|
|
63
|
+
notifyCallback({
|
|
64
|
+
uuid,
|
|
65
|
+
value: {
|
|
66
|
+
massTotal: receivedData,
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
}
|
|
@@ -2,6 +2,7 @@ import { Device } from "./types";
|
|
|
2
2
|
export declare const Motherboard: Device;
|
|
3
3
|
/**
|
|
4
4
|
* handleMotherboardData
|
|
5
|
-
* @param
|
|
5
|
+
* @param uuid - Unique identifier
|
|
6
|
+
* @param receivedData - Received data string
|
|
6
7
|
*/
|
|
7
|
-
export declare function handleMotherboardData(uuid: string,
|
|
8
|
+
export declare function handleMotherboardData(uuid: string, receivedData: string): void;
|
|
@@ -87,37 +87,50 @@ export const Motherboard = {
|
|
|
87
87
|
* @param calibration
|
|
88
88
|
*/
|
|
89
89
|
const applyCalibration = (sample, calibration) => {
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
// Extract the calibrated value for the zero point
|
|
91
|
+
const zeroCalibration = calibration[0][2];
|
|
92
|
+
// Initialize sign as positive
|
|
93
|
+
let sign = 1;
|
|
94
|
+
// Initialize the final calibrated value
|
|
92
95
|
let final = 0;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
// If the sample value is less than the zero calibration point
|
|
97
|
+
if (sample < zeroCalibration) {
|
|
98
|
+
// Change the sign to negative
|
|
99
|
+
sign = -1;
|
|
100
|
+
// Reflect the sample around the zero calibration point
|
|
101
|
+
sample = 2 * zeroCalibration - sample;
|
|
96
102
|
}
|
|
103
|
+
// Iterate through the calibration data
|
|
97
104
|
for (let i = 1; i < calibration.length; i++) {
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
105
|
+
// Extract the lower and upper bounds of the current calibration range
|
|
106
|
+
const calibrationStart = calibration[i - 1][2];
|
|
107
|
+
const calibrationEnd = calibration[i][2];
|
|
108
|
+
// If the sample value is within the current calibration range
|
|
109
|
+
if (sample < calibrationEnd) {
|
|
110
|
+
// Interpolate to get the calibrated value within the range
|
|
101
111
|
final =
|
|
102
112
|
calibration[i - 1][1] +
|
|
103
|
-
((sample -
|
|
113
|
+
((sample - calibrationStart) / (calibrationEnd - calibrationStart)) *
|
|
114
|
+
(calibration[i][1] - calibration[i - 1][1]);
|
|
104
115
|
break;
|
|
105
116
|
}
|
|
106
117
|
}
|
|
107
|
-
|
|
118
|
+
// Return the calibrated value with the appropriate sign (positive/negative)
|
|
119
|
+
return sign * final;
|
|
108
120
|
};
|
|
109
121
|
/**
|
|
110
122
|
* handleMotherboardData
|
|
111
|
-
* @param
|
|
123
|
+
* @param uuid - Unique identifier
|
|
124
|
+
* @param receivedData - Received data string
|
|
112
125
|
*/
|
|
113
|
-
export function handleMotherboardData(uuid,
|
|
126
|
+
export function handleMotherboardData(uuid, receivedData) {
|
|
114
127
|
const receivedTime = Date.now();
|
|
115
128
|
// Check if the line is entirely hex characters
|
|
116
|
-
const
|
|
117
|
-
//
|
|
118
|
-
if (
|
|
129
|
+
const isAllHex = /^[0-9A-Fa-f]+$/g.test(receivedData);
|
|
130
|
+
// Handle streaming packet
|
|
131
|
+
if (isAllHex && receivedData.length === PACKET_LENGTH) {
|
|
119
132
|
// Base-16 decode the string: convert hex pairs to byte values
|
|
120
|
-
const bytes = Array.from({ length:
|
|
133
|
+
const bytes = Array.from({ length: receivedData.length / 2 }, (_, i) => Number(`0x${receivedData.substring(i * 2, i * 2 + 2)}`));
|
|
121
134
|
// Translate header into packet, number of samples from the packet length
|
|
122
135
|
const packet = {
|
|
123
136
|
received: receivedTime,
|
|
@@ -126,9 +139,15 @@ export function handleMotherboardData(uuid, receivedString) {
|
|
|
126
139
|
samples: [],
|
|
127
140
|
masses: [],
|
|
128
141
|
};
|
|
142
|
+
const dataView = new DataView(new Uint8Array(bytes).buffer);
|
|
129
143
|
for (let i = 0; i < NUM_SAMPLES; i++) {
|
|
130
144
|
const sampleStart = 4 + 3 * i;
|
|
131
|
-
|
|
145
|
+
// Use DataView to read the 24-bit unsigned integer
|
|
146
|
+
const rawValue = dataView.getUint8(sampleStart) |
|
|
147
|
+
(dataView.getUint8(sampleStart + 1) << 8) |
|
|
148
|
+
(dataView.getUint8(sampleStart + 2) << 16);
|
|
149
|
+
// Ensure unsigned 32-bit integer
|
|
150
|
+
packet.samples[i] = rawValue >>> 0;
|
|
132
151
|
if (packet.samples[i] >= 0x7fffff) {
|
|
133
152
|
packet.samples[i] -= 0x1000000;
|
|
134
153
|
}
|
|
@@ -146,18 +165,19 @@ export function handleMotherboardData(uuid, receivedString) {
|
|
|
146
165
|
massTotal: Math.max(-1000, left + right + center).toFixed(3),
|
|
147
166
|
massLeft: Math.max(-1000, left).toFixed(3),
|
|
148
167
|
massRight: Math.max(-1000, right).toFixed(3),
|
|
149
|
-
|
|
168
|
+
massCenter: Math.max(-1000, center).toFixed(3),
|
|
150
169
|
},
|
|
151
170
|
});
|
|
152
171
|
}
|
|
153
|
-
else if ((
|
|
172
|
+
else if ((receivedData.match(/,/g) || []).length === 3) {
|
|
173
|
+
console.log(receivedData);
|
|
154
174
|
// if the returned notification is a calibration string add them to the array
|
|
155
|
-
const parts =
|
|
175
|
+
const parts = receivedData.split(",");
|
|
156
176
|
const numericParts = parts.map((x) => parseFloat(x));
|
|
157
177
|
CALIBRATION[numericParts[0]].push(numericParts.slice(1));
|
|
158
178
|
}
|
|
159
179
|
else {
|
|
160
180
|
// unhanded data
|
|
161
|
-
console.log(
|
|
181
|
+
console.log(receivedData);
|
|
162
182
|
}
|
|
163
183
|
}
|
|
@@ -90,28 +90,42 @@ export const Motherboard: Device = {
|
|
|
90
90
|
* @param calibration
|
|
91
91
|
*/
|
|
92
92
|
const applyCalibration = (sample: number, calibration: number[][]): number => {
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
// Extract the calibrated value for the zero point
|
|
94
|
+
const zeroCalibration: number = calibration[0][2]
|
|
95
|
+
|
|
96
|
+
// Initialize sign as positive
|
|
97
|
+
let sign: number = 1
|
|
98
|
+
|
|
99
|
+
// Initialize the final calibrated value
|
|
95
100
|
let final: number = 0
|
|
96
101
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
102
|
+
// If the sample value is less than the zero calibration point
|
|
103
|
+
if (sample < zeroCalibration) {
|
|
104
|
+
// Change the sign to negative
|
|
105
|
+
sign = -1
|
|
106
|
+
|
|
107
|
+
// Reflect the sample around the zero calibration point
|
|
108
|
+
sample = 2 * zeroCalibration - sample
|
|
100
109
|
}
|
|
101
110
|
|
|
111
|
+
// Iterate through the calibration data
|
|
102
112
|
for (let i = 1; i < calibration.length; i++) {
|
|
103
|
-
|
|
104
|
-
const
|
|
113
|
+
// Extract the lower and upper bounds of the current calibration range
|
|
114
|
+
const calibrationStart: number = calibration[i - 1][2]
|
|
115
|
+
const calibrationEnd: number = calibration[i][2]
|
|
105
116
|
|
|
106
|
-
|
|
117
|
+
// If the sample value is within the current calibration range
|
|
118
|
+
if (sample < calibrationEnd) {
|
|
119
|
+
// Interpolate to get the calibrated value within the range
|
|
107
120
|
final =
|
|
108
121
|
calibration[i - 1][1] +
|
|
109
|
-
((sample -
|
|
122
|
+
((sample - calibrationStart) / (calibrationEnd - calibrationStart)) *
|
|
123
|
+
(calibration[i][1] - calibration[i - 1][1])
|
|
110
124
|
break
|
|
111
125
|
}
|
|
112
126
|
}
|
|
113
|
-
|
|
114
|
-
return
|
|
127
|
+
// Return the calibrated value with the appropriate sign (positive/negative)
|
|
128
|
+
return sign * final
|
|
115
129
|
}
|
|
116
130
|
|
|
117
131
|
interface Packet {
|
|
@@ -124,19 +138,20 @@ interface Packet {
|
|
|
124
138
|
|
|
125
139
|
/**
|
|
126
140
|
* handleMotherboardData
|
|
127
|
-
* @param
|
|
141
|
+
* @param uuid - Unique identifier
|
|
142
|
+
* @param receivedData - Received data string
|
|
128
143
|
*/
|
|
129
|
-
export function handleMotherboardData(uuid: string,
|
|
144
|
+
export function handleMotherboardData(uuid: string, receivedData: string): void {
|
|
130
145
|
const receivedTime: number = Date.now()
|
|
131
146
|
|
|
132
147
|
// Check if the line is entirely hex characters
|
|
133
|
-
const
|
|
148
|
+
const isAllHex: boolean = /^[0-9A-Fa-f]+$/g.test(receivedData)
|
|
134
149
|
|
|
135
|
-
//
|
|
136
|
-
if (
|
|
150
|
+
// Handle streaming packet
|
|
151
|
+
if (isAllHex && receivedData.length === PACKET_LENGTH) {
|
|
137
152
|
// Base-16 decode the string: convert hex pairs to byte values
|
|
138
|
-
const bytes: number[] = Array.from({ length:
|
|
139
|
-
Number(`0x${
|
|
153
|
+
const bytes: number[] = Array.from({ length: receivedData.length / 2 }, (_, i) =>
|
|
154
|
+
Number(`0x${receivedData.substring(i * 2, i * 2 + 2)}`),
|
|
140
155
|
)
|
|
141
156
|
|
|
142
157
|
// Translate header into packet, number of samples from the packet length
|
|
@@ -148,9 +163,18 @@ export function handleMotherboardData(uuid: string, receivedString: string): voi
|
|
|
148
163
|
masses: [],
|
|
149
164
|
}
|
|
150
165
|
|
|
166
|
+
const dataView = new DataView(new Uint8Array(bytes).buffer)
|
|
167
|
+
|
|
151
168
|
for (let i = 0; i < NUM_SAMPLES; i++) {
|
|
152
169
|
const sampleStart: number = 4 + 3 * i
|
|
153
|
-
|
|
170
|
+
// Use DataView to read the 24-bit unsigned integer
|
|
171
|
+
const rawValue =
|
|
172
|
+
dataView.getUint8(sampleStart) |
|
|
173
|
+
(dataView.getUint8(sampleStart + 1) << 8) |
|
|
174
|
+
(dataView.getUint8(sampleStart + 2) << 16)
|
|
175
|
+
|
|
176
|
+
// Ensure unsigned 32-bit integer
|
|
177
|
+
packet.samples[i] = rawValue >>> 0
|
|
154
178
|
|
|
155
179
|
if (packet.samples[i] >= 0x7fffff) {
|
|
156
180
|
packet.samples[i] -= 0x1000000
|
|
@@ -158,7 +182,6 @@ export function handleMotherboardData(uuid: string, receivedString: string): voi
|
|
|
158
182
|
|
|
159
183
|
// TODO: make sure device is calibrated
|
|
160
184
|
if (!CALIBRATION[0].length) return
|
|
161
|
-
|
|
162
185
|
packet.masses[i] = applyCalibration(packet.samples[i], CALIBRATION[i])
|
|
163
186
|
}
|
|
164
187
|
|
|
@@ -172,16 +195,17 @@ export function handleMotherboardData(uuid: string, receivedString: string): voi
|
|
|
172
195
|
massTotal: Math.max(-1000, left + right + center).toFixed(3),
|
|
173
196
|
massLeft: Math.max(-1000, left).toFixed(3),
|
|
174
197
|
massRight: Math.max(-1000, right).toFixed(3),
|
|
175
|
-
|
|
198
|
+
massCenter: Math.max(-1000, center).toFixed(3),
|
|
176
199
|
},
|
|
177
200
|
})
|
|
178
|
-
} else if ((
|
|
201
|
+
} else if ((receivedData.match(/,/g) || []).length === 3) {
|
|
202
|
+
console.log(receivedData)
|
|
179
203
|
// if the returned notification is a calibration string add them to the array
|
|
180
|
-
const parts: string[] =
|
|
204
|
+
const parts: string[] = receivedData.split(",")
|
|
181
205
|
const numericParts: number[] = parts.map((x) => parseFloat(x))
|
|
182
206
|
;(CALIBRATION[numericParts[0]] as number[][]).push(numericParts.slice(1))
|
|
183
207
|
} else {
|
|
184
208
|
// unhanded data
|
|
185
|
-
console.log(
|
|
209
|
+
console.log(receivedData)
|
|
186
210
|
}
|
|
187
211
|
}
|
package/src/write.js
CHANGED
|
@@ -10,9 +10,8 @@ export const write = (board, serviceId, characteristicId, message, duration = 0)
|
|
|
10
10
|
const encoder = new TextEncoder();
|
|
11
11
|
const characteristic = getCharacteristic(board, serviceId, characteristicId);
|
|
12
12
|
if (characteristic) {
|
|
13
|
-
const value = message + "\n";
|
|
14
13
|
characteristic
|
|
15
|
-
.writeValue(encoder.encode(
|
|
14
|
+
.writeValue(encoder.encode(message))
|
|
16
15
|
.then(() => {
|
|
17
16
|
setTimeout(() => {
|
|
18
17
|
resolve();
|
package/src/write.ts
CHANGED
|
@@ -19,9 +19,8 @@ export const write = (
|
|
|
19
19
|
const characteristic = getCharacteristic(board, serviceId, characteristicId)
|
|
20
20
|
|
|
21
21
|
if (characteristic) {
|
|
22
|
-
const value = message + "\n"
|
|
23
22
|
characteristic
|
|
24
|
-
.writeValue(encoder.encode(
|
|
23
|
+
.writeValue(encoder.encode(message))
|
|
25
24
|
.then(() => {
|
|
26
25
|
setTimeout(() => {
|
|
27
26
|
resolve()
|
package/tsconfig.json
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
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;
|
package/build/characteristic.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
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/build/connect.d.ts
DELETED
package/build/connect.js
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { notifyCallback } from "./notify";
|
|
2
|
-
import { handleMotherboardData } from "./devices/moterboard";
|
|
3
|
-
let server;
|
|
4
|
-
const receiveBuffer = [];
|
|
5
|
-
/**
|
|
6
|
-
* onDisconnected
|
|
7
|
-
* @param board
|
|
8
|
-
* @param event
|
|
9
|
-
*/
|
|
10
|
-
const onDisconnected = (event, board) => {
|
|
11
|
-
board.device = undefined;
|
|
12
|
-
const device = event.target;
|
|
13
|
-
console.log(`Device ${device.name} is disconnected.`);
|
|
14
|
-
};
|
|
15
|
-
/**
|
|
16
|
-
* handleNotifications
|
|
17
|
-
* @param event
|
|
18
|
-
* @param onNotify
|
|
19
|
-
*/
|
|
20
|
-
const handleNotifications = (event, board) => {
|
|
21
|
-
const characteristic = event.target;
|
|
22
|
-
const value = characteristic.value;
|
|
23
|
-
if (value) {
|
|
24
|
-
if (board.name === "Motherboard") {
|
|
25
|
-
if (value) {
|
|
26
|
-
for (let i = 0; i < value.byteLength; i++) {
|
|
27
|
-
receiveBuffer.push(value.getUint8(i));
|
|
28
|
-
}
|
|
29
|
-
let idx;
|
|
30
|
-
while ((idx = receiveBuffer.indexOf(10)) >= 0) {
|
|
31
|
-
const line = receiveBuffer.splice(0, idx + 1).slice(0, -1); // Combine and remove LF
|
|
32
|
-
if (line.length > 0 && line[line.length - 1] === 13)
|
|
33
|
-
line.pop(); // Remove CR
|
|
34
|
-
const decoder = new TextDecoder("utf-8");
|
|
35
|
-
const receivedString = decoder.decode(new Uint8Array(line));
|
|
36
|
-
handleMotherboardData(characteristic.uuid, receivedString);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
else if (board.name === "ENTRALPI") {
|
|
41
|
-
// TODO: handle Entralpi notify
|
|
42
|
-
// characteristic.value!.getInt16(0) / 100;
|
|
43
|
-
if (notifyCallback) {
|
|
44
|
-
notifyCallback({ uuid: characteristic.uuid, value: value });
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
else if (board.name === "Tindeq") {
|
|
48
|
-
// TODO: handle Tindeq notify
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
if (notifyCallback) {
|
|
52
|
-
notifyCallback({ uuid: characteristic.uuid, value: value });
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
/**
|
|
58
|
-
* onConnected
|
|
59
|
-
* @param event
|
|
60
|
-
* @param board
|
|
61
|
-
*/
|
|
62
|
-
const onConnected = async (board, onSuccess) => {
|
|
63
|
-
try {
|
|
64
|
-
const services = await server?.getPrimaryServices();
|
|
65
|
-
if (!services || services.length === 0) {
|
|
66
|
-
console.error("No services found");
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
for (const service of services) {
|
|
70
|
-
const matchingService = board.services.find((boardService) => boardService.uuid === service.uuid);
|
|
71
|
-
if (matchingService) {
|
|
72
|
-
// Android bug: Introduce a delay before getting characteristics
|
|
73
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
74
|
-
const characteristics = await service.getCharacteristics();
|
|
75
|
-
for (const characteristic of matchingService.characteristics) {
|
|
76
|
-
const matchingCharacteristic = characteristics.find((char) => char.uuid === characteristic.uuid);
|
|
77
|
-
if (matchingCharacteristic) {
|
|
78
|
-
const element = matchingService.characteristics.find((char) => char.uuid === matchingCharacteristic.uuid);
|
|
79
|
-
if (element) {
|
|
80
|
-
element.characteristic = matchingCharacteristic;
|
|
81
|
-
// notify
|
|
82
|
-
if (element.id === "rx") {
|
|
83
|
-
matchingCharacteristic.startNotifications();
|
|
84
|
-
matchingCharacteristic.addEventListener("characteristicvaluechanged", (event) => handleNotifications(event, board));
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
console.warn(`Characteristic ${characteristic.uuid} not found in service ${service.uuid}`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
// Call the onSuccess callback after successful connection and setup
|
|
95
|
-
onSuccess();
|
|
96
|
-
}
|
|
97
|
-
catch (error) {
|
|
98
|
-
console.error(error);
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
/**
|
|
102
|
-
* Return all service UUIDs
|
|
103
|
-
* @param device
|
|
104
|
-
*/
|
|
105
|
-
function getAllServiceUUIDs(device) {
|
|
106
|
-
return device.services.map((service) => service.uuid);
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Connect to the BluetoothDevice
|
|
110
|
-
* @param device
|
|
111
|
-
* @param onSuccess
|
|
112
|
-
*/
|
|
113
|
-
export const connect = async (board, onSuccess) => {
|
|
114
|
-
try {
|
|
115
|
-
const deviceServices = getAllServiceUUIDs(board);
|
|
116
|
-
// setup filter list
|
|
117
|
-
const filters = [];
|
|
118
|
-
if (board.name) {
|
|
119
|
-
filters.push({
|
|
120
|
-
name: board.name,
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
if (board.companyId) {
|
|
124
|
-
filters.push({
|
|
125
|
-
manufacturerData: [
|
|
126
|
-
{
|
|
127
|
-
companyIdentifier: board.companyId,
|
|
128
|
-
},
|
|
129
|
-
],
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
const device = await navigator.bluetooth.requestDevice({
|
|
133
|
-
filters: filters,
|
|
134
|
-
optionalServices: deviceServices,
|
|
135
|
-
});
|
|
136
|
-
board.device = device;
|
|
137
|
-
if (!board.device.gatt) {
|
|
138
|
-
console.error("GATT is not available on this device");
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
server = await board.device?.gatt?.connect();
|
|
142
|
-
board.device.addEventListener("gattserverdisconnected", (event) => onDisconnected(event, board));
|
|
143
|
-
if (server.connected) {
|
|
144
|
-
await onConnected(board, onSuccess);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
catch (error) {
|
|
148
|
-
console.error(error);
|
|
149
|
-
}
|
|
150
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
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
|
-
};
|
package/build/devices/index.d.ts
DELETED
package/build/devices/index.js
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { notifyCallback } from "../notify";
|
|
2
|
-
const PACKET_LENGTH = 32;
|
|
3
|
-
const NUM_SAMPLES = 3;
|
|
4
|
-
const CALIBRATION = [[], [], [], []];
|
|
5
|
-
export const Motherboard = {
|
|
6
|
-
name: "Motherboard",
|
|
7
|
-
companyId: 0x2a29,
|
|
8
|
-
services: [
|
|
9
|
-
{
|
|
10
|
-
name: "Device Information",
|
|
11
|
-
id: "device",
|
|
12
|
-
uuid: "0000180a-0000-1000-8000-00805f9b34fb",
|
|
13
|
-
characteristics: [
|
|
14
|
-
// {
|
|
15
|
-
// name: 'Serial Number (Blocked)',
|
|
16
|
-
// id: 'serial'
|
|
17
|
-
// uuid: '00002a25-0000-1000-8000-00805f9b34fb'
|
|
18
|
-
// },
|
|
19
|
-
{
|
|
20
|
-
name: "Firmware Revision",
|
|
21
|
-
id: "firmware",
|
|
22
|
-
uuid: "00002a26-0000-1000-8000-00805f9b34fb",
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
name: "Hardware Revision",
|
|
26
|
-
id: "hardware",
|
|
27
|
-
uuid: "00002a27-0000-1000-8000-00805f9b34fb",
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: "Manufacturer Name",
|
|
31
|
-
id: "manufacturer",
|
|
32
|
-
uuid: "00002a29-0000-1000-8000-00805f9b34fb",
|
|
33
|
-
},
|
|
34
|
-
],
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
name: "Battery Service",
|
|
38
|
-
id: "battery",
|
|
39
|
-
uuid: "0000180f-0000-1000-8000-00805f9b34fb",
|
|
40
|
-
characteristics: [
|
|
41
|
-
{
|
|
42
|
-
name: "Battery Level",
|
|
43
|
-
id: "level",
|
|
44
|
-
uuid: "00002a19-0000-1000-8000-00805f9b34fb",
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
name: "Unknown Service",
|
|
50
|
-
id: "unknown",
|
|
51
|
-
uuid: "10ababcd-15e1-28ff-de13-725bea03b127",
|
|
52
|
-
characteristics: [
|
|
53
|
-
{
|
|
54
|
-
name: "Unknown 01",
|
|
55
|
-
id: "01",
|
|
56
|
-
uuid: "10ab1524-15e1-28ff-de13-725bea03b127",
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: "Unknown 02",
|
|
60
|
-
id: "02",
|
|
61
|
-
uuid: "10ab1525-15e1-28ff-de13-725bea03b127",
|
|
62
|
-
},
|
|
63
|
-
],
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
name: "UART Nordic Service",
|
|
67
|
-
id: "uart",
|
|
68
|
-
uuid: "6e400001-b5a3-f393-e0a9-e50e24dcca9e",
|
|
69
|
-
characteristics: [
|
|
70
|
-
{
|
|
71
|
-
name: "TX",
|
|
72
|
-
id: "tx",
|
|
73
|
-
uuid: "6e400002-b5a3-f393-e0a9-e50e24dcca9e",
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
name: "RX",
|
|
77
|
-
id: "rx",
|
|
78
|
-
uuid: "6e400003-b5a3-f393-e0a9-e50e24dcca9e",
|
|
79
|
-
},
|
|
80
|
-
],
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
};
|
|
84
|
-
/**
|
|
85
|
-
* applyCalibration
|
|
86
|
-
* @param sample
|
|
87
|
-
* @param calibration
|
|
88
|
-
*/
|
|
89
|
-
const applyCalibration = (sample, calibration) => {
|
|
90
|
-
const zeroCalib = calibration[0][2];
|
|
91
|
-
let sgn = 1;
|
|
92
|
-
let final = 0;
|
|
93
|
-
if (sample < zeroCalib) {
|
|
94
|
-
sgn = -1;
|
|
95
|
-
sample = 2 * zeroCalib - sample;
|
|
96
|
-
}
|
|
97
|
-
for (let i = 1; i < calibration.length; i++) {
|
|
98
|
-
const calibStart = calibration[i - 1][2];
|
|
99
|
-
const calibEnd = calibration[i][2];
|
|
100
|
-
if (sample < calibEnd) {
|
|
101
|
-
final =
|
|
102
|
-
calibration[i - 1][1] +
|
|
103
|
-
((sample - calibStart) / (calibEnd - calibStart)) * (calibration[i][1] - calibration[i - 1][1]);
|
|
104
|
-
break;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return sgn * final;
|
|
108
|
-
};
|
|
109
|
-
/**
|
|
110
|
-
* handleMotherboardData
|
|
111
|
-
* @param line
|
|
112
|
-
*/
|
|
113
|
-
export function handleMotherboardData(uuid, receivedString) {
|
|
114
|
-
const receivedTime = Date.now();
|
|
115
|
-
// Check if the line is entirely hex characters
|
|
116
|
-
const allHex = /^[0-9A-Fa-f]+$/g.test(receivedString);
|
|
117
|
-
// Decide if this is a streaming packet
|
|
118
|
-
if (allHex && receivedString.length === PACKET_LENGTH) {
|
|
119
|
-
// Base-16 decode the string: convert hex pairs to byte values
|
|
120
|
-
const bytes = Array.from({ length: receivedString.length / 2 }, (_, i) => Number(`0x${receivedString.substring(i * 2, i * 2 + 2)}`));
|
|
121
|
-
// Translate header into packet, number of samples from the packet length
|
|
122
|
-
const packet = {
|
|
123
|
-
received: receivedTime,
|
|
124
|
-
sampleNum: new DataView(new Uint8Array(bytes).buffer).getUint16(0, true),
|
|
125
|
-
battRaw: new DataView(new Uint8Array(bytes).buffer).getUint16(2, true),
|
|
126
|
-
samples: [],
|
|
127
|
-
masses: [],
|
|
128
|
-
};
|
|
129
|
-
for (let i = 0; i < NUM_SAMPLES; i++) {
|
|
130
|
-
const sampleStart = 4 + 3 * i;
|
|
131
|
-
packet.samples[i] = bytes[sampleStart] | (bytes[sampleStart + 1] << 8) | (bytes[sampleStart + 2] << 16);
|
|
132
|
-
if (packet.samples[i] >= 0x7fffff) {
|
|
133
|
-
packet.samples[i] -= 0x1000000;
|
|
134
|
-
}
|
|
135
|
-
// TODO: make sure device is calibrated
|
|
136
|
-
if (!CALIBRATION[0].length)
|
|
137
|
-
return;
|
|
138
|
-
packet.masses[i] = applyCalibration(packet.samples[i], CALIBRATION[i]);
|
|
139
|
-
}
|
|
140
|
-
const left = packet.masses[0];
|
|
141
|
-
const center = packet.masses[1];
|
|
142
|
-
const right = packet.masses[2];
|
|
143
|
-
notifyCallback({
|
|
144
|
-
uuid,
|
|
145
|
-
value: {
|
|
146
|
-
massTotal: Math.max(-1000, left + right + center).toFixed(3),
|
|
147
|
-
massLeft: Math.max(-1000, left).toFixed(3),
|
|
148
|
-
massRight: Math.max(-1000, right).toFixed(3),
|
|
149
|
-
massCentre: Math.max(-1000, center).toFixed(3),
|
|
150
|
-
},
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
else if ((receivedString.match(/,/g) || []).length === 3) {
|
|
154
|
-
// if the returned notification is a calibration string add them to the array
|
|
155
|
-
const parts = receivedString.split(",");
|
|
156
|
-
const numericParts = parts.map((x) => parseFloat(x));
|
|
157
|
-
CALIBRATION[numericParts[0]].push(numericParts.slice(1));
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
// unhanded data
|
|
161
|
-
console.log(receivedString);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
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
|
-
};
|
package/build/devices/tindeq.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
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
|
-
};
|
package/build/devices/types.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
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 {};
|
package/build/devices/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/build/disconnect.d.ts
DELETED
package/build/disconnect.js
DELETED
package/build/index.d.ts
DELETED
package/build/index.js
DELETED
package/build/notify.d.ts
DELETED
package/build/notify.js
DELETED
package/build/read.d.ts
DELETED
package/build/read.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
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
DELETED
package/build/write.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
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
|
-
const value = message + "\n";
|
|
14
|
-
characteristic
|
|
15
|
-
.writeValue(encoder.encode(value))
|
|
16
|
-
.then(() => {
|
|
17
|
-
setTimeout(() => {
|
|
18
|
-
resolve();
|
|
19
|
-
}, duration);
|
|
20
|
-
})
|
|
21
|
-
.catch((error) => {
|
|
22
|
-
reject(error);
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
reject(new Error("Characteristics is undefined"));
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
reject(new Error("Device is not connected"));
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
};
|