@hangtime/grip-connect 0.2.1 → 0.2.3
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 +42 -35
- package/package.json +5 -3
- package/src/battery.d.ts +6 -0
- package/src/battery.js +19 -0
- package/src/calibration.d.ts +6 -0
- package/src/calibration.js +15 -0
- package/src/characteristic.d.ts +9 -0
- package/src/characteristic.js +15 -0
- package/src/commands/climbro.d.ts +6 -0
- package/src/commands/climbro.js +5 -0
- package/src/commands/entralpi.d.ts +6 -0
- package/src/commands/entralpi.js +5 -0
- package/src/commands/index.d.ts +5 -0
- package/src/commands/index.js +5 -0
- package/src/commands/motherboard.d.ts +6 -0
- package/src/commands/motherboard.js +13 -0
- package/src/commands/progressor.d.ts +15 -0
- package/src/commands/progressor.js +27 -0
- package/src/commands/smartboard.d.ts +6 -0
- package/src/commands/smartboard.js +5 -0
- package/src/commands/types.d.ts +18 -0
- package/src/commands/types.js +1 -0
- package/src/connect.d.ts +7 -0
- package/src/connect.js +159 -0
- package/src/connect.ts +3 -58
- package/src/data.d.ts +9 -0
- package/src/data.js +157 -0
- package/src/data.ts +45 -0
- package/src/declarations.d.ts +1 -0
- package/src/devices/climbro.d.ts +2 -0
- package/src/devices/climbro.js +4 -0
- package/src/devices/entralpi.d.ts +2 -0
- package/src/devices/entralpi.js +52 -0
- package/src/devices/index.d.ts +5 -0
- package/src/devices/index.js +5 -0
- package/src/devices/motherboard.d.ts +2 -0
- package/src/devices/motherboard.js +79 -0
- package/src/devices/progressor.d.ts +2 -0
- package/src/devices/progressor.js +34 -0
- package/src/devices/smartboard.d.ts +2 -0
- package/src/devices/smartboard.js +4 -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 +10 -0
- package/src/index.d.ts +10 -0
- package/src/index.js +12 -0
- package/src/info.d.ts +6 -0
- package/src/info.js +23 -0
- package/src/is-connected.d.ts +7 -0
- package/src/is-connected.js +10 -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 +45 -0
- package/src/stop.d.ts +6 -0
- package/src/stop.js +18 -0
- package/src/stream.d.ts +6 -0
- package/src/stream.js +35 -0
- package/src/write.d.ts +8 -0
- package/src/write.js +41 -0
package/README.md
CHANGED
|
@@ -4,47 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
The objective of this project is to create a Web Bluetooth API client that can establish connections with various
|
|
6
6
|
Force-Sensing Hangboards / Plates used by climbers for strength measurement. Examples of such hangboards include the
|
|
7
|
-
[Motherboard](https://griptonite.io/shop/motherboard/), [Climbro](https://climbro.com/),
|
|
7
|
+
[Griptonite Motherboard](https://griptonite.io/shop/motherboard/), [Climbro](https://climbro.com/),
|
|
8
8
|
[SmartBoard](https://www.smartboard-climbing.com/), [Entralpi](https://entralpi.com/) or
|
|
9
9
|
[Tindeq Progressor](https://tindeq.com/)
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Learn more: [Docs](https://stevie-ray.github.io/hangtime-grip-connect/) -
|
|
12
12
|
[Browser Support](https://caniuse.com/web-bluetooth)
|
|
13
13
|
|
|
14
|
-
##
|
|
15
|
-
|
|
16
|
-
**Help wanted:** Do you own any of these devices? Use Google Chrome's Bluetooth Internals
|
|
17
|
-
`chrome://bluetooth-internals/#devices` and press `Start Scan` to look for your device, click on `Inspect` and share all
|
|
18
|
-
available services with us.
|
|
19
|
-
|
|
20
|
-
- ✅ Griptonite Motherboard
|
|
21
|
-
- ✅️ Connect with devices
|
|
22
|
-
- ✅️ Read / Write / Notify using Bluetooth
|
|
23
|
-
- ✅️ Output weight/force stream
|
|
24
|
-
- ✅ Tindeq Progressor
|
|
25
|
-
- ✅️ Connect with devices
|
|
26
|
-
- ✅️ Read / Write / Notify using Bluetooth
|
|
27
|
-
- ✅️ Output weight/force stream
|
|
28
|
-
- ✅ Entralpi
|
|
29
|
-
- ✅️ Connect with devices
|
|
30
|
-
- ✅️ Read / Write / Notify using Bluetooth
|
|
31
|
-
- ✅️️ Output weight/force stream
|
|
32
|
-
- ➡️ Climbro
|
|
33
|
-
- ➡️ Connect with devices
|
|
34
|
-
- ➡️ Read / Write / Notify using Bluetooth
|
|
35
|
-
- ➡️ Output weight/force stream
|
|
36
|
-
- ➡️ SmartBoard
|
|
37
|
-
- ➡️ Connect with devices
|
|
38
|
-
- ➡️ Read / Write / Notify using Bluetooth
|
|
39
|
-
- ➡️ Output weight/force stream
|
|
40
|
-
|
|
41
|
-
## Development
|
|
14
|
+
## Try it out
|
|
42
15
|
|
|
43
|
-
|
|
44
|
-
git clone https://github.com/Stevie-Ray/hangtime-grip-connect
|
|
45
|
-
cd hangtime-grip-connect
|
|
46
|
-
npm install
|
|
47
|
-
```
|
|
16
|
+
[Chart](https://grip-connect.vercel.app/) - [Flappy Bird](https://grip-connect-flappy-bird.vercel.app/)
|
|
48
17
|
|
|
49
18
|
## Install
|
|
50
19
|
|
|
@@ -89,6 +58,44 @@ motherboardButton.addEventListener("click", () => {
|
|
|
89
58
|
})
|
|
90
59
|
```
|
|
91
60
|
|
|
61
|
+
## Roadmap
|
|
62
|
+
|
|
63
|
+
**Help wanted:** Do you own any of these devices? Use Google Chrome's Bluetooth Internals
|
|
64
|
+
`chrome://bluetooth-internals/#devices` and press `Start Scan` to look for your device, click on `Inspect` and share all
|
|
65
|
+
available services with us.
|
|
66
|
+
|
|
67
|
+
### Device support
|
|
68
|
+
|
|
69
|
+
- ✅ Griptonite Motherboard
|
|
70
|
+
- ✅ Tindeq Progressor
|
|
71
|
+
- ✅ Entralpi
|
|
72
|
+
- ➡️ Climbro
|
|
73
|
+
- ➡️ SmartBoard
|
|
74
|
+
|
|
75
|
+
### Features
|
|
76
|
+
|
|
77
|
+
- ✅ Connect
|
|
78
|
+
- ✅ Disconnect
|
|
79
|
+
- ✅ Start data stream (live data)
|
|
80
|
+
- ✅ Stop data stream
|
|
81
|
+
- ✅ Battery status
|
|
82
|
+
- ✅ Read calibration
|
|
83
|
+
- ✅ Device info (firmware / serial etc.)
|
|
84
|
+
- ✅ Check if device is connected
|
|
85
|
+
- ➡️ Peak load
|
|
86
|
+
- ➡️ Endurance
|
|
87
|
+
- ➡️ Rate of Force Development (RFD)
|
|
88
|
+
- ➡️ Repeaters
|
|
89
|
+
- ➡️ Critical Force
|
|
90
|
+
|
|
91
|
+
## Development
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
git clone https://github.com/Stevie-Ray/hangtime-grip-connect
|
|
95
|
+
cd hangtime-grip-connect
|
|
96
|
+
npm install
|
|
97
|
+
```
|
|
98
|
+
|
|
92
99
|
## Credits
|
|
93
100
|
|
|
94
101
|
A special thank you to:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hangtime/grip-connect",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "A client that can establish connections with various Force-Sensing Hangboards/Plates used by climbers for strength measurement. Examples of such hangboards include the Griptonite Motherboard, Climbro, SmartBoard, Entralpi or Tindeq Progressor",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
},
|
|
9
9
|
"author": "Stevie-Ray Hartog <mail@stevie-ray.nl>",
|
|
10
10
|
"license": "BSD-2-Clause",
|
|
11
|
-
"devDependencies": {},
|
|
12
11
|
"repository": {
|
|
13
12
|
"type": "git",
|
|
14
13
|
"url": "git+https://github.com/Stevie-Ray/hangtime-grip-connect.git"
|
|
@@ -25,5 +24,8 @@
|
|
|
25
24
|
"bugs": {
|
|
26
25
|
"url": "https://github.com/Stevie-Ray/hangtime-grip-connect/issues"
|
|
27
26
|
},
|
|
28
|
-
"homepage": "https://stevie-ray.github.io/hangtime-grip-connect/"
|
|
27
|
+
"homepage": "https://stevie-ray.github.io/hangtime-grip-connect/",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@aksel/structjs": "^1.0.0"
|
|
30
|
+
}
|
|
29
31
|
}
|
package/src/battery.d.ts
ADDED
package/src/battery.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { write } from "./write";
|
|
2
|
+
import { read } from "./read";
|
|
3
|
+
import { isConnected } from "./is-connected";
|
|
4
|
+
import { Motherboard, Progressor } from "./devices";
|
|
5
|
+
import { ProgressorCommands } from "./commands";
|
|
6
|
+
/**
|
|
7
|
+
* Get Battery / Voltage information
|
|
8
|
+
* @param board
|
|
9
|
+
*/
|
|
10
|
+
export const battery = async (board) => {
|
|
11
|
+
if (isConnected(board)) {
|
|
12
|
+
if (board.name === "Motherboard") {
|
|
13
|
+
await read(Motherboard, "battery", "level", 250);
|
|
14
|
+
}
|
|
15
|
+
if (board.name && board.name.startsWith("Progressor")) {
|
|
16
|
+
await write(Progressor, "progressor", "tx", ProgressorCommands.GET_BATT_VLTG, 250);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { isConnected } from "./is-connected";
|
|
2
|
+
import { write } from "./write";
|
|
3
|
+
import { Motherboard } from "./devices";
|
|
4
|
+
import { MotherboardCommands } from "./commands";
|
|
5
|
+
/**
|
|
6
|
+
* write command to get calibration
|
|
7
|
+
* @param board
|
|
8
|
+
*/
|
|
9
|
+
export const calibration = async (board) => {
|
|
10
|
+
if (isConnected(board)) {
|
|
11
|
+
if (board.name === "Motherboard") {
|
|
12
|
+
await write(Motherboard, "uart", "tx", MotherboardCommands.GET_CALIBRATION, 2500);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
};
|
|
@@ -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,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Warning:
|
|
3
|
+
* Using other commands can seriously harm your device
|
|
4
|
+
*/
|
|
5
|
+
export const MotherboardCommands = {
|
|
6
|
+
GET_SERIAL: "#",
|
|
7
|
+
START_WEIGHT_MEAS: "S30",
|
|
8
|
+
STOP_WEIGHT_MEAS: "", // All commands will stop the data stream.
|
|
9
|
+
GET_CALIBRATION: "C",
|
|
10
|
+
SLEEP: 0,
|
|
11
|
+
GET_TEXT: "T",
|
|
12
|
+
DEBUG_STREAM: "D",
|
|
13
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Commands } from "../commands/types";
|
|
2
|
+
/**
|
|
3
|
+
* Warning:
|
|
4
|
+
* Using other commands can seriously harm your device
|
|
5
|
+
*/
|
|
6
|
+
export declare const ProgressorCommands: Commands;
|
|
7
|
+
/**
|
|
8
|
+
* The Progressor returns a Uint8Array.
|
|
9
|
+
* The first item [0] is the type of response it returns
|
|
10
|
+
*/
|
|
11
|
+
export declare const ProgressorResponses: {
|
|
12
|
+
COMMAND_RESPONSE: number;
|
|
13
|
+
WEIGHT_MEASURE: number;
|
|
14
|
+
LOW_BATTERY_WARNING: number;
|
|
15
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Warning:
|
|
3
|
+
* Using other commands can seriously harm your device
|
|
4
|
+
*/
|
|
5
|
+
export const ProgressorCommands = {
|
|
6
|
+
TARE_SCALE: "d", // 0x64,
|
|
7
|
+
START_WEIGHT_MEAS: "e", // 0x65,
|
|
8
|
+
STOP_WEIGHT_MEAS: "f", // 0x66,
|
|
9
|
+
START_PEAK_RFD_MEAS: "g", // 0x67,
|
|
10
|
+
START_PEAK_RFD_MEAS_SERIES: "h", // 0x68,
|
|
11
|
+
ADD_CALIB_POINT: "i", // 0x69,
|
|
12
|
+
SAVE_CALIB: "j", // 0x6a,
|
|
13
|
+
GET_FW_VERSION: "k", // 0x6b,
|
|
14
|
+
GET_ERR_INFO: "l", // 0x6c,
|
|
15
|
+
CLR_ERR_INFO: "m", // 0x6d,
|
|
16
|
+
SLEEP: "n", // 0x6e,
|
|
17
|
+
GET_BATT_VLTG: "o", // 0x6f,
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* The Progressor returns a Uint8Array.
|
|
21
|
+
* The first item [0] is the type of response it returns
|
|
22
|
+
*/
|
|
23
|
+
export const ProgressorResponses = {
|
|
24
|
+
COMMAND_RESPONSE: 0,
|
|
25
|
+
WEIGHT_MEASURE: 1,
|
|
26
|
+
LOW_BATTERY_WARNING: 2,
|
|
27
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface Commands {
|
|
2
|
+
START_WEIGHT_MEAS?: string;
|
|
3
|
+
STOP_WEIGHT_MEAS?: string;
|
|
4
|
+
SLEEP?: number | string;
|
|
5
|
+
GET_SERIAL?: string;
|
|
6
|
+
GET_TEXT?: string;
|
|
7
|
+
DEBUG_STREAM?: string;
|
|
8
|
+
GET_CALIBRATION?: string;
|
|
9
|
+
TARE_SCALE?: string;
|
|
10
|
+
START_PEAK_RFD_MEAS?: string;
|
|
11
|
+
START_PEAK_RFD_MEAS_SERIES?: string;
|
|
12
|
+
ADD_CALIB_POINT?: string;
|
|
13
|
+
SAVE_CALIB?: string;
|
|
14
|
+
GET_FW_VERSION?: string;
|
|
15
|
+
GET_ERR_INFO?: string;
|
|
16
|
+
CLR_ERR_INFO?: string;
|
|
17
|
+
GET_BATT_VLTG?: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/src/connect.d.ts
ADDED
package/src/connect.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { notifyCallback } from "./notify";
|
|
2
|
+
import { handleMotherboardData, handleProgressorData } from "./data";
|
|
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
|
+
for (let i = 0; i < value.byteLength; i++) {
|
|
26
|
+
receiveBuffer.push(value.getUint8(i));
|
|
27
|
+
}
|
|
28
|
+
let idx;
|
|
29
|
+
while ((idx = receiveBuffer.indexOf(10)) >= 0) {
|
|
30
|
+
const line = receiveBuffer.splice(0, idx + 1).slice(0, -1); // Combine and remove LF
|
|
31
|
+
if (line.length > 0 && line[line.length - 1] === 13)
|
|
32
|
+
line.pop(); // Remove CR
|
|
33
|
+
const decoder = new TextDecoder("utf-8");
|
|
34
|
+
const receivedData = decoder.decode(new Uint8Array(line));
|
|
35
|
+
handleMotherboardData(characteristic.uuid, receivedData);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else if (board.name === "ENTRALPI") {
|
|
39
|
+
if (value.buffer) {
|
|
40
|
+
const buffer = value.buffer;
|
|
41
|
+
const rawData = new DataView(buffer);
|
|
42
|
+
const receivedData = rawData.getUint16(0) / 100;
|
|
43
|
+
if (notifyCallback) {
|
|
44
|
+
notifyCallback({
|
|
45
|
+
uuid: characteristic.uuid,
|
|
46
|
+
value: {
|
|
47
|
+
massTotal: receivedData,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else if (board.name && board.name.startsWith("Progressor")) {
|
|
54
|
+
if (value.buffer) {
|
|
55
|
+
const buffer = value.buffer;
|
|
56
|
+
const rawData = new DataView(buffer);
|
|
57
|
+
handleProgressorData(characteristic.uuid, rawData);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
if (notifyCallback) {
|
|
62
|
+
notifyCallback({ uuid: characteristic.uuid, value: value });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* onConnected
|
|
69
|
+
* @param event
|
|
70
|
+
* @param board
|
|
71
|
+
*/
|
|
72
|
+
const onConnected = async (board, onSuccess) => {
|
|
73
|
+
try {
|
|
74
|
+
const services = await server?.getPrimaryServices();
|
|
75
|
+
if (!services || services.length === 0) {
|
|
76
|
+
console.error("No services found");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
for (const service of services) {
|
|
80
|
+
const matchingService = board.services.find((boardService) => boardService.uuid === service.uuid);
|
|
81
|
+
if (matchingService) {
|
|
82
|
+
// Android bug: Introduce a delay before getting characteristics
|
|
83
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
84
|
+
const characteristics = await service.getCharacteristics();
|
|
85
|
+
for (const characteristic of matchingService.characteristics) {
|
|
86
|
+
const matchingCharacteristic = characteristics.find((char) => char.uuid === characteristic.uuid);
|
|
87
|
+
if (matchingCharacteristic) {
|
|
88
|
+
const element = matchingService.characteristics.find((char) => char.uuid === matchingCharacteristic.uuid);
|
|
89
|
+
if (element) {
|
|
90
|
+
element.characteristic = matchingCharacteristic;
|
|
91
|
+
// notify
|
|
92
|
+
if (element.id === "rx") {
|
|
93
|
+
matchingCharacteristic.startNotifications();
|
|
94
|
+
matchingCharacteristic.addEventListener("characteristicvaluechanged", (event) => handleNotifications(event, board));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.warn(`Characteristic ${characteristic.uuid} not found in service ${service.uuid}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Call the onSuccess callback after successful connection and setup
|
|
105
|
+
onSuccess();
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
console.error(error);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Return all service UUIDs
|
|
113
|
+
* @param device
|
|
114
|
+
*/
|
|
115
|
+
const getAllServiceUUIDs = (device) => {
|
|
116
|
+
return device.services.map((service) => service.uuid);
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Connect to the BluetoothDevice
|
|
120
|
+
* @param device
|
|
121
|
+
* @param onSuccess
|
|
122
|
+
*/
|
|
123
|
+
export const connect = async (board, onSuccess) => {
|
|
124
|
+
try {
|
|
125
|
+
const deviceServices = getAllServiceUUIDs(board);
|
|
126
|
+
// setup filter list
|
|
127
|
+
const filters = [];
|
|
128
|
+
if (board.name) {
|
|
129
|
+
const filterName = board.name === "Progressor" ? { namePrefix: board.name } : { name: board.name };
|
|
130
|
+
filters.push(filterName);
|
|
131
|
+
}
|
|
132
|
+
if (board.companyId) {
|
|
133
|
+
filters.push({
|
|
134
|
+
manufacturerData: [
|
|
135
|
+
{
|
|
136
|
+
companyIdentifier: board.companyId,
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const device = await navigator.bluetooth.requestDevice({
|
|
142
|
+
filters: filters,
|
|
143
|
+
optionalServices: deviceServices,
|
|
144
|
+
});
|
|
145
|
+
board.device = device;
|
|
146
|
+
if (!board.device.gatt) {
|
|
147
|
+
console.error("GATT is not available on this device");
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
server = await board.device?.gatt?.connect();
|
|
151
|
+
board.device.addEventListener("gattserverdisconnected", (event) => onDisconnected(event, board));
|
|
152
|
+
if (server.connected) {
|
|
153
|
+
await onConnected(board, onSuccess);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
console.error(error);
|
|
158
|
+
}
|
|
159
|
+
};
|
package/src/connect.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { Device } from "./devices/types"
|
|
2
|
-
import { ProgressorCommands, ProgressorResponses } from "./commands/progressor"
|
|
3
2
|
import { notifyCallback } from "./notify"
|
|
4
|
-
import { handleMotherboardData } from "./data"
|
|
5
|
-
import { lastWrite } from "./write"
|
|
3
|
+
import { handleMotherboardData, handleProgressorData } from "./data"
|
|
6
4
|
|
|
7
5
|
let server: BluetoothRemoteGATTServer
|
|
8
6
|
const receiveBuffer: number[] = []
|
|
@@ -26,18 +24,6 @@ const handleNotifications = (event: Event, board: Device): void => {
|
|
|
26
24
|
const characteristic: BluetoothRemoteGATTCharacteristic = event.target as BluetoothRemoteGATTCharacteristic
|
|
27
25
|
const value: DataView | undefined = characteristic.value
|
|
28
26
|
|
|
29
|
-
function _unpackFloat(bytes: Uint8Array) {
|
|
30
|
-
const view = new DataView(new ArrayBuffer(4))
|
|
31
|
-
for (let i = 0; i < 4; i++) {
|
|
32
|
-
view.setUint8(i, bytes[i])
|
|
33
|
-
}
|
|
34
|
-
return view.getFloat32(0, true)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// function _unpackInt(bytes: Uint8Array) {
|
|
38
|
-
// return (bytes[1] << 8) + bytes[0];
|
|
39
|
-
// }
|
|
40
|
-
|
|
41
27
|
if (value) {
|
|
42
28
|
if (board.name === "Motherboard") {
|
|
43
29
|
for (let i: number = 0; i < value.byteLength; i++) {
|
|
@@ -69,49 +55,8 @@ const handleNotifications = (event: Event, board: Device): void => {
|
|
|
69
55
|
} else if (board.name && board.name.startsWith("Progressor")) {
|
|
70
56
|
if (value.buffer) {
|
|
71
57
|
const buffer: ArrayBuffer = value.buffer
|
|
72
|
-
const rawData:
|
|
73
|
-
|
|
74
|
-
const tare: number = 0 // todo: add tare
|
|
75
|
-
if (kind === ProgressorResponses.WEIGHT_MEASURE) {
|
|
76
|
-
for (let i = 2; i < rawData.length; i += 6) {
|
|
77
|
-
const weight = _unpackFloat(rawData.slice(i, i + 4))
|
|
78
|
-
// let useconds = _unpackInt(rawData.slice(i + 4, i + 6));
|
|
79
|
-
// let now = useconds / 1.0e6;
|
|
80
|
-
|
|
81
|
-
if (notifyCallback) {
|
|
82
|
-
notifyCallback({
|
|
83
|
-
uuid: characteristic.uuid,
|
|
84
|
-
value: {
|
|
85
|
-
massTotal: weight - tare,
|
|
86
|
-
},
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
} else if (kind === ProgressorResponses.COMMAND_RESPONSE) {
|
|
91
|
-
if (!lastWrite) return
|
|
92
|
-
|
|
93
|
-
let value: string = ""
|
|
94
|
-
|
|
95
|
-
if (lastWrite === ProgressorCommands.GET_BATT_VLTG) {
|
|
96
|
-
const vdd = new DataView(rawData.buffer, 2).getUint32(0, true)
|
|
97
|
-
value = `Battery level = ${vdd} [mV]`
|
|
98
|
-
} else if (lastWrite === ProgressorCommands.GET_FW_VERSION) {
|
|
99
|
-
value = new TextDecoder().decode(rawData.slice(2))
|
|
100
|
-
} else if (lastWrite === ProgressorCommands.GET_ERR_INFO) {
|
|
101
|
-
value = new TextDecoder().decode(rawData.slice(2))
|
|
102
|
-
}
|
|
103
|
-
if (notifyCallback) {
|
|
104
|
-
notifyCallback({ uuid: characteristic.uuid, value: value })
|
|
105
|
-
}
|
|
106
|
-
} else if (kind === ProgressorResponses.LOW_BATTERY_WARNING) {
|
|
107
|
-
if (notifyCallback) {
|
|
108
|
-
notifyCallback({ uuid: characteristic.uuid, value: "low power warning" })
|
|
109
|
-
}
|
|
110
|
-
} else {
|
|
111
|
-
if (notifyCallback) {
|
|
112
|
-
notifyCallback({ uuid: characteristic.uuid, value: `unknown message kind ${kind}` })
|
|
113
|
-
}
|
|
114
|
-
}
|
|
58
|
+
const rawData: DataView = new DataView(buffer)
|
|
59
|
+
handleProgressorData(characteristic.uuid, rawData)
|
|
115
60
|
}
|
|
116
61
|
} else {
|
|
117
62
|
if (notifyCallback) {
|
package/src/data.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const CALIBRATION: never[][];
|
|
2
|
+
/**
|
|
3
|
+
* handleMotherboardData
|
|
4
|
+
*
|
|
5
|
+
* @param uuid - Unique identifier
|
|
6
|
+
* @param receivedData - Received data string
|
|
7
|
+
*/
|
|
8
|
+
export declare const handleMotherboardData: (uuid: string, receivedData: string) => void;
|
|
9
|
+
export declare const handleProgressorData: (uuid: string, data: DataView) => void;
|