@hangtime/grip-connect 0.12.0 → 0.13.1
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 +20 -9
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +3 -3
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/interfaces/command.interface.d.ts +110 -21
- package/dist/cjs/interfaces/command.interface.d.ts.map +1 -1
- package/dist/cjs/interfaces/device/aurora.interface.d.ts +17 -0
- package/dist/cjs/interfaces/device/aurora.interface.d.ts.map +1 -0
- package/dist/cjs/interfaces/device/{kilterboard.interface.js → aurora.interface.js} +1 -1
- package/dist/cjs/interfaces/device/aurora.interface.js.map +1 -0
- package/dist/cjs/interfaces/device/cts500.interface.d.ts +96 -0
- package/dist/cjs/interfaces/device/cts500.interface.d.ts.map +1 -0
- package/dist/cjs/interfaces/device/cts500.interface.js +3 -0
- package/dist/cjs/interfaces/device/cts500.interface.js.map +1 -0
- package/dist/cjs/interfaces/device/forceboard.interface.d.ts +2 -2
- package/dist/cjs/interfaces/device/forceboard.interface.d.ts.map +1 -1
- package/dist/cjs/interfaces/device/motherboard.interface.d.ts +1 -1
- package/dist/cjs/interfaces/device/pb-700bt.interface.d.ts +53 -0
- package/dist/cjs/interfaces/device/pb-700bt.interface.d.ts.map +1 -0
- package/dist/cjs/interfaces/device/pb-700bt.interface.js +3 -0
- package/dist/cjs/interfaces/device/pb-700bt.interface.js.map +1 -0
- package/dist/cjs/interfaces/device/progressor.interface.d.ts +2 -2
- package/dist/cjs/interfaces/device/progressor.interface.d.ts.map +1 -1
- package/dist/cjs/interfaces/index.d.ts +4 -1
- package/dist/cjs/interfaces/index.d.ts.map +1 -1
- package/dist/cjs/interfaces/nordic.interface.d.ts +47 -0
- package/dist/cjs/interfaces/nordic.interface.d.ts.map +1 -0
- package/dist/cjs/interfaces/nordic.interface.js +3 -0
- package/dist/cjs/interfaces/nordic.interface.js.map +1 -0
- package/dist/cjs/models/device/{kilterboard.model.d.ts → aurora.model.d.ts} +82 -40
- package/dist/cjs/models/device/aurora.model.d.ts.map +1 -0
- package/dist/cjs/models/device/aurora.model.js +407 -0
- package/dist/cjs/models/device/aurora.model.js.map +1 -0
- package/dist/cjs/models/device/climbro.model.js +1 -1
- package/dist/cjs/models/device/climbro.model.js.map +1 -1
- package/dist/cjs/models/device/cts500.model.d.ts +173 -0
- package/dist/cjs/models/device/cts500.model.d.ts.map +1 -0
- package/dist/cjs/models/device/cts500.model.js +596 -0
- package/dist/cjs/models/device/cts500.model.js.map +1 -0
- package/dist/cjs/models/device/forceboard.model.d.ts +2 -2
- package/dist/cjs/models/device/forceboard.model.d.ts.map +1 -1
- package/dist/cjs/models/device/forceboard.model.js +9 -16
- package/dist/cjs/models/device/forceboard.model.js.map +1 -1
- package/dist/cjs/models/device/motherboard.model.d.ts +4 -1
- package/dist/cjs/models/device/motherboard.model.d.ts.map +1 -1
- package/dist/cjs/models/device/motherboard.model.js +26 -10
- package/dist/cjs/models/device/motherboard.model.js.map +1 -1
- package/dist/cjs/models/device/pb-700bt.model.d.ts +2 -1
- package/dist/cjs/models/device/pb-700bt.model.d.ts.map +1 -1
- package/dist/cjs/models/device/pb-700bt.model.js.map +1 -1
- package/dist/cjs/models/device/progressor.model.d.ts +2 -2
- package/dist/cjs/models/device/progressor.model.d.ts.map +1 -1
- package/dist/cjs/models/device/progressor.model.js +4 -20
- package/dist/cjs/models/device/progressor.model.js.map +1 -1
- package/dist/cjs/models/device/wh-c06.model.d.ts +2 -0
- package/dist/cjs/models/device/wh-c06.model.d.ts.map +1 -1
- package/dist/cjs/models/device/wh-c06.model.js +45 -34
- package/dist/cjs/models/device/wh-c06.model.js.map +1 -1
- package/dist/cjs/models/device.model.d.ts +25 -5
- package/dist/cjs/models/device.model.d.ts.map +1 -1
- package/dist/cjs/models/device.model.js +94 -24
- package/dist/cjs/models/device.model.js.map +1 -1
- package/dist/cjs/models/index.d.ts +3 -1
- package/dist/cjs/models/index.d.ts.map +1 -1
- package/dist/cjs/models/index.js +8 -4
- package/dist/cjs/models/index.js.map +1 -1
- package/dist/cjs/models/nordic.model.d.ts +128 -0
- package/dist/cjs/models/nordic.model.d.ts.map +1 -0
- package/dist/cjs/models/nordic.model.js +405 -0
- package/dist/cjs/models/nordic.model.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/command.interface.d.ts +110 -21
- package/dist/interfaces/command.interface.d.ts.map +1 -1
- package/dist/interfaces/device/aurora.interface.d.ts +17 -0
- package/dist/interfaces/device/aurora.interface.d.ts.map +1 -0
- package/dist/interfaces/device/aurora.interface.js +2 -0
- package/dist/interfaces/device/aurora.interface.js.map +1 -0
- package/dist/interfaces/device/cts500.interface.d.ts +96 -0
- package/dist/interfaces/device/cts500.interface.d.ts.map +1 -0
- package/dist/interfaces/device/cts500.interface.js +2 -0
- package/dist/interfaces/device/cts500.interface.js.map +1 -0
- package/dist/interfaces/device/forceboard.interface.d.ts +2 -2
- package/dist/interfaces/device/forceboard.interface.d.ts.map +1 -1
- package/dist/interfaces/device/motherboard.interface.d.ts +1 -1
- package/dist/interfaces/device/pb-700bt.interface.d.ts +53 -0
- package/dist/interfaces/device/pb-700bt.interface.d.ts.map +1 -0
- package/dist/interfaces/device/pb-700bt.interface.js +2 -0
- package/dist/interfaces/device/pb-700bt.interface.js.map +1 -0
- package/dist/interfaces/device/progressor.interface.d.ts +2 -2
- package/dist/interfaces/device/progressor.interface.d.ts.map +1 -1
- package/dist/interfaces/index.d.ts +4 -1
- package/dist/interfaces/index.d.ts.map +1 -1
- package/dist/interfaces/nordic.interface.d.ts +47 -0
- package/dist/interfaces/nordic.interface.d.ts.map +1 -0
- package/dist/interfaces/nordic.interface.js +2 -0
- package/dist/interfaces/nordic.interface.js.map +1 -0
- package/dist/models/device/{kilterboard.model.d.ts → aurora.model.d.ts} +82 -40
- package/dist/models/device/aurora.model.d.ts.map +1 -0
- package/dist/models/device/aurora.model.js +401 -0
- package/dist/models/device/aurora.model.js.map +1 -0
- package/dist/models/device/climbro.model.js +1 -1
- package/dist/models/device/climbro.model.js.map +1 -1
- package/dist/models/device/cts500.model.d.ts +173 -0
- package/dist/models/device/cts500.model.d.ts.map +1 -0
- package/dist/models/device/cts500.model.js +592 -0
- package/dist/models/device/cts500.model.js.map +1 -0
- package/dist/models/device/forceboard.model.d.ts +2 -2
- package/dist/models/device/forceboard.model.d.ts.map +1 -1
- package/dist/models/device/forceboard.model.js +9 -16
- package/dist/models/device/forceboard.model.js.map +1 -1
- package/dist/models/device/motherboard.model.d.ts +4 -1
- package/dist/models/device/motherboard.model.d.ts.map +1 -1
- package/dist/models/device/motherboard.model.js +26 -10
- package/dist/models/device/motherboard.model.js.map +1 -1
- package/dist/models/device/pb-700bt.model.d.ts +2 -1
- package/dist/models/device/pb-700bt.model.d.ts.map +1 -1
- package/dist/models/device/pb-700bt.model.js.map +1 -1
- package/dist/models/device/progressor.model.d.ts +2 -2
- package/dist/models/device/progressor.model.d.ts.map +1 -1
- package/dist/models/device/progressor.model.js +4 -20
- package/dist/models/device/progressor.model.js.map +1 -1
- package/dist/models/device/wh-c06.model.d.ts +2 -0
- package/dist/models/device/wh-c06.model.d.ts.map +1 -1
- package/dist/models/device/wh-c06.model.js +44 -34
- package/dist/models/device/wh-c06.model.js.map +1 -1
- package/dist/models/device.model.d.ts +25 -5
- package/dist/models/device.model.d.ts.map +1 -1
- package/dist/models/device.model.js +93 -24
- package/dist/models/device.model.js.map +1 -1
- package/dist/models/index.d.ts +3 -1
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +3 -1
- package/dist/models/index.js.map +1 -1
- package/dist/models/nordic.model.d.ts +128 -0
- package/dist/models/nordic.model.d.ts.map +1 -0
- package/dist/models/nordic.model.js +393 -0
- package/dist/models/nordic.model.js.map +1 -0
- package/package.json +47 -43
- package/src/index.ts +6 -3
- package/src/interfaces/command.interface.ts +131 -21
- package/src/interfaces/device/aurora.interface.ts +18 -0
- package/src/interfaces/device/cts500.interface.ts +113 -0
- package/src/interfaces/device/forceboard.interface.ts +2 -2
- package/src/interfaces/device/motherboard.interface.ts +1 -1
- package/src/interfaces/device/pb-700bt.interface.ts +61 -0
- package/src/interfaces/device/progressor.interface.ts +2 -2
- package/src/interfaces/index.ts +8 -2
- package/src/interfaces/nordic.interface.ts +47 -0
- package/src/models/device/aurora.model.ts +497 -0
- package/src/models/device/climbro.model.ts +1 -1
- package/src/models/device/cts500.model.ts +709 -0
- package/src/models/device/forceboard.model.ts +9 -16
- package/src/models/device/motherboard.model.ts +51 -9
- package/src/models/device/pb-700bt.model.ts +2 -1
- package/src/models/device/progressor.model.ts +4 -20
- package/src/models/device/wh-c06.model.ts +54 -42
- package/src/models/device.model.ts +104 -24
- package/src/models/index.ts +5 -1
- package/src/models/nordic.model.ts +468 -0
- package/dist/cjs/interfaces/device/kilterboard.interface.d.ts +0 -17
- package/dist/cjs/interfaces/device/kilterboard.interface.d.ts.map +0 -1
- package/dist/cjs/interfaces/device/kilterboard.interface.js.map +0 -1
- package/dist/cjs/models/device/kilterboard.model.d.ts.map +0 -1
- package/dist/cjs/models/device/kilterboard.model.js +0 -327
- package/dist/cjs/models/device/kilterboard.model.js.map +0 -1
- package/dist/interfaces/device/kilterboard.interface.d.ts +0 -17
- package/dist/interfaces/device/kilterboard.interface.d.ts.map +0 -1
- package/dist/interfaces/device/kilterboard.interface.js +0 -2
- package/dist/interfaces/device/kilterboard.interface.js.map +0 -1
- package/dist/models/device/kilterboard.model.d.ts.map +0 -1
- package/dist/models/device/kilterboard.model.js +0 -323
- package/dist/models/device/kilterboard.model.js.map +0 -1
- package/dist/tsconfig.cjs.tsbuildinfo +0 -1
- package/src/interfaces/device/kilterboard.interface.ts +0 -12
- package/src/models/device/kilterboard.model.ts +0 -347
|
@@ -1,347 +0,0 @@
|
|
|
1
|
-
import { Device } from "../device.model.js"
|
|
2
|
-
import type { IKilterBoard } from "../../interfaces/device/kilterboard.interface.js"
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* For API level 2 and API level 3.
|
|
6
|
-
* The first byte in the data is dependent on where the packet is in the message as a whole.
|
|
7
|
-
* More details: https://github.com/1-max-1/fake_kilter_board
|
|
8
|
-
*/
|
|
9
|
-
export enum KilterBoardPacket {
|
|
10
|
-
/** If this packet is in the middle, the byte gets set to 77 (M). */
|
|
11
|
-
V2_MIDDLE = 77,
|
|
12
|
-
/** If this packet is the first packet in the message, then this byte gets set to 78 (N). */
|
|
13
|
-
V2_FIRST,
|
|
14
|
-
/** If this is the last packet in the message, this byte gets set to 79 (0). */
|
|
15
|
-
V2_LAST,
|
|
16
|
-
/** 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. */
|
|
17
|
-
V2_ONLY,
|
|
18
|
-
/** If this packet is in the middle, the byte gets set to 81 (Q). */
|
|
19
|
-
V3_MIDDLE,
|
|
20
|
-
/** If this packet is the first packet in the message, then this byte gets set to 82 (R). */
|
|
21
|
-
V3_FIRST,
|
|
22
|
-
/** If this is the last packet in the message, this byte gets set to 83 (S). */
|
|
23
|
-
V3_LAST,
|
|
24
|
-
/** 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. */
|
|
25
|
-
V3_ONLY,
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Extracted from placement_roles database table.
|
|
29
|
-
*/
|
|
30
|
-
export const KilterBoardPlacementRoles = [
|
|
31
|
-
{
|
|
32
|
-
id: 12,
|
|
33
|
-
product_id: 1,
|
|
34
|
-
position: 1,
|
|
35
|
-
name: "start",
|
|
36
|
-
full_name: "Start",
|
|
37
|
-
led_color: "00FF00",
|
|
38
|
-
screen_color: "00DD00",
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
id: 13,
|
|
42
|
-
product_id: 1,
|
|
43
|
-
position: 2,
|
|
44
|
-
name: "middle",
|
|
45
|
-
full_name: "Middle",
|
|
46
|
-
led_color: "00FFFF",
|
|
47
|
-
screen_color: "00FFFF",
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
id: 14,
|
|
51
|
-
product_id: 1,
|
|
52
|
-
position: 3,
|
|
53
|
-
name: "finish",
|
|
54
|
-
full_name: "Finish",
|
|
55
|
-
led_color: "FF00FF",
|
|
56
|
-
screen_color: "FF00FF",
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
id: 15,
|
|
60
|
-
product_id: 1,
|
|
61
|
-
position: 4,
|
|
62
|
-
name: "foot",
|
|
63
|
-
full_name: "Foot Only",
|
|
64
|
-
led_color: "FFB600",
|
|
65
|
-
screen_color: "FFA500",
|
|
66
|
-
},
|
|
67
|
-
]
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Represents a Aurora Climbing device.
|
|
71
|
-
* Kilter Board, Tension Board, Decoy Board, Touchstone Board, Grasshopper Board, Aurora Board, So iLL Board
|
|
72
|
-
* {@link https://auroraclimbing.com}
|
|
73
|
-
*/
|
|
74
|
-
export class KilterBoard extends Device implements IKilterBoard {
|
|
75
|
-
/**
|
|
76
|
-
* UUID for the Aurora Climbing Advertising service.
|
|
77
|
-
* This constant is used to identify the specific Bluetooth service for Kilter Boards.
|
|
78
|
-
* @type {string}
|
|
79
|
-
* @static
|
|
80
|
-
* @readonly
|
|
81
|
-
* @constant
|
|
82
|
-
*/
|
|
83
|
-
static readonly AuroraUUID: string = "4488b571-7806-4df6-bcff-a2897e4953ff"
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Maximum length of the message body for byte wrapping.
|
|
87
|
-
* This value defines the limit for the size of messages that can be sent or received
|
|
88
|
-
* to ensure proper byte wrapping in communication.
|
|
89
|
-
* @type {number}
|
|
90
|
-
* @private
|
|
91
|
-
* @readonly
|
|
92
|
-
* @constant
|
|
93
|
-
*/
|
|
94
|
-
private static readonly messageBodyMaxLength: number = 255
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Maximum length of the Bluetooth message chunk.
|
|
98
|
-
* This value sets the upper limit for the size of individual Bluetooth messages
|
|
99
|
-
* sent to and from the device to comply with Bluetooth protocol constraints.
|
|
100
|
-
* @type {number}
|
|
101
|
-
* @private
|
|
102
|
-
* @readonly
|
|
103
|
-
* @constant
|
|
104
|
-
*/
|
|
105
|
-
private static readonly maxBluetoothMessageSize: number = 20
|
|
106
|
-
|
|
107
|
-
constructor() {
|
|
108
|
-
super({
|
|
109
|
-
filters: [
|
|
110
|
-
{
|
|
111
|
-
services: [KilterBoard.AuroraUUID],
|
|
112
|
-
},
|
|
113
|
-
],
|
|
114
|
-
services: [
|
|
115
|
-
{
|
|
116
|
-
name: "UART Nordic Service",
|
|
117
|
-
id: "uart",
|
|
118
|
-
uuid: "6e400001-b5a3-f393-e0a9-e50e24dcca9e",
|
|
119
|
-
characteristics: [
|
|
120
|
-
{
|
|
121
|
-
name: "TX",
|
|
122
|
-
id: "tx",
|
|
123
|
-
uuid: "6e400002-b5a3-f393-e0a9-e50e24dcca9e",
|
|
124
|
-
},
|
|
125
|
-
// {
|
|
126
|
-
// name: "RX",
|
|
127
|
-
// id: "rx",
|
|
128
|
-
// uuid: "6e400003-b5a3-f393-e0a9-e50e24dcca9e",
|
|
129
|
-
// },
|
|
130
|
-
],
|
|
131
|
-
},
|
|
132
|
-
],
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Calculates the checksum for a byte array by summing up all bytes ot hre packet in a single-byte variable.
|
|
138
|
-
* @param data - The array of bytes to calculate the checksum for.
|
|
139
|
-
* @returns {number} The calculated checksum value.
|
|
140
|
-
*/
|
|
141
|
-
private checksum(data: number[]): number {
|
|
142
|
-
let i = 0
|
|
143
|
-
for (const value of data) {
|
|
144
|
-
i = (i + value) & 255
|
|
145
|
-
}
|
|
146
|
-
return ~i & 255
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Wraps a byte array with header and footer bytes for transmission.
|
|
151
|
-
* @param data - The array of bytes to wrap.
|
|
152
|
-
* @returns {number[]} The wrapped byte array.
|
|
153
|
-
*/
|
|
154
|
-
private wrapBytes(data: number[]): number[] {
|
|
155
|
-
if (data.length > KilterBoard.messageBodyMaxLength) {
|
|
156
|
-
return []
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
- 0x1
|
|
160
|
-
- len(packets)
|
|
161
|
-
- checksum(packets)
|
|
162
|
-
- 0x2
|
|
163
|
-
- *packets
|
|
164
|
-
- 0x3
|
|
165
|
-
|
|
166
|
-
First byte is always 1, the second is a number of packets, then checksum, then 2, packets themselves, and finally 3.
|
|
167
|
-
*/
|
|
168
|
-
return [1, data.length, this.checksum(data), 2, ...data, 3]
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Encodes a position into a byte array.
|
|
173
|
-
* The lowest 8 bits of the position get put in the first byte of the group.
|
|
174
|
-
* The highest 8 bits of the position get put in the second byte of the group.
|
|
175
|
-
* @param position - The position to encode.
|
|
176
|
-
* @returns {number[]} The encoded byte array representing the position.
|
|
177
|
-
*/
|
|
178
|
-
private encodePosition(position: number): number[] {
|
|
179
|
-
const position1 = position & 255
|
|
180
|
-
const position2 = (position & 65280) >> 8
|
|
181
|
-
|
|
182
|
-
return [position1, position2]
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Encodes a color string into a numeric representation.
|
|
187
|
-
* The rgb color, 3 bits for the R and G components, 2 bits for the B component, with the 3 R bits occupying the high end of the byte and the 2 B bits in the low end (hence 3 G bits in the middle).
|
|
188
|
-
* Format: 0bRRRGGGBB where RRR is 3 bits for red, GGG is 3 bits for green, BB is 2 bits for blue.
|
|
189
|
-
* @param color - The color string in hexadecimal format (e.g., 'FFFFFF').
|
|
190
|
-
* @returns The encoded /compressed color value.
|
|
191
|
-
*/
|
|
192
|
-
private encodeColor(color: string): number {
|
|
193
|
-
const r = parseInt(color.substring(0, 2), 16)
|
|
194
|
-
const g = parseInt(color.substring(2, 4), 16)
|
|
195
|
-
const b = parseInt(color.substring(4, 6), 16)
|
|
196
|
-
|
|
197
|
-
// Integer division: R and G divided by 32, B divided by 64
|
|
198
|
-
// Then pack into 0bRRRGGGBB format
|
|
199
|
-
const rBits = Math.floor(r / 32) // 0-7 (3 bits)
|
|
200
|
-
const gBits = Math.floor(g / 32) // 0-7 (3 bits)
|
|
201
|
-
const bBits = Math.floor(b / 64) // 0-3 (2 bits)
|
|
202
|
-
|
|
203
|
-
// Pack: RRR in bits 7-5, GGG in bits 4-2, BB in bits 1-0
|
|
204
|
-
return (rBits << 5) | (gBits << 2) | bBits
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Encodes a placement (requires a 16-bit position and a 24-bit rgb color. ) into a byte array.
|
|
209
|
-
* @param position - The position to encode.
|
|
210
|
-
* @param ledColor - The color of the LED in hexadecimal format (e.g., 'FFFFFF').
|
|
211
|
-
* @returns The encoded byte array representing the placement.
|
|
212
|
-
*/
|
|
213
|
-
private encodePlacement(position: number, ledColor: string): number[] {
|
|
214
|
-
return [...this.encodePosition(position), this.encodeColor(ledColor)]
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Prepares byte arrays for transmission based on a list of climb placements.
|
|
219
|
-
* @param {{ position: number; role_id?: number; color?: string }[]} climbPlacementList - The list of climb placements containing position and either role ID or color.
|
|
220
|
-
* @returns {number[]} The final byte array ready for transmission.
|
|
221
|
-
*/
|
|
222
|
-
private prepBytesV3(climbPlacementList: { position: number; role_id?: number; color?: string }[]): number[] {
|
|
223
|
-
const resultArray: number[][] = []
|
|
224
|
-
let tempArray: number[] = [KilterBoardPacket.V3_MIDDLE]
|
|
225
|
-
|
|
226
|
-
// Filter out any invalid placements and clean up objects before processing
|
|
227
|
-
const validPlacements = climbPlacementList
|
|
228
|
-
.filter((p) => {
|
|
229
|
-
// Explicitly check for color
|
|
230
|
-
const hasColor = p.color != null && typeof p.color === "string" && p.color.trim() !== ""
|
|
231
|
-
// Explicitly check for role_id - must be a number, not undefined or null
|
|
232
|
-
const hasRoleId = typeof p.role_id === "number" && !isNaN(p.role_id)
|
|
233
|
-
|
|
234
|
-
return hasColor || hasRoleId
|
|
235
|
-
})
|
|
236
|
-
.map((p) => {
|
|
237
|
-
// Create clean objects without undefined properties
|
|
238
|
-
if (p.color != null && typeof p.color === "string" && p.color.trim() !== "") {
|
|
239
|
-
return { position: p.position, color: p.color.trim() } as { position: number; color: string }
|
|
240
|
-
} else if (typeof p.role_id === "number" && !isNaN(p.role_id)) {
|
|
241
|
-
return { position: p.position, role_id: p.role_id } as { position: number; role_id: number }
|
|
242
|
-
}
|
|
243
|
-
// This should never happen due to the filter above, but TypeScript needs this
|
|
244
|
-
throw new Error("Invalid placement after filter")
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
for (const climbPlacement of validPlacements) {
|
|
248
|
-
if (tempArray.length + 3 > KilterBoard.messageBodyMaxLength) {
|
|
249
|
-
resultArray.push(tempArray)
|
|
250
|
-
tempArray = [KilterBoardPacket.V3_MIDDLE]
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
let colorHex: string
|
|
254
|
-
|
|
255
|
-
// Type guard: check if this placement has a color property
|
|
256
|
-
if ("color" in climbPlacement && climbPlacement.color) {
|
|
257
|
-
// Use direct color if provided
|
|
258
|
-
colorHex = climbPlacement.color.replace("#", "").toUpperCase()
|
|
259
|
-
} else if ("role_id" in climbPlacement && typeof climbPlacement.role_id === "number") {
|
|
260
|
-
// Fall back to role_id if no color provided
|
|
261
|
-
const role = KilterBoardPlacementRoles.find((placement) => placement.id === climbPlacement.role_id)
|
|
262
|
-
if (!role) {
|
|
263
|
-
throw new Error(`Role with id ${climbPlacement.role_id} not found in placement_roles`)
|
|
264
|
-
}
|
|
265
|
-
colorHex = role.led_color
|
|
266
|
-
} else {
|
|
267
|
-
// This should never happen due to the filter above, but just in case
|
|
268
|
-
throw new Error(`Either role_id or color must be provided for position ${climbPlacement.position}`)
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const encodedPlacement = this.encodePlacement(climbPlacement.position, colorHex)
|
|
272
|
-
tempArray.push(...encodedPlacement)
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
resultArray.push(tempArray)
|
|
276
|
-
|
|
277
|
-
if (resultArray.length === 1) {
|
|
278
|
-
resultArray[0][0] = KilterBoardPacket.V3_ONLY
|
|
279
|
-
} else if (resultArray.length > 1) {
|
|
280
|
-
resultArray[0][0] = KilterBoardPacket.V3_FIRST
|
|
281
|
-
resultArray[resultArray.length - 1][0] = KilterBoardPacket.V3_LAST
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const finalResultArray: number[] = []
|
|
285
|
-
for (const currentArray of resultArray) {
|
|
286
|
-
finalResultArray.push(...this.wrapBytes(currentArray))
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return finalResultArray
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Splits a collection into slices of the specified length.
|
|
294
|
-
* https://github.com/ramda/ramda/blob/master/source/splitEvery
|
|
295
|
-
* @param {Number} n
|
|
296
|
-
* @param {Array} list
|
|
297
|
-
* @return {Array<number[]>}
|
|
298
|
-
*/
|
|
299
|
-
private splitEvery(n: number, list: number[]): number[][] {
|
|
300
|
-
if (n <= 0) {
|
|
301
|
-
throw new Error("First argument to splitEvery must be a positive integer")
|
|
302
|
-
}
|
|
303
|
-
const result = []
|
|
304
|
-
let idx = 0
|
|
305
|
-
while (idx < list.length) {
|
|
306
|
-
result.push(list.slice(idx, (idx += n)))
|
|
307
|
-
}
|
|
308
|
-
return result
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* The kilter board only supports messages of 20 bytes
|
|
313
|
-
* at a time. This method splits a full message into parts
|
|
314
|
-
* of 20 bytes
|
|
315
|
-
*
|
|
316
|
-
* @param buffer
|
|
317
|
-
*/
|
|
318
|
-
private splitMessages = (buffer: number[]) =>
|
|
319
|
-
this.splitEvery(KilterBoard.maxBluetoothMessageSize, buffer).map((arr) => new Uint8Array(arr))
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Sends a series of messages to a device.
|
|
323
|
-
*/
|
|
324
|
-
private async writeMessageSeries(messages: Uint8Array[]) {
|
|
325
|
-
for (const message of messages) {
|
|
326
|
-
await this.write("uart", "tx", message)
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Configures the LEDs based on an array of climb placements.
|
|
332
|
-
* @param {{ position: number; role_id?: number; color?: string }[]} config - Array of climb placements for the LEDs. Either role_id or color (hex string) must be provided.
|
|
333
|
-
* @returns {Promise<number[] | undefined>} A promise that resolves with the payload array for the Kilter Board if LED settings were applied, or `undefined` if no action was taken or for the Motherboard.
|
|
334
|
-
*/
|
|
335
|
-
led = async (config: { position: number; role_id?: number; color?: string }[]): Promise<number[] | undefined> => {
|
|
336
|
-
// Handle Kilterboard logic: process placements and send payload if connected
|
|
337
|
-
if (Array.isArray(config)) {
|
|
338
|
-
// Prepares byte arrays for transmission based on a list of climb placements.
|
|
339
|
-
const payload = this.prepBytesV3(config)
|
|
340
|
-
if (this.isConnected()) {
|
|
341
|
-
await this.writeMessageSeries(this.splitMessages(payload))
|
|
342
|
-
}
|
|
343
|
-
return payload
|
|
344
|
-
}
|
|
345
|
-
return undefined
|
|
346
|
-
}
|
|
347
|
-
}
|