@hangtime/grip-connect 0.3.4 → 0.3.6
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 +12 -8
- package/dist/battery.d.ts +7 -0
- package/dist/battery.js +25 -0
- package/dist/calibration.d.ts +7 -0
- package/dist/calibration.js +19 -0
- package/dist/characteristic.d.ts +9 -0
- package/dist/characteristic.js +20 -0
- package/dist/commands/climbro.d.ts +6 -0
- package/dist/commands/climbro.js +5 -0
- package/dist/commands/entralpi.d.ts +6 -0
- package/dist/commands/entralpi.js +5 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.js +6 -0
- package/dist/commands/kilterboard.d.ts +23 -0
- package/dist/commands/kilterboard.js +24 -0
- package/dist/commands/motherboard.d.ts +6 -0
- package/dist/commands/motherboard.js +13 -0
- package/dist/commands/mysmartboard.d.ts +6 -0
- package/dist/commands/mysmartboard.js +5 -0
- package/dist/commands/progressor.d.ts +17 -0
- package/dist/commands/progressor.js +30 -0
- package/dist/commands/wh-c06.d.ts +6 -0
- package/dist/commands/wh-c06.js +5 -0
- package/dist/connect.d.ts +7 -0
- package/dist/connect.js +159 -0
- package/dist/data/entralpi.d.ts +5 -0
- package/dist/data/entralpi.js +30 -0
- package/dist/data/index.d.ts +4 -0
- package/dist/data/index.js +4 -0
- package/dist/data/motherboard.d.ts +6 -0
- package/dist/data/motherboard.js +133 -0
- package/dist/data/progressor.d.ts +5 -0
- package/dist/data/progressor.js +72 -0
- package/dist/data/wh-c06.d.ts +5 -0
- package/dist/data/wh-c06.js +35 -0
- package/dist/devices/climbro.d.ts +6 -0
- package/dist/devices/climbro.js +8 -0
- package/dist/devices/entralpi.d.ts +5 -0
- package/dist/devices/entralpi.js +59 -0
- package/dist/devices/index.d.ts +7 -0
- package/dist/devices/index.js +7 -0
- package/dist/devices/kilterboard.d.ts +6 -0
- package/dist/devices/kilterboard.js +30 -0
- package/dist/devices/motherboard.d.ts +5 -0
- package/dist/devices/motherboard.js +81 -0
- package/dist/devices/mysmartboard.d.ts +6 -0
- package/dist/devices/mysmartboard.js +8 -0
- package/dist/devices/progressor.d.ts +5 -0
- package/dist/devices/progressor.js +37 -0
- package/dist/devices/wh-c06.d.ts +6 -0
- package/dist/devices/wh-c06.js +17 -0
- package/dist/disconnect.d.ts +6 -0
- package/dist/disconnect.js +12 -0
- package/dist/download.d.ts +10 -0
- package/dist/download.js +50 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +22 -0
- package/dist/info.d.ts +7 -0
- package/dist/info.js +30 -0
- package/dist/is-connected.d.ts +7 -0
- package/dist/is-connected.js +13 -0
- package/dist/led.d.ts +19 -0
- package/dist/led.js +183 -0
- package/dist/notify.d.ts +16 -0
- package/dist/notify.js +14 -0
- package/dist/read.d.ts +10 -0
- package/dist/read.js +49 -0
- package/dist/stop.d.ts +7 -0
- package/dist/stop.js +21 -0
- package/dist/stream.d.ts +8 -0
- package/dist/stream.js +41 -0
- package/dist/struct/index.d.ts +9 -0
- package/dist/struct/index.js +203 -0
- package/dist/tare.d.ts +12 -0
- package/dist/tare.js +70 -0
- package/dist/types/commands.d.ts +18 -0
- package/dist/types/commands.js +1 -0
- package/dist/types/devices.d.ts +38 -0
- package/dist/types/devices.js +1 -0
- package/dist/types/download.d.ts +15 -0
- package/dist/types/download.js +1 -0
- package/dist/types/notify.d.ts +14 -0
- package/dist/types/notify.js +1 -0
- package/dist/write.d.ts +16 -0
- package/dist/write.js +57 -0
- package/package.json +3 -2
- package/src/commands/index.ts +1 -1
- package/src/commands/kilterboard.ts +23 -0
- package/src/commands/{musclemeter.ts → wh-c06.ts} +1 -1
- package/src/connect.ts +33 -8
- package/src/data/entralpi.ts +37 -0
- package/src/data/index.ts +7 -0
- package/src/{data.ts → data/motherboard.ts} +14 -105
- package/src/data/progressor.ts +72 -0
- package/src/data/wh-c06.ts +43 -0
- package/src/devices/index.ts +1 -1
- package/src/devices/wh-c06.ts +19 -0
- package/src/index.ts +4 -1
- package/src/led.ts +196 -0
- package/src/notify.ts +1 -1
- package/src/read.ts +1 -6
- package/src/stream.ts +2 -2
- package/src/struct/index.ts +45 -21
- package/src/tare.ts +9 -9
- package/src/write.ts +16 -12
- package/tsconfig.json +3 -1
- package/src/devices/musclemeter.ts +0 -10
package/README.md
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
**Force-Sensing Climbing Training**
|
|
4
4
|
|
|
5
5
|
The objective of this project is to create a Web Bluetooth API client that can establish connections with various
|
|
6
|
-
Force-Sensing Hangboards / Plates / LED system boards used by climbers
|
|
7
|
-
|
|
8
|
-
[
|
|
9
|
-
[
|
|
10
|
-
[
|
|
6
|
+
Force-Sensing Hangboards / Dynamometers / Plates / LED system boards used by climbers. Examples of such tools include
|
|
7
|
+
the [Griptonite Motherboard](https://griptonite.io/shop/motherboard/), [Climbro](https://climbro.com/),
|
|
8
|
+
[mySmartBoard](https://www.smartboard-climbing.com/), [Entralpi](https://entralpi.com/),
|
|
9
|
+
[Tindeq Progressor](https://tindeq.com/) or
|
|
10
|
+
[Weiheng WH-C06](https://weihengmanufacturer.com/products/wh-c06-bluetooth-300kg-hanging-scale/) also sold as
|
|
11
|
+
[MAT Muscle Meter](https://www.matassessment.com/musclemeter).
|
|
11
12
|
|
|
12
13
|
And LED system boards from [Aurora Climbing](https://auroraclimbing.com/) like the
|
|
13
14
|
[Kilter Board](https://settercloset.com/pages/the-kilter-board),
|
|
@@ -91,10 +92,11 @@ available services with us.
|
|
|
91
92
|
- ✅ Griptonite Motherboard
|
|
92
93
|
- ✅ Tindeq Progressor
|
|
93
94
|
- ⏳ Entralpi (not verified)
|
|
94
|
-
- ⏳ Kilterboard (
|
|
95
|
+
- ⏳ Kilterboard (see example)
|
|
96
|
+
- ⏳ Weiheng WH-C06 / MAT Muscle Meter
|
|
97
|
+
- Enable: `chrome://flags#enable-experimental-web-platform-features`
|
|
95
98
|
- ➡️ Climbro
|
|
96
99
|
- ➡️ mySmartBoard
|
|
97
|
-
- ➡️ MAT Muscle Meter
|
|
98
100
|
|
|
99
101
|
### Features
|
|
100
102
|
|
|
@@ -133,7 +135,9 @@ A special thank you to:
|
|
|
133
135
|
- [@Phil9l](https://github.com/phil9l) for his research and providing a [blog](https://bazun.me/blog/kiterboard/) on how
|
|
134
136
|
to connect with the Kilter Board.
|
|
135
137
|
- [@1-max-1](https://github.com/1-max-1) for the docs on his Kilter Board
|
|
136
|
-
[simulator](https://github.com/1-max-1/fake_kilter_board)
|
|
138
|
+
[simulator](https://github.com/1-max-1/fake_kilter_board) that I coverted to
|
|
139
|
+
[hangtime-arduino-kilterboard](https://github.com/Stevie-Ray/hangtime-arduino-kilterboard).
|
|
140
|
+
- [sebws](https://github.com/sebw) for a [code sample](https://github.com/sebws/Crane) of the Weiheng WH-C06 App.
|
|
137
141
|
|
|
138
142
|
## Disclaimer
|
|
139
143
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Device } from "./types/devices";
|
|
2
|
+
/**
|
|
3
|
+
* Retrieves battery or voltage information from the device.
|
|
4
|
+
* @param {Device} board - The device.
|
|
5
|
+
* @returns {Promise<void>} A Promise that resolves when the information is successfully retrieved.
|
|
6
|
+
*/
|
|
7
|
+
export declare const battery: (board: Device) => Promise<void>;
|
package/dist/battery.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
* Retrieves battery or voltage information from the device.
|
|
8
|
+
* @param {Device} board - The device.
|
|
9
|
+
* @returns {Promise<void>} A Promise that resolves when the information is successfully retrieved.
|
|
10
|
+
*/
|
|
11
|
+
export const battery = async (board) => {
|
|
12
|
+
// Check if the device is connected
|
|
13
|
+
if (isConnected(board)) {
|
|
14
|
+
// If the device is connected and it is a Motherboard device
|
|
15
|
+
if (board.filters.some((filter) => filter.name === "Motherboard")) {
|
|
16
|
+
// Read battery level information from the Motherboard
|
|
17
|
+
await read(Motherboard, "battery", "level", 250);
|
|
18
|
+
}
|
|
19
|
+
// If the device is connected and its name starts with "Progressor"
|
|
20
|
+
if (board.filters.some((filter) => filter.namePrefix === "Progressor")) {
|
|
21
|
+
// Write command to get battery voltage information to the Progressor
|
|
22
|
+
await write(Progressor, "progressor", "tx", ProgressorCommands.GET_BATT_VLTG, 250);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Device } from "./types/devices";
|
|
2
|
+
/**
|
|
3
|
+
* Writes a command to get calibration data from the device.
|
|
4
|
+
* @param {Device} board - The device.
|
|
5
|
+
* @returns {Promise<void>} A Promise that resolves when the command is successfully sent.
|
|
6
|
+
*/
|
|
7
|
+
export declare const calibration: (board: Device) => Promise<void>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { isConnected } from "./is-connected";
|
|
2
|
+
import { write } from "./write";
|
|
3
|
+
import { Motherboard } from "./devices";
|
|
4
|
+
import { MotherboardCommands } from "./commands";
|
|
5
|
+
/**
|
|
6
|
+
* Writes a command to get calibration data from the device.
|
|
7
|
+
* @param {Device} board - The device.
|
|
8
|
+
* @returns {Promise<void>} A Promise that resolves when the command is successfully sent.
|
|
9
|
+
*/
|
|
10
|
+
export const calibration = async (board) => {
|
|
11
|
+
// Check if the device is connected
|
|
12
|
+
if (isConnected(board)) {
|
|
13
|
+
// If the device is connected, and it is a Motherboard device
|
|
14
|
+
if (board.filters.some((filter) => filter.name === "Motherboard")) {
|
|
15
|
+
// Write the command to get calibration data to the device
|
|
16
|
+
await write(Motherboard, "uart", "tx", MotherboardCommands.GET_CALIBRATION, 2500);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Device } from "./types/devices";
|
|
2
|
+
/**
|
|
3
|
+
* Retrieves the characteristic from the device's service.
|
|
4
|
+
* @param {Device} board - The device.
|
|
5
|
+
* @param {string} serviceId - The UUID of the service.
|
|
6
|
+
* @param {string} characteristicId - The UUID of the characteristic.
|
|
7
|
+
* @returns {BluetoothRemoteGATTCharacteristic | undefined} The characteristic, if found.
|
|
8
|
+
*/
|
|
9
|
+
export declare const getCharacteristic: (board: Device, serviceId: string, characteristicId: string) => BluetoothRemoteGATTCharacteristic | undefined;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retrieves the characteristic from the device's service.
|
|
3
|
+
* @param {Device} board - The device.
|
|
4
|
+
* @param {string} serviceId - The UUID of the service.
|
|
5
|
+
* @param {string} characteristicId - The UUID of the characteristic.
|
|
6
|
+
* @returns {BluetoothRemoteGATTCharacteristic | undefined} The characteristic, if found.
|
|
7
|
+
*/
|
|
8
|
+
export const getCharacteristic = (board, serviceId, characteristicId) => {
|
|
9
|
+
// Find the service with the specified serviceId
|
|
10
|
+
const boardService = board.services.find((service) => service.id === serviceId);
|
|
11
|
+
if (boardService) {
|
|
12
|
+
// If the service is found, find the characteristic with the specified characteristicId
|
|
13
|
+
const boardCharacteristic = boardService.characteristics.find((characteristic) => characteristic.id === characteristicId);
|
|
14
|
+
if (boardCharacteristic) {
|
|
15
|
+
// If the characteristic is found, return it
|
|
16
|
+
return boardCharacteristic.characteristic;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
// Return undefined if the service or characteristic is not found
|
|
20
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { ClimbroCommands } from "./climbro";
|
|
2
|
+
export { EntralpiCommands } from "./entralpi";
|
|
3
|
+
export { MotherboardCommands } from "./motherboard";
|
|
4
|
+
export { WHC06Commands } from "./wh-c06";
|
|
5
|
+
export { ProgressorCommands } from "./progressor";
|
|
6
|
+
export { mySmartBoardCommands } from "./mysmartboard";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { ClimbroCommands } from "./climbro";
|
|
2
|
+
export { EntralpiCommands } from "./entralpi";
|
|
3
|
+
export { MotherboardCommands } from "./motherboard";
|
|
4
|
+
export { WHC06Commands } from "./wh-c06";
|
|
5
|
+
export { ProgressorCommands } from "./progressor";
|
|
6
|
+
export { mySmartBoardCommands } from "./mysmartboard";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* For API level 2 and API level 3.
|
|
3
|
+
* The first byte in the data is dependent on where the packet is in the message as a whole.
|
|
4
|
+
* More details: https://github.com/1-max-1/fake_kilter_board
|
|
5
|
+
*/
|
|
6
|
+
export declare enum KilterBoardPacket {
|
|
7
|
+
/** If this packet is in the middle, the byte gets set to 77 (M). */
|
|
8
|
+
V2_MIDDLE = 77,
|
|
9
|
+
/** If this packet is the first packet in the message, then this byte gets set to 78 (N). */
|
|
10
|
+
V2_FIRST = 78,
|
|
11
|
+
/** If this is the last packet in the message, this byte gets set to 79 (0). */
|
|
12
|
+
V2_LAST = 79,
|
|
13
|
+
/** If this packet is the only packet in the message, the byte gets set to 80 (P). Note that this takes priority over the other conditions. */
|
|
14
|
+
V2_ONLY = 80,
|
|
15
|
+
/** If this packet is in the middle, the byte gets set to 81 (Q). */
|
|
16
|
+
V3_MIDDLE = 81,
|
|
17
|
+
/** If this packet is the first packet in the message, then this byte gets set to 82 (R). */
|
|
18
|
+
V3_FIRST = 82,
|
|
19
|
+
/** If this is the last packet in the message, this byte gets set to 83 (S). */
|
|
20
|
+
V3_LAST = 83,
|
|
21
|
+
/** If this packet is the only packet in the message, the byte gets set to 84 (T). Note that this takes priority over the other conditions. */
|
|
22
|
+
V3_ONLY = 84
|
|
23
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* For API level 2 and API level 3.
|
|
3
|
+
* The first byte in the data is dependent on where the packet is in the message as a whole.
|
|
4
|
+
* More details: https://github.com/1-max-1/fake_kilter_board
|
|
5
|
+
*/
|
|
6
|
+
export var KilterBoardPacket;
|
|
7
|
+
(function (KilterBoardPacket) {
|
|
8
|
+
/** If this packet is in the middle, the byte gets set to 77 (M). */
|
|
9
|
+
KilterBoardPacket[KilterBoardPacket["V2_MIDDLE"] = 77] = "V2_MIDDLE";
|
|
10
|
+
/** If this packet is the first packet in the message, then this byte gets set to 78 (N). */
|
|
11
|
+
KilterBoardPacket[KilterBoardPacket["V2_FIRST"] = 78] = "V2_FIRST";
|
|
12
|
+
/** If this is the last packet in the message, this byte gets set to 79 (0). */
|
|
13
|
+
KilterBoardPacket[KilterBoardPacket["V2_LAST"] = 79] = "V2_LAST";
|
|
14
|
+
/** If this packet is the only packet in the message, the byte gets set to 80 (P). Note that this takes priority over the other conditions. */
|
|
15
|
+
KilterBoardPacket[KilterBoardPacket["V2_ONLY"] = 80] = "V2_ONLY";
|
|
16
|
+
/** If this packet is in the middle, the byte gets set to 81 (Q). */
|
|
17
|
+
KilterBoardPacket[KilterBoardPacket["V3_MIDDLE"] = 81] = "V3_MIDDLE";
|
|
18
|
+
/** If this packet is the first packet in the message, then this byte gets set to 82 (R). */
|
|
19
|
+
KilterBoardPacket[KilterBoardPacket["V3_FIRST"] = 82] = "V3_FIRST";
|
|
20
|
+
/** If this is the last packet in the message, this byte gets set to 83 (S). */
|
|
21
|
+
KilterBoardPacket[KilterBoardPacket["V3_LAST"] = 83] = "V3_LAST";
|
|
22
|
+
/** If this packet is the only packet in the message, the byte gets set to 84 (T). Note that this takes priority over the other conditions. */
|
|
23
|
+
KilterBoardPacket[KilterBoardPacket["V3_ONLY"] = 84] = "V3_ONLY";
|
|
24
|
+
})(KilterBoardPacket || (KilterBoardPacket = {}));
|
|
@@ -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,17 @@
|
|
|
1
|
+
import type { Commands } from "../types/commands";
|
|
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 enum ProgressorResponses {
|
|
12
|
+
COMMAND_RESPONSE = 0,
|
|
13
|
+
WEIGHT_MEASURE = 1,
|
|
14
|
+
PEAK_RFD_MEAS = 2,
|
|
15
|
+
PEAK_RFD_MEAS_SERIES = 3,
|
|
16
|
+
LOW_BATTERY_WARNING = 4
|
|
17
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
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 var ProgressorResponses;
|
|
24
|
+
(function (ProgressorResponses) {
|
|
25
|
+
ProgressorResponses[ProgressorResponses["COMMAND_RESPONSE"] = 0] = "COMMAND_RESPONSE";
|
|
26
|
+
ProgressorResponses[ProgressorResponses["WEIGHT_MEASURE"] = 1] = "WEIGHT_MEASURE";
|
|
27
|
+
ProgressorResponses[ProgressorResponses["PEAK_RFD_MEAS"] = 2] = "PEAK_RFD_MEAS";
|
|
28
|
+
ProgressorResponses[ProgressorResponses["PEAK_RFD_MEAS_SERIES"] = 3] = "PEAK_RFD_MEAS_SERIES";
|
|
29
|
+
ProgressorResponses[ProgressorResponses["LOW_BATTERY_WARNING"] = 4] = "LOW_BATTERY_WARNING";
|
|
30
|
+
})(ProgressorResponses || (ProgressorResponses = {}));
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Device } from "./types/devices";
|
|
2
|
+
/**
|
|
3
|
+
* Connects to a Bluetooth device.
|
|
4
|
+
* @param {Device} board - The device to connect to.
|
|
5
|
+
* @param {Function} onSuccess - Callback function to execute on successful connection.
|
|
6
|
+
*/
|
|
7
|
+
export declare const connect: (board: Device, onSuccess: () => void) => Promise<void>;
|
package/dist/connect.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { handleEntralpiData, handleMotherboardData, handleProgressorData, handleWHC06Data } from "./data";
|
|
2
|
+
let server;
|
|
3
|
+
const receiveBuffer = [];
|
|
4
|
+
/**
|
|
5
|
+
* Handles the 'disconnected' event.
|
|
6
|
+
* @param {Event} event - The 'disconnected' event.
|
|
7
|
+
* @param {Device} board - The device that is disconnected.
|
|
8
|
+
*/
|
|
9
|
+
const onDisconnected = (event, board) => {
|
|
10
|
+
board.device = undefined;
|
|
11
|
+
const device = event.target;
|
|
12
|
+
console.log(`Device ${device.name} is disconnected.`);
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Handles notifications received from a characteristic.
|
|
16
|
+
* @param {Event} event - The notification event.
|
|
17
|
+
* @param {Device} board - The device associated with the characteristic.
|
|
18
|
+
*/
|
|
19
|
+
const handleNotifications = (event, board) => {
|
|
20
|
+
const characteristic = event.target;
|
|
21
|
+
const value = characteristic.value;
|
|
22
|
+
if (value) {
|
|
23
|
+
// If the device is connected and it is a Motherboard device
|
|
24
|
+
if (board.filters.some((filter) => filter.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(receivedData);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else if (board.filters.some((filter) => filter.name === "ENTRALPI")) {
|
|
39
|
+
if (value.buffer) {
|
|
40
|
+
const buffer = value.buffer;
|
|
41
|
+
const rawData = new DataView(buffer);
|
|
42
|
+
const receivedData = (rawData.getUint16(0) / 100).toFixed(1);
|
|
43
|
+
handleEntralpiData(receivedData);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else if (board.filters.some((filter) => filter.namePrefix === "Progressor")) {
|
|
47
|
+
if (value.buffer) {
|
|
48
|
+
const buffer = value.buffer;
|
|
49
|
+
const rawData = new DataView(buffer);
|
|
50
|
+
handleProgressorData(rawData);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
console.log(value);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Handles the 'connected' event.
|
|
60
|
+
* @param {Device} board - The connected device.
|
|
61
|
+
* @param {Function} onSuccess - Callback function to execute on successful connection.
|
|
62
|
+
*/
|
|
63
|
+
const onConnected = async (board, onSuccess) => {
|
|
64
|
+
try {
|
|
65
|
+
// Connect to GATT server and set up characteristics
|
|
66
|
+
const services = await server.getPrimaryServices();
|
|
67
|
+
if (!services || services.length === 0) {
|
|
68
|
+
console.error("No services found");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
for (const service of services) {
|
|
72
|
+
const matchingService = board.services.find((boardService) => boardService.uuid === service.uuid);
|
|
73
|
+
if (matchingService) {
|
|
74
|
+
// Android bug: Introduce a delay before getting characteristics
|
|
75
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
76
|
+
const characteristics = await service.getCharacteristics();
|
|
77
|
+
for (const characteristic of matchingService.characteristics) {
|
|
78
|
+
const matchingCharacteristic = characteristics.find((char) => char.uuid === characteristic.uuid);
|
|
79
|
+
if (matchingCharacteristic) {
|
|
80
|
+
const element = matchingService.characteristics.find((char) => char.uuid === matchingCharacteristic.uuid);
|
|
81
|
+
if (element) {
|
|
82
|
+
element.characteristic = matchingCharacteristic;
|
|
83
|
+
// notify
|
|
84
|
+
if (element.id === "rx") {
|
|
85
|
+
matchingCharacteristic.startNotifications();
|
|
86
|
+
matchingCharacteristic.addEventListener("characteristicvaluechanged", (event) => {
|
|
87
|
+
handleNotifications(event, board);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.warn(`Characteristic ${characteristic.uuid} not found in service ${service.uuid}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Call the onSuccess callback after successful connection and setup
|
|
99
|
+
onSuccess();
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
console.error(error);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Returns UUIDs of all services associated with the device.
|
|
107
|
+
* @param {Device} device - The device.
|
|
108
|
+
* @returns {string[]} Array of service UUIDs.
|
|
109
|
+
*/
|
|
110
|
+
const getAllServiceUUIDs = (device) => {
|
|
111
|
+
return device.services.map((service) => service.uuid);
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Connects to a Bluetooth device.
|
|
115
|
+
* @param {Device} board - The device to connect to.
|
|
116
|
+
* @param {Function} onSuccess - Callback function to execute on successful connection.
|
|
117
|
+
*/
|
|
118
|
+
export const connect = async (board, onSuccess) => {
|
|
119
|
+
try {
|
|
120
|
+
// Request device and set up connection
|
|
121
|
+
const deviceServices = getAllServiceUUIDs(board);
|
|
122
|
+
// Only data matching the optionalManufacturerData parameter to requestDevice is included in the advertisement event: https://github.com/WebBluetoothCG/web-bluetooth/issues/598
|
|
123
|
+
const optionalManufacturerData = board.filters.flatMap((filter) => filter.manufacturerData?.map((data) => data.companyIdentifier) || []);
|
|
124
|
+
const device = await navigator.bluetooth.requestDevice({
|
|
125
|
+
filters: board.filters,
|
|
126
|
+
optionalServices: deviceServices,
|
|
127
|
+
optionalManufacturerData,
|
|
128
|
+
});
|
|
129
|
+
board.device = device;
|
|
130
|
+
if (!board.device.gatt) {
|
|
131
|
+
console.error("GATT is not available on this device");
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
board.device.addEventListener("gattserverdisconnected", (event) => {
|
|
135
|
+
onDisconnected(event, board);
|
|
136
|
+
});
|
|
137
|
+
// WH-C06
|
|
138
|
+
const MANUFACTURER_ID = 256; // 0x0100
|
|
139
|
+
board.device.addEventListener("advertisementreceived", (event) => {
|
|
140
|
+
const manufacturerData = event.manufacturerData.get(MANUFACTURER_ID);
|
|
141
|
+
if (manufacturerData) {
|
|
142
|
+
// Device has no services / characteristics
|
|
143
|
+
onSuccess();
|
|
144
|
+
// Handle recieved data
|
|
145
|
+
handleWHC06Data(manufacturerData);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
if (optionalManufacturerData.length) {
|
|
149
|
+
await board.device.watchAdvertisements();
|
|
150
|
+
}
|
|
151
|
+
server = await board.device.gatt.connect();
|
|
152
|
+
if (server.connected) {
|
|
153
|
+
await onConnected(board, onSuccess);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
console.error(error);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { notifyCallback } from "./../notify";
|
|
2
|
+
import { applyTare } from "./../tare";
|
|
3
|
+
// Constants
|
|
4
|
+
let MASS_MAX = "0";
|
|
5
|
+
let MASS_AVERAGE = "0";
|
|
6
|
+
let MASS_TOTAL_SUM = 0;
|
|
7
|
+
let DATAPOINT_COUNT = 0;
|
|
8
|
+
/**
|
|
9
|
+
* Handles data received from the Entralpi device.
|
|
10
|
+
* @param {string} receivedData - The received data string.
|
|
11
|
+
*/
|
|
12
|
+
export const handleEntralpiData = (receivedData) => {
|
|
13
|
+
let numericData = Number(receivedData);
|
|
14
|
+
// Tare correction
|
|
15
|
+
numericData -= applyTare(numericData);
|
|
16
|
+
// Update MASS_MAX
|
|
17
|
+
MASS_MAX = Math.max(Number(MASS_MAX), numericData).toFixed(1);
|
|
18
|
+
// Update running sum and count
|
|
19
|
+
const currentMassTotal = Math.max(-1000, numericData);
|
|
20
|
+
MASS_TOTAL_SUM += currentMassTotal;
|
|
21
|
+
DATAPOINT_COUNT++;
|
|
22
|
+
// Calculate the average dynamically
|
|
23
|
+
MASS_AVERAGE = (MASS_TOTAL_SUM / DATAPOINT_COUNT).toFixed(1);
|
|
24
|
+
// Notify with weight data
|
|
25
|
+
notifyCallback({
|
|
26
|
+
massMax: MASS_MAX,
|
|
27
|
+
massAverage: MASS_AVERAGE,
|
|
28
|
+
massTotal: Math.max(-1000, numericData).toFixed(1),
|
|
29
|
+
});
|
|
30
|
+
};
|