edilkamin 1.10.2 → 1.12.0

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.
Files changed (52) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/bluetooth-protocol.d.ts +178 -0
  3. package/dist/cjs/src/bluetooth-protocol.js +423 -0
  4. package/dist/cjs/src/bluetooth-protocol.test.d.ts +1 -0
  5. package/dist/cjs/src/bluetooth-protocol.test.js +389 -0
  6. package/dist/cjs/src/bluetooth-utils.js +2 -6
  7. package/dist/cjs/src/bluetooth.d.ts +2 -0
  8. package/dist/cjs/src/bluetooth.js +17 -1
  9. package/dist/cjs/src/cli.js +9 -8
  10. package/dist/cjs/src/index.d.ts +4 -3
  11. package/dist/cjs/src/index.js +14 -1
  12. package/dist/cjs/src/library.d.ts +30 -0
  13. package/dist/cjs/src/library.js +97 -3
  14. package/dist/cjs/src/library.test.js +225 -4
  15. package/dist/cjs/src/mac-utils.d.ts +15 -0
  16. package/dist/cjs/src/mac-utils.js +24 -0
  17. package/dist/cjs/src/mac-utils.test.d.ts +1 -0
  18. package/dist/cjs/src/mac-utils.test.js +41 -0
  19. package/dist/cjs/src/types.d.ts +94 -2
  20. package/dist/cjs/src/types.js +95 -1
  21. package/dist/esm/package.json +1 -1
  22. package/dist/esm/src/bluetooth-protocol.d.ts +178 -0
  23. package/dist/esm/src/bluetooth-protocol.js +415 -0
  24. package/dist/esm/src/bluetooth-protocol.test.d.ts +1 -0
  25. package/dist/esm/src/bluetooth-protocol.test.js +387 -0
  26. package/dist/esm/src/bluetooth-utils.js +2 -6
  27. package/dist/esm/src/bluetooth.d.ts +2 -0
  28. package/dist/esm/src/bluetooth.js +8 -0
  29. package/dist/esm/src/cli.js +9 -8
  30. package/dist/esm/src/index.d.ts +4 -3
  31. package/dist/esm/src/index.js +3 -2
  32. package/dist/esm/src/library.d.ts +30 -0
  33. package/dist/esm/src/library.js +94 -2
  34. package/dist/esm/src/library.test.js +226 -5
  35. package/dist/esm/src/mac-utils.d.ts +15 -0
  36. package/dist/esm/src/mac-utils.js +21 -0
  37. package/dist/esm/src/mac-utils.test.d.ts +1 -0
  38. package/dist/esm/src/mac-utils.test.js +39 -0
  39. package/dist/esm/src/types.d.ts +94 -2
  40. package/dist/esm/src/types.js +89 -1
  41. package/package.json +1 -1
  42. package/src/bluetooth-protocol.test.ts +497 -0
  43. package/src/bluetooth-protocol.ts +524 -0
  44. package/src/bluetooth-utils.ts +3 -7
  45. package/src/bluetooth.ts +21 -0
  46. package/src/cli.ts +9 -8
  47. package/src/index.ts +24 -2
  48. package/src/library.test.ts +325 -4
  49. package/src/library.ts +109 -2
  50. package/src/mac-utils.test.ts +60 -0
  51. package/src/mac-utils.ts +22 -0
  52. package/src/types.ts +144 -1
@@ -0,0 +1,389 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const assert_1 = require("assert");
13
+ const bluetooth_protocol_1 = require("./bluetooth-protocol");
14
+ describe("bluetooth-protocol", () => {
15
+ describe("constants", () => {
16
+ it("exports SERVICE_UUID", () => {
17
+ assert_1.strict.equal(bluetooth_protocol_1.SERVICE_UUID, "0000abf0-0000-1000-8000-00805f9b34fb");
18
+ });
19
+ it("exports WRITE_CHARACTERISTIC_UUID", () => {
20
+ assert_1.strict.equal(bluetooth_protocol_1.WRITE_CHARACTERISTIC_UUID, "0000abf1-0000-1000-8000-00805f9b34fb");
21
+ });
22
+ it("exports NOTIFY_CHARACTERISTIC_UUID", () => {
23
+ assert_1.strict.equal(bluetooth_protocol_1.NOTIFY_CHARACTERISTIC_UUID, "0000abf2-0000-1000-8000-00805f9b34fb");
24
+ });
25
+ });
26
+ describe("crc16Modbus", () => {
27
+ it("calculates correct CRC for power-on command", () => {
28
+ const command = new Uint8Array([0x01, 0x06, 0x03, 0x1c, 0x00, 0x01]);
29
+ const crc = (0, bluetooth_protocol_1.crc16Modbus)(command);
30
+ assert_1.strict.equal(crc.length, 2);
31
+ // CRC is returned as [crcLo, crcHi]
32
+ assert_1.strict.ok(crc[0] >= 0 && crc[0] <= 255);
33
+ assert_1.strict.ok(crc[1] >= 0 && crc[1] <= 255);
34
+ });
35
+ it("returns 2 bytes for any input", () => {
36
+ const testCases = [
37
+ new Uint8Array([0x01, 0x03, 0x05, 0x25, 0x00, 0x01]),
38
+ new Uint8Array([0x01, 0x06, 0x04, 0x40, 0x00, 0x03]),
39
+ new Uint8Array([0x00]),
40
+ new Uint8Array([0xff, 0xff, 0xff]),
41
+ ];
42
+ for (const data of testCases) {
43
+ const crc = (0, bluetooth_protocol_1.crc16Modbus)(data);
44
+ assert_1.strict.equal(crc.length, 2, `CRC for ${data.toString()} should be 2 bytes`);
45
+ }
46
+ });
47
+ it("produces different CRCs for different data", () => {
48
+ const crc1 = (0, bluetooth_protocol_1.crc16Modbus)(new Uint8Array([0x01, 0x06, 0x03, 0x1c, 0x00, 0x01]));
49
+ const crc2 = (0, bluetooth_protocol_1.crc16Modbus)(new Uint8Array([0x01, 0x06, 0x03, 0x1c, 0x00, 0x00]));
50
+ // CRCs should be different for different data
51
+ assert_1.strict.ok(crc1[0] !== crc2[0] || crc1[1] !== crc2[1]);
52
+ });
53
+ });
54
+ describe("aesEncrypt/aesDecrypt", () => {
55
+ it("roundtrip returns original data", () => __awaiter(void 0, void 0, void 0, function* () {
56
+ const original = new Uint8Array(32).fill(0x42);
57
+ const encrypted = yield (0, bluetooth_protocol_1.aesEncrypt)(original);
58
+ const decrypted = yield (0, bluetooth_protocol_1.aesDecrypt)(encrypted);
59
+ assert_1.strict.deepEqual(decrypted, original);
60
+ }));
61
+ it("produces 32-byte output for 32-byte input", () => __awaiter(void 0, void 0, void 0, function* () {
62
+ const input = new Uint8Array(32);
63
+ const encrypted = yield (0, bluetooth_protocol_1.aesEncrypt)(input);
64
+ assert_1.strict.equal(encrypted.length, 32);
65
+ }));
66
+ it("produces different output for different input", () => __awaiter(void 0, void 0, void 0, function* () {
67
+ const input1 = new Uint8Array(32).fill(0x00);
68
+ const input2 = new Uint8Array(32).fill(0xff);
69
+ const encrypted1 = yield (0, bluetooth_protocol_1.aesEncrypt)(input1);
70
+ const encrypted2 = yield (0, bluetooth_protocol_1.aesEncrypt)(input2);
71
+ // At least some bytes should be different
72
+ let different = false;
73
+ for (let i = 0; i < 32; i++) {
74
+ if (encrypted1[i] !== encrypted2[i]) {
75
+ different = true;
76
+ break;
77
+ }
78
+ }
79
+ assert_1.strict.ok(different, "Different inputs should produce different outputs");
80
+ }));
81
+ it("encrypted data is different from plaintext", () => __awaiter(void 0, void 0, void 0, function* () {
82
+ const original = new Uint8Array(32).fill(0xaa);
83
+ const encrypted = yield (0, bluetooth_protocol_1.aesEncrypt)(original);
84
+ // Encrypted should not equal original
85
+ let same = true;
86
+ for (let i = 0; i < 32; i++) {
87
+ if (encrypted[i] !== original[i]) {
88
+ same = false;
89
+ break;
90
+ }
91
+ }
92
+ assert_1.strict.ok(!same, "Encrypted data should differ from original");
93
+ }));
94
+ });
95
+ describe("createPacket", () => {
96
+ it("produces 32-byte encrypted packet", () => __awaiter(void 0, void 0, void 0, function* () {
97
+ const command = bluetooth_protocol_1.readCommands.power;
98
+ const packet = yield (0, bluetooth_protocol_1.createPacket)(command);
99
+ assert_1.strict.equal(packet.length, 32);
100
+ }));
101
+ it("rejects commands not exactly 6 bytes", () => __awaiter(void 0, void 0, void 0, function* () {
102
+ yield assert_1.strict.rejects(() => (0, bluetooth_protocol_1.createPacket)(new Uint8Array([0x01, 0x02])), /must be exactly 6 bytes/);
103
+ }));
104
+ it("rejects empty commands", () => __awaiter(void 0, void 0, void 0, function* () {
105
+ yield assert_1.strict.rejects(() => (0, bluetooth_protocol_1.createPacket)(new Uint8Array([])), /must be exactly 6 bytes/);
106
+ }));
107
+ it("rejects 7-byte commands", () => __awaiter(void 0, void 0, void 0, function* () {
108
+ yield assert_1.strict.rejects(() => (0, bluetooth_protocol_1.createPacket)(new Uint8Array([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07])), /must be exactly 6 bytes/);
109
+ }));
110
+ it("produces different packets for different commands", () => __awaiter(void 0, void 0, void 0, function* () {
111
+ const packet1 = yield (0, bluetooth_protocol_1.createPacket)(bluetooth_protocol_1.writeCommands.setPower(true));
112
+ const packet2 = yield (0, bluetooth_protocol_1.createPacket)(bluetooth_protocol_1.writeCommands.setPower(false));
113
+ // Packets should be different (different command bytes)
114
+ let different = false;
115
+ for (let i = 0; i < 32; i++) {
116
+ if (packet1[i] !== packet2[i]) {
117
+ different = true;
118
+ break;
119
+ }
120
+ }
121
+ assert_1.strict.ok(different, "Different commands should produce different packets");
122
+ }));
123
+ });
124
+ describe("parseResponse", () => {
125
+ it("rejects responses not 32 bytes", () => __awaiter(void 0, void 0, void 0, function* () {
126
+ yield assert_1.strict.rejects(() => (0, bluetooth_protocol_1.parseResponse)(new Uint8Array(16)), /must be exactly 32 bytes/);
127
+ }));
128
+ it("can decrypt and parse an encrypted packet", () => __awaiter(void 0, void 0, void 0, function* () {
129
+ // Create a command packet and try to parse it
130
+ // This tests that encrypt/decrypt work together
131
+ const command = bluetooth_protocol_1.readCommands.power;
132
+ const encrypted = yield (0, bluetooth_protocol_1.createPacket)(command);
133
+ // Parse the response (it's not a valid response but should decrypt)
134
+ const parsed = yield (0, bluetooth_protocol_1.parseResponse)(encrypted);
135
+ // Should have parsed something
136
+ assert_1.strict.ok(typeof parsed.slaveAddress === "number");
137
+ assert_1.strict.ok(typeof parsed.functionCode === "number");
138
+ assert_1.strict.ok(typeof parsed.isError === "boolean");
139
+ }));
140
+ });
141
+ describe("readCommands", () => {
142
+ it("all commands are 6 bytes", () => {
143
+ Object.entries(bluetooth_protocol_1.readCommands).forEach(([name, cmd]) => {
144
+ assert_1.strict.equal(cmd.length, 6, `${name} command must be 6 bytes`);
145
+ });
146
+ });
147
+ it("all commands use slave address 0x01", () => {
148
+ Object.entries(bluetooth_protocol_1.readCommands).forEach(([name, cmd]) => {
149
+ assert_1.strict.equal(cmd[0], 0x01, `${name} should use slave address 0x01`);
150
+ });
151
+ });
152
+ it("all commands use function code 0x03", () => {
153
+ Object.entries(bluetooth_protocol_1.readCommands).forEach(([name, cmd]) => {
154
+ assert_1.strict.equal(cmd[1], 0x03, `${name} should use function code 0x03`);
155
+ });
156
+ });
157
+ it("power command has correct register address", () => {
158
+ assert_1.strict.equal(bluetooth_protocol_1.readCommands.power[2], 0x05);
159
+ assert_1.strict.equal(bluetooth_protocol_1.readCommands.power[3], 0x29);
160
+ });
161
+ it("temperature command has correct register address", () => {
162
+ assert_1.strict.equal(bluetooth_protocol_1.readCommands.temperature[2], 0x05);
163
+ assert_1.strict.equal(bluetooth_protocol_1.readCommands.temperature[3], 0x25);
164
+ });
165
+ });
166
+ describe("writeCommands", () => {
167
+ it("setPower(true) produces correct bytes", () => {
168
+ const cmd = bluetooth_protocol_1.writeCommands.setPower(true);
169
+ assert_1.strict.deepEqual(cmd, new Uint8Array([0x01, 0x06, 0x03, 0x1c, 0x00, 0x01]));
170
+ });
171
+ it("setPower(false) produces correct bytes", () => {
172
+ const cmd = bluetooth_protocol_1.writeCommands.setPower(false);
173
+ assert_1.strict.deepEqual(cmd, new Uint8Array([0x01, 0x06, 0x03, 0x1c, 0x00, 0x00]));
174
+ });
175
+ it("setTemperature encodes correctly", () => {
176
+ const cmd = bluetooth_protocol_1.writeCommands.setTemperature(21.5);
177
+ // 21.5 * 10 = 215 = 0x00D7
178
+ assert_1.strict.equal(cmd[0], 0x01); // slave address
179
+ assert_1.strict.equal(cmd[1], 0x06); // function code
180
+ assert_1.strict.equal(cmd[2], 0x05); // register hi
181
+ assert_1.strict.equal(cmd[3], 0x25); // register lo
182
+ assert_1.strict.equal(cmd[4], 0x00); // value hi
183
+ assert_1.strict.equal(cmd[5], 0xd7); // value lo
184
+ });
185
+ it("setTemperature handles whole numbers", () => {
186
+ const cmd = bluetooth_protocol_1.writeCommands.setTemperature(20);
187
+ // 20 * 10 = 200 = 0x00C8
188
+ assert_1.strict.equal(cmd[4], 0x00);
189
+ assert_1.strict.equal(cmd[5], 0xc8);
190
+ });
191
+ it("setTemperature handles high temperatures", () => {
192
+ const cmd = bluetooth_protocol_1.writeCommands.setTemperature(30);
193
+ // 30 * 10 = 300 = 0x012C
194
+ assert_1.strict.equal(cmd[4], 0x01);
195
+ assert_1.strict.equal(cmd[5], 0x2c);
196
+ });
197
+ it("setPowerLevel validates range", () => {
198
+ assert_1.strict.throws(() => bluetooth_protocol_1.writeCommands.setPowerLevel(0), /must be 1-5/);
199
+ assert_1.strict.throws(() => bluetooth_protocol_1.writeCommands.setPowerLevel(6), /must be 1-5/);
200
+ assert_1.strict.doesNotThrow(() => bluetooth_protocol_1.writeCommands.setPowerLevel(1));
201
+ assert_1.strict.doesNotThrow(() => bluetooth_protocol_1.writeCommands.setPowerLevel(3));
202
+ assert_1.strict.doesNotThrow(() => bluetooth_protocol_1.writeCommands.setPowerLevel(5));
203
+ });
204
+ it("setPowerLevel produces correct bytes", () => {
205
+ const cmd = bluetooth_protocol_1.writeCommands.setPowerLevel(3);
206
+ assert_1.strict.equal(cmd[0], 0x01);
207
+ assert_1.strict.equal(cmd[1], 0x06);
208
+ assert_1.strict.equal(cmd[2], 0x04);
209
+ assert_1.strict.equal(cmd[3], 0x40);
210
+ assert_1.strict.equal(cmd[4], 0x00);
211
+ assert_1.strict.equal(cmd[5], 0x03);
212
+ });
213
+ it("setFan1Speed validates range", () => {
214
+ assert_1.strict.throws(() => bluetooth_protocol_1.writeCommands.setFan1Speed(-1), /must be 0-5/);
215
+ assert_1.strict.throws(() => bluetooth_protocol_1.writeCommands.setFan1Speed(6), /must be 0-5/);
216
+ assert_1.strict.doesNotThrow(() => bluetooth_protocol_1.writeCommands.setFan1Speed(0)); // auto
217
+ assert_1.strict.doesNotThrow(() => bluetooth_protocol_1.writeCommands.setFan1Speed(5));
218
+ });
219
+ it("setFan2Speed validates range", () => {
220
+ assert_1.strict.throws(() => bluetooth_protocol_1.writeCommands.setFan2Speed(-1), /must be 0-5/);
221
+ assert_1.strict.throws(() => bluetooth_protocol_1.writeCommands.setFan2Speed(6), /must be 0-5/);
222
+ assert_1.strict.doesNotThrow(() => bluetooth_protocol_1.writeCommands.setFan2Speed(0));
223
+ assert_1.strict.doesNotThrow(() => bluetooth_protocol_1.writeCommands.setFan2Speed(5));
224
+ });
225
+ it("setAutoMode produces correct bytes", () => {
226
+ const cmdOn = bluetooth_protocol_1.writeCommands.setAutoMode(true);
227
+ assert_1.strict.equal(cmdOn[5], 0x01);
228
+ const cmdOff = bluetooth_protocol_1.writeCommands.setAutoMode(false);
229
+ assert_1.strict.equal(cmdOff[5], 0x00);
230
+ });
231
+ it("setStandby produces correct bytes", () => {
232
+ const cmdOn = bluetooth_protocol_1.writeCommands.setStandby(true);
233
+ assert_1.strict.equal(cmdOn[5], 0x01);
234
+ const cmdOff = bluetooth_protocol_1.writeCommands.setStandby(false);
235
+ assert_1.strict.equal(cmdOff[5], 0x00);
236
+ });
237
+ it("all write commands are 6 bytes", () => {
238
+ const commands = [
239
+ bluetooth_protocol_1.writeCommands.setPower(true),
240
+ bluetooth_protocol_1.writeCommands.setTemperature(21),
241
+ bluetooth_protocol_1.writeCommands.setPowerLevel(3),
242
+ bluetooth_protocol_1.writeCommands.setFan1Speed(2),
243
+ bluetooth_protocol_1.writeCommands.setFan2Speed(2),
244
+ bluetooth_protocol_1.writeCommands.setAutoMode(true),
245
+ bluetooth_protocol_1.writeCommands.setStandby(false),
246
+ ];
247
+ commands.forEach((cmd, i) => {
248
+ assert_1.strict.equal(cmd.length, 6, `Command ${i} should be 6 bytes`);
249
+ });
250
+ });
251
+ it("all write commands use function code 0x06", () => {
252
+ const commands = [
253
+ bluetooth_protocol_1.writeCommands.setPower(true),
254
+ bluetooth_protocol_1.writeCommands.setTemperature(21),
255
+ bluetooth_protocol_1.writeCommands.setPowerLevel(3),
256
+ bluetooth_protocol_1.writeCommands.setFan1Speed(2),
257
+ bluetooth_protocol_1.writeCommands.setFan2Speed(2),
258
+ bluetooth_protocol_1.writeCommands.setAutoMode(true),
259
+ bluetooth_protocol_1.writeCommands.setStandby(false),
260
+ ];
261
+ commands.forEach((cmd, i) => {
262
+ assert_1.strict.equal(cmd[1], 0x06, `Command ${i} should use function code 0x06`);
263
+ });
264
+ });
265
+ });
266
+ describe("parsers", () => {
267
+ it("boolean parser returns true for 0x01", () => {
268
+ const response = {
269
+ slaveAddress: 1,
270
+ functionCode: 0x03,
271
+ byteCount: 2,
272
+ data: new Uint8Array([0x00, 0x01]),
273
+ isError: false,
274
+ };
275
+ assert_1.strict.equal(bluetooth_protocol_1.parsers.boolean(response), true);
276
+ });
277
+ it("boolean parser returns false for 0x00", () => {
278
+ const response = {
279
+ slaveAddress: 1,
280
+ functionCode: 0x03,
281
+ byteCount: 2,
282
+ data: new Uint8Array([0x00, 0x00]),
283
+ isError: false,
284
+ };
285
+ assert_1.strict.equal(bluetooth_protocol_1.parsers.boolean(response), false);
286
+ });
287
+ it("temperature parser divides by 10", () => {
288
+ const response = {
289
+ slaveAddress: 1,
290
+ functionCode: 0x03,
291
+ byteCount: 2,
292
+ data: new Uint8Array([0x00, 0xd7]), // 215
293
+ isError: false,
294
+ };
295
+ assert_1.strict.equal(bluetooth_protocol_1.parsers.temperature(response), 21.5);
296
+ });
297
+ it("temperature parser handles high temperatures", () => {
298
+ const response = {
299
+ slaveAddress: 1,
300
+ functionCode: 0x03,
301
+ byteCount: 2,
302
+ data: new Uint8Array([0x01, 0x2c]), // 300
303
+ isError: false,
304
+ };
305
+ assert_1.strict.equal(bluetooth_protocol_1.parsers.temperature(response), 30);
306
+ });
307
+ it("number parser returns big-endian value", () => {
308
+ const response = {
309
+ slaveAddress: 1,
310
+ functionCode: 0x03,
311
+ byteCount: 2,
312
+ data: new Uint8Array([0x00, 0x03]), // power level 3
313
+ isError: false,
314
+ };
315
+ assert_1.strict.equal(bluetooth_protocol_1.parsers.number(response), 3);
316
+ });
317
+ it("number parser handles larger values", () => {
318
+ const response = {
319
+ slaveAddress: 1,
320
+ functionCode: 0x03,
321
+ byteCount: 2,
322
+ data: new Uint8Array([0x01, 0x00]), // 256
323
+ isError: false,
324
+ };
325
+ assert_1.strict.equal(bluetooth_protocol_1.parsers.number(response), 256);
326
+ });
327
+ it("boolean parser throws on error response", () => {
328
+ const errorResponse = {
329
+ slaveAddress: 1,
330
+ functionCode: 0x03,
331
+ data: new Uint8Array([0x02]), // error code
332
+ isError: true,
333
+ };
334
+ assert_1.strict.throws(() => bluetooth_protocol_1.parsers.boolean(errorResponse), /Modbus error: 2/);
335
+ });
336
+ it("temperature parser throws on error response", () => {
337
+ const errorResponse = {
338
+ slaveAddress: 1,
339
+ functionCode: 0x03,
340
+ data: new Uint8Array([0x03]),
341
+ isError: true,
342
+ };
343
+ assert_1.strict.throws(() => bluetooth_protocol_1.parsers.temperature(errorResponse), /Modbus error: 3/);
344
+ });
345
+ it("number parser throws on error response", () => {
346
+ const errorResponse = {
347
+ slaveAddress: 1,
348
+ functionCode: 0x03,
349
+ data: new Uint8Array([0x04]),
350
+ isError: true,
351
+ };
352
+ assert_1.strict.throws(() => bluetooth_protocol_1.parsers.number(errorResponse), /Modbus error: 4/);
353
+ });
354
+ });
355
+ describe("integration", () => {
356
+ it("full roundtrip: create packet, decrypt, check structure", () => __awaiter(void 0, void 0, void 0, function* () {
357
+ // Create a power-on command
358
+ const command = bluetooth_protocol_1.writeCommands.setPower(true);
359
+ assert_1.strict.deepEqual(command, new Uint8Array([0x01, 0x06, 0x03, 0x1c, 0x00, 0x01]));
360
+ // Create encrypted packet
361
+ const packet = yield (0, bluetooth_protocol_1.createPacket)(command);
362
+ assert_1.strict.equal(packet.length, 32);
363
+ // Decrypt it back (as if we received it)
364
+ // Note: createPacket encrypts with padding, parseResponse expects response format
365
+ // This is not a true response but tests the encryption layer
366
+ }));
367
+ it("all read commands can create valid packets", () => __awaiter(void 0, void 0, void 0, function* () {
368
+ for (const [name, command] of Object.entries(bluetooth_protocol_1.readCommands)) {
369
+ const packet = yield (0, bluetooth_protocol_1.createPacket)(command);
370
+ assert_1.strict.equal(packet.length, 32, `${name} should create 32-byte packet`);
371
+ }
372
+ }));
373
+ it("all write commands can create valid packets", () => __awaiter(void 0, void 0, void 0, function* () {
374
+ const commands = [
375
+ { name: "setPower", cmd: bluetooth_protocol_1.writeCommands.setPower(true) },
376
+ { name: "setTemperature", cmd: bluetooth_protocol_1.writeCommands.setTemperature(21) },
377
+ { name: "setPowerLevel", cmd: bluetooth_protocol_1.writeCommands.setPowerLevel(3) },
378
+ { name: "setFan1Speed", cmd: bluetooth_protocol_1.writeCommands.setFan1Speed(2) },
379
+ { name: "setFan2Speed", cmd: bluetooth_protocol_1.writeCommands.setFan2Speed(2) },
380
+ { name: "setAutoMode", cmd: bluetooth_protocol_1.writeCommands.setAutoMode(true) },
381
+ { name: "setStandby", cmd: bluetooth_protocol_1.writeCommands.setStandby(false) },
382
+ ];
383
+ for (const { name, cmd } of commands) {
384
+ const packet = yield (0, bluetooth_protocol_1.createPacket)(cmd);
385
+ assert_1.strict.equal(packet.length, 32, `${name} should create 32-byte packet`);
386
+ }
387
+ }));
388
+ });
389
+ });
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.bleToWifiMac = void 0;
4
+ const mac_utils_1 = require("./mac-utils");
4
5
  /**
5
6
  * Converts a BLE MAC address to WiFi MAC address.
6
7
  * The WiFi MAC is the BLE MAC minus 2 in hexadecimal.
@@ -13,12 +14,7 @@ exports.bleToWifiMac = void 0;
13
14
  * bleToWifiMac("a8032afed50a") // returns "a8032afed508"
14
15
  */
15
16
  const bleToWifiMac = (bleMac) => {
16
- // Remove colons, dashes, and convert to lowercase
17
- const normalized = bleMac.replace(/[:-]/g, "").toLowerCase();
18
- // Validate MAC address format (12 hex characters)
19
- if (!/^[0-9a-f]{12}$/.test(normalized)) {
20
- throw new Error(`Invalid MAC address format: ${bleMac}`);
21
- }
17
+ const normalized = (0, mac_utils_1.normalizeMac)(bleMac);
22
18
  // Convert to number, subtract 2, convert back to hex
23
19
  const bleValue = BigInt(`0x${normalized}`);
24
20
  const wifiValue = bleValue - BigInt(2);
@@ -38,3 +38,5 @@ declare const scanForDevices: () => Promise<DiscoveredDevice[]>;
38
38
  declare const scanWithOptions: (options: RequestDeviceOptions) => Promise<BluetoothDevice>;
39
39
  export { EDILKAMIN_DEVICE_NAME, EDILKAMIN_SERVICE_UUID, isWebBluetoothSupported, scanForDevices, scanWithOptions, };
40
40
  export type { DiscoveredDevice } from "./types";
41
+ export { aesDecrypt, aesEncrypt, crc16Modbus, createPacket, NOTIFY_CHARACTERISTIC_UUID, parseResponse, parsers, readCommands, SERVICE_UUID, WRITE_CHARACTERISTIC_UUID, writeCommands, } from "./bluetooth-protocol";
42
+ export type { ModbusResponse } from "./bluetooth-protocol";
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.scanWithOptions = exports.scanForDevices = exports.isWebBluetoothSupported = exports.EDILKAMIN_SERVICE_UUID = exports.EDILKAMIN_DEVICE_NAME = void 0;
12
+ exports.writeCommands = exports.WRITE_CHARACTERISTIC_UUID = exports.SERVICE_UUID = exports.readCommands = exports.parsers = exports.parseResponse = exports.NOTIFY_CHARACTERISTIC_UUID = exports.createPacket = exports.crc16Modbus = exports.aesEncrypt = exports.aesDecrypt = exports.scanWithOptions = exports.scanForDevices = exports.isWebBluetoothSupported = exports.EDILKAMIN_SERVICE_UUID = exports.EDILKAMIN_DEVICE_NAME = void 0;
13
13
  const bluetooth_utils_1 = require("./bluetooth-utils");
14
14
  /** Device name broadcast by Edilkamin stoves */
15
15
  const EDILKAMIN_DEVICE_NAME = "EDILKAMIN_EP";
@@ -105,3 +105,19 @@ const scanWithOptions = (options) => __awaiter(void 0, void 0, void 0, function*
105
105
  return navigator.bluetooth.requestDevice(options);
106
106
  });
107
107
  exports.scanWithOptions = scanWithOptions;
108
+ // Protocol functions
109
+ var bluetooth_protocol_1 = require("./bluetooth-protocol");
110
+ Object.defineProperty(exports, "aesDecrypt", { enumerable: true, get: function () { return bluetooth_protocol_1.aesDecrypt; } });
111
+ Object.defineProperty(exports, "aesEncrypt", { enumerable: true, get: function () { return bluetooth_protocol_1.aesEncrypt; } });
112
+ Object.defineProperty(exports, "crc16Modbus", { enumerable: true, get: function () { return bluetooth_protocol_1.crc16Modbus; } });
113
+ Object.defineProperty(exports, "createPacket", { enumerable: true, get: function () { return bluetooth_protocol_1.createPacket; } });
114
+ // Constants
115
+ Object.defineProperty(exports, "NOTIFY_CHARACTERISTIC_UUID", { enumerable: true, get: function () { return bluetooth_protocol_1.NOTIFY_CHARACTERISTIC_UUID; } });
116
+ Object.defineProperty(exports, "parseResponse", { enumerable: true, get: function () { return bluetooth_protocol_1.parseResponse; } });
117
+ // Commands
118
+ Object.defineProperty(exports, "parsers", { enumerable: true, get: function () { return bluetooth_protocol_1.parsers; } });
119
+ Object.defineProperty(exports, "readCommands", { enumerable: true, get: function () { return bluetooth_protocol_1.readCommands; } });
120
+ Object.defineProperty(exports, "SERVICE_UUID", { enumerable: true, get: function () { return bluetooth_protocol_1.SERVICE_UUID; } });
121
+ Object.defineProperty(exports, "WRITE_CHARACTERISTIC_UUID", { enumerable: true, get: function () { return bluetooth_protocol_1.WRITE_CHARACTERISTIC_UUID; } });
122
+ // Parsers
123
+ Object.defineProperty(exports, "writeCommands", { enumerable: true, get: function () { return bluetooth_protocol_1.writeCommands; } });
@@ -19,6 +19,7 @@ const readline_1 = __importDefault(require("readline"));
19
19
  const package_json_1 = require("../package.json");
20
20
  const constants_1 = require("./constants");
21
21
  const library_1 = require("./library");
22
+ const mac_utils_1 = require("./mac-utils");
22
23
  const token_storage_1 = require("./token-storage");
23
24
  const types_1 = require("./types");
24
25
  const promptPassword = () => {
@@ -72,7 +73,7 @@ const addLegacyOption = (command) => command.option("--legacy", "Use legacy API
72
73
  */
73
74
  const initializeCommand = (options) => __awaiter(void 0, void 0, void 0, function* () {
74
75
  const { username, password, mac, legacy = false } = options;
75
- const normalizedMac = mac.replace(/:/g, "");
76
+ const normalizedMac = (0, mac_utils_1.normalizeMac)(mac);
76
77
  // Initialize file storage for session persistence
77
78
  const storage = (0, token_storage_1.createFileStorage)();
78
79
  (0, library_1.configureAmplify)(storage);
@@ -395,7 +396,7 @@ const createProgram = () => {
395
396
  .command("getFanSpeed")
396
397
  .description("Retrieve fan speed by index (1-3)")).requiredOption("-i, --index <number>", "Fan index (1, 2, or 3)", parseInt))).action((options) => __awaiter(void 0, void 0, void 0, function* () {
397
398
  const { username, password, mac, index, legacy = false } = options;
398
- const normalizedMac = mac.replace(/:/g, "");
399
+ const normalizedMac = (0, mac_utils_1.normalizeMac)(mac);
399
400
  const storage = (0, token_storage_1.createFileStorage)();
400
401
  (0, library_1.configureAmplify)(storage);
401
402
  let jwtToken;
@@ -418,7 +419,7 @@ const createProgram = () => {
418
419
  .command("getTargetTemperature")
419
420
  .description("Retrieve target temperature by environment index (1-3)")).requiredOption("-i, --index <number>", "Environment index (1, 2, or 3)", parseInt))).action((options) => __awaiter(void 0, void 0, void 0, function* () {
420
421
  const { username, password, mac, index, legacy = false } = options;
421
- const normalizedMac = mac.replace(/:/g, "");
422
+ const normalizedMac = (0, mac_utils_1.normalizeMac)(mac);
422
423
  const storage = (0, token_storage_1.createFileStorage)();
423
424
  (0, library_1.configureAmplify)(storage);
424
425
  let jwtToken;
@@ -444,7 +445,7 @@ const createProgram = () => {
444
445
  .requiredOption("-i, --index <number>", "Fan index (1, 2, or 3)", parseInt)
445
446
  .requiredOption("-v, --value <number>", "Fan speed (0-5)", parseFloat))).action((options) => __awaiter(void 0, void 0, void 0, function* () {
446
447
  const { username, password, mac, index, value, legacy = false } = options;
447
- const normalizedMac = mac.replace(/:/g, "");
448
+ const normalizedMac = (0, mac_utils_1.normalizeMac)(mac);
448
449
  const storage = (0, token_storage_1.createFileStorage)();
449
450
  (0, library_1.configureAmplify)(storage);
450
451
  let jwtToken;
@@ -469,7 +470,7 @@ const createProgram = () => {
469
470
  .requiredOption("-i, --index <number>", "Environment index (1, 2, or 3)", parseInt)
470
471
  .requiredOption("-v, --value <number>", "Temperature in degrees Celsius", parseFloat))).action((options) => __awaiter(void 0, void 0, void 0, function* () {
471
472
  const { username, password, mac, index, value, legacy = false } = options;
472
- const normalizedMac = mac.replace(/:/g, "");
473
+ const normalizedMac = (0, mac_utils_1.normalizeMac)(mac);
473
474
  const storage = (0, token_storage_1.createFileStorage)();
474
475
  (0, library_1.configureAmplify)(storage);
475
476
  let jwtToken;
@@ -493,7 +494,7 @@ const createProgram = () => {
493
494
  .command("getAlarmHistory")
494
495
  .description("Get alarm history log with human-readable descriptions")))).action((options) => __awaiter(void 0, void 0, void 0, function* () {
495
496
  const { username, password, mac, legacy = false } = options;
496
- const normalizedMac = mac.replace(/:/g, "");
497
+ const normalizedMac = (0, mac_utils_1.normalizeMac)(mac);
497
498
  const storage = (0, token_storage_1.createFileStorage)();
498
499
  (0, library_1.configureAmplify)(storage);
499
500
  let jwtToken;
@@ -524,7 +525,7 @@ const createProgram = () => {
524
525
  .requiredOption("-r, --room <deviceRoom>", "Room name")
525
526
  .action((options) => __awaiter(void 0, void 0, void 0, function* () {
526
527
  const { username, password, mac, serial, name, room, legacy = false, } = options;
527
- const normalizedMac = mac.replace(/:/g, "");
528
+ const normalizedMac = (0, mac_utils_1.normalizeMac)(mac);
528
529
  // Initialize file storage for session persistence
529
530
  const storage = (0, token_storage_1.createFileStorage)();
530
531
  (0, library_1.configureAmplify)(storage);
@@ -553,7 +554,7 @@ const createProgram = () => {
553
554
  .requiredOption("-r, --room <deviceRoom>", "Room name")
554
555
  .action((options) => __awaiter(void 0, void 0, void 0, function* () {
555
556
  const { username, password, mac, name, room, legacy = false } = options;
556
- const normalizedMac = mac.replace(/:/g, "");
557
+ const normalizedMac = (0, mac_utils_1.normalizeMac)(mac);
557
558
  // Initialize file storage for session persistence
558
559
  const storage = (0, token_storage_1.createFileStorage)();
559
560
  (0, library_1.configureAmplify)(storage);
@@ -1,8 +1,9 @@
1
1
  export { bleToWifiMac } from "./bluetooth-utils";
2
2
  export { decompressBuffer, isBuffer, processResponse } from "./buffer-utils";
3
3
  export { API_URL, NEW_API_URL, OLD_API_URL } from "./constants";
4
- export { configure, deriveUsageAnalytics, getSession, signIn } from "./library";
4
+ export { configure, derivePhaseDescription, deriveUsageAnalytics, getPhaseDescription, getSession, signIn, } from "./library";
5
+ export { normalizeMac } from "./mac-utils";
5
6
  export { serialNumberDisplay, serialNumberFromHex, serialNumberToHex, } from "./serial-utils";
6
- export { AlarmEntryType, AlarmsLogType, BufferEncodedType, CommandsType, DeviceAssociationBody, DeviceAssociationResponse, DeviceInfoRawType, DeviceInfoType, DiscoveredDevice, EditDeviceAssociationBody, PowerDistributionType, RegenerationDataType, ServiceCountersType, ServiceStatusType, StatusCountersType, StatusType, TemperaturesType, TotalCountersType, UsageAnalyticsType, UserParametersType, } from "./types";
7
- export { AlarmCode, AlarmDescriptions } from "./types";
7
+ export { AlarmEntryType, AlarmsLogType, BufferEncodedType, CommandsType, DeviceAssociationBody, DeviceAssociationResponse, DeviceInfoRawType, DeviceInfoType, DiscoveredDevice, EditDeviceAssociationBody, FansType, PowerDistributionType, RegenerationDataType, ServiceCountersType, ServiceStatusType, StateType, StatusCountersType, StatusType, TemperaturesType, TotalCountersType, UsageAnalyticsType, UserParametersType, } from "./types";
8
+ export { AlarmCode, AlarmDescriptions, getIgnitionSubPhaseDescription, getOperationalPhaseDescription, getStoveStateDescription, IgnitionSubPhase, IgnitionSubPhaseDescriptions, OperationalPhase, OperationalPhaseDescriptions, StoveState, StoveStateDescriptions, } from "./types";
8
9
  export declare const deviceInfo: (jwtToken: string, macAddress: string) => Promise<import("./types").DeviceInfoType>, registerDevice: (jwtToken: string, macAddress: string, serialNumber: string, deviceName?: string, deviceRoom?: string) => Promise<import("./types").DeviceAssociationResponse>, editDevice: (jwtToken: string, macAddress: string, deviceName?: string, deviceRoom?: string) => Promise<import("./types").DeviceAssociationResponse>, setPower: (jwtToken: string, macAddress: string, value: number) => Promise<unknown>, setPowerOff: (jwtToken: string, macAddress: string) => Promise<unknown>, setPowerOn: (jwtToken: string, macAddress: string) => Promise<unknown>, getPower: (jwtToken: string, macAddress: string) => Promise<boolean>, getEnvironmentTemperature: (jwtToken: string, macAddress: string) => Promise<number>, getTargetTemperature: (jwtToken: string, macAddress: string, envIndex: 1 | 2 | 3) => Promise<number>, setTargetTemperature: (jwtToken: string, macAddress: string, envIndex: 1 | 2 | 3, temperature: number) => Promise<unknown>;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.setTargetTemperature = exports.getTargetTemperature = exports.getEnvironmentTemperature = exports.getPower = exports.setPowerOn = exports.setPowerOff = exports.setPower = exports.editDevice = exports.registerDevice = exports.deviceInfo = exports.AlarmDescriptions = exports.AlarmCode = exports.serialNumberToHex = exports.serialNumberFromHex = exports.serialNumberDisplay = exports.signIn = exports.getSession = exports.deriveUsageAnalytics = exports.configure = exports.OLD_API_URL = exports.NEW_API_URL = exports.API_URL = exports.processResponse = exports.isBuffer = exports.decompressBuffer = exports.bleToWifiMac = void 0;
4
+ exports.setTargetTemperature = exports.getTargetTemperature = exports.getEnvironmentTemperature = exports.getPower = exports.setPowerOn = exports.setPowerOff = exports.setPower = exports.editDevice = exports.registerDevice = exports.deviceInfo = exports.StoveStateDescriptions = exports.StoveState = exports.OperationalPhaseDescriptions = exports.OperationalPhase = exports.IgnitionSubPhaseDescriptions = exports.IgnitionSubPhase = exports.getStoveStateDescription = exports.getOperationalPhaseDescription = exports.getIgnitionSubPhaseDescription = exports.AlarmDescriptions = exports.AlarmCode = exports.serialNumberToHex = exports.serialNumberFromHex = exports.serialNumberDisplay = exports.normalizeMac = exports.signIn = exports.getSession = exports.getPhaseDescription = exports.deriveUsageAnalytics = exports.derivePhaseDescription = exports.configure = exports.OLD_API_URL = exports.NEW_API_URL = exports.API_URL = exports.processResponse = exports.isBuffer = exports.decompressBuffer = exports.bleToWifiMac = void 0;
5
5
  const library_1 = require("./library");
6
6
  var bluetooth_utils_1 = require("./bluetooth-utils");
7
7
  Object.defineProperty(exports, "bleToWifiMac", { enumerable: true, get: function () { return bluetooth_utils_1.bleToWifiMac; } });
@@ -15,9 +15,13 @@ Object.defineProperty(exports, "NEW_API_URL", { enumerable: true, get: function
15
15
  Object.defineProperty(exports, "OLD_API_URL", { enumerable: true, get: function () { return constants_1.OLD_API_URL; } });
16
16
  var library_2 = require("./library");
17
17
  Object.defineProperty(exports, "configure", { enumerable: true, get: function () { return library_2.configure; } });
18
+ Object.defineProperty(exports, "derivePhaseDescription", { enumerable: true, get: function () { return library_2.derivePhaseDescription; } });
18
19
  Object.defineProperty(exports, "deriveUsageAnalytics", { enumerable: true, get: function () { return library_2.deriveUsageAnalytics; } });
20
+ Object.defineProperty(exports, "getPhaseDescription", { enumerable: true, get: function () { return library_2.getPhaseDescription; } });
19
21
  Object.defineProperty(exports, "getSession", { enumerable: true, get: function () { return library_2.getSession; } });
20
22
  Object.defineProperty(exports, "signIn", { enumerable: true, get: function () { return library_2.signIn; } });
23
+ var mac_utils_1 = require("./mac-utils");
24
+ Object.defineProperty(exports, "normalizeMac", { enumerable: true, get: function () { return mac_utils_1.normalizeMac; } });
21
25
  var serial_utils_1 = require("./serial-utils");
22
26
  Object.defineProperty(exports, "serialNumberDisplay", { enumerable: true, get: function () { return serial_utils_1.serialNumberDisplay; } });
23
27
  Object.defineProperty(exports, "serialNumberFromHex", { enumerable: true, get: function () { return serial_utils_1.serialNumberFromHex; } });
@@ -25,4 +29,13 @@ Object.defineProperty(exports, "serialNumberToHex", { enumerable: true, get: fun
25
29
  var types_1 = require("./types");
26
30
  Object.defineProperty(exports, "AlarmCode", { enumerable: true, get: function () { return types_1.AlarmCode; } });
27
31
  Object.defineProperty(exports, "AlarmDescriptions", { enumerable: true, get: function () { return types_1.AlarmDescriptions; } });
32
+ Object.defineProperty(exports, "getIgnitionSubPhaseDescription", { enumerable: true, get: function () { return types_1.getIgnitionSubPhaseDescription; } });
33
+ Object.defineProperty(exports, "getOperationalPhaseDescription", { enumerable: true, get: function () { return types_1.getOperationalPhaseDescription; } });
34
+ Object.defineProperty(exports, "getStoveStateDescription", { enumerable: true, get: function () { return types_1.getStoveStateDescription; } });
35
+ Object.defineProperty(exports, "IgnitionSubPhase", { enumerable: true, get: function () { return types_1.IgnitionSubPhase; } });
36
+ Object.defineProperty(exports, "IgnitionSubPhaseDescriptions", { enumerable: true, get: function () { return types_1.IgnitionSubPhaseDescriptions; } });
37
+ Object.defineProperty(exports, "OperationalPhase", { enumerable: true, get: function () { return types_1.OperationalPhase; } });
38
+ Object.defineProperty(exports, "OperationalPhaseDescriptions", { enumerable: true, get: function () { return types_1.OperationalPhaseDescriptions; } });
39
+ Object.defineProperty(exports, "StoveState", { enumerable: true, get: function () { return types_1.StoveState; } });
40
+ Object.defineProperty(exports, "StoveStateDescriptions", { enumerable: true, get: function () { return types_1.StoveStateDescriptions; } });
28
41
  _a = (0, library_1.configure)(), exports.deviceInfo = _a.deviceInfo, exports.registerDevice = _a.registerDevice, exports.editDevice = _a.editDevice, exports.setPower = _a.setPower, exports.setPowerOff = _a.setPowerOff, exports.setPowerOn = _a.setPowerOn, exports.getPower = _a.getPower, exports.getEnvironmentTemperature = _a.getEnvironmentTemperature, exports.getTargetTemperature = _a.getTargetTemperature, exports.setTargetTemperature = _a.setTargetTemperature;
@@ -45,6 +45,32 @@ declare const signIn: (username: string, password: string, legacy?: boolean) =>
45
45
  * const analytics = deriveUsageAnalytics(info);
46
46
  */
47
47
  export declare const deriveUsageAnalytics: (deviceInfo: DeviceInfoType, serviceThreshold?: number) => UsageAnalyticsType;
48
+ /**
49
+ * Get human-readable description of the current device phase.
50
+ * Combines operational_phase and sub_operational_phase for context.
51
+ *
52
+ * @param {number} operationalPhase - The main operational phase.
53
+ * @param {number} subOperationalPhase - The sub-phase (used during ignition).
54
+ * @returns {string} - Human-readable phase description.
55
+ *
56
+ * @example
57
+ * const desc = getPhaseDescription(2, 1);
58
+ * // Returns: "Ignition - Pellet load"
59
+ */
60
+ export declare const getPhaseDescription: (operationalPhase: number, subOperationalPhase: number) => string;
61
+ /**
62
+ * Derive phase description from existing DeviceInfo.
63
+ * Pure function - no API calls required.
64
+ *
65
+ * @param {DeviceInfoType} deviceInfo - The device info object.
66
+ * @returns {string} - Human-readable phase description.
67
+ *
68
+ * @example
69
+ * const info = await api.deviceInfo(token, mac);
70
+ * const desc = derivePhaseDescription(info);
71
+ * // Returns: "On" or "Ignition - Warmup" etc.
72
+ */
73
+ export declare const derivePhaseDescription: (deviceInfo: DeviceInfoType) => string;
48
74
  /**
49
75
  * Configures the library for API interactions.
50
76
  * Initializes API methods with a specified base URL.
@@ -97,6 +123,10 @@ declare const configure: (baseURL?: string) => {
97
123
  getLanguage: (jwtToken: string, macAddress: string) => Promise<number>;
98
124
  getPelletInReserve: (jwtToken: string, macAddress: string) => Promise<boolean>;
99
125
  getPelletAutonomyTime: (jwtToken: string, macAddress: string) => Promise<number>;
126
+ getOperationalPhase: (jwtToken: string, macAddress: string) => Promise<number>;
127
+ getSubOperationalPhase: (jwtToken: string, macAddress: string) => Promise<number>;
128
+ getStoveState: (jwtToken: string, macAddress: string) => Promise<number>;
129
+ getActualPower: (jwtToken: string, macAddress: string) => Promise<number>;
100
130
  getTotalCounters: (jwtToken: string, macAddress: string) => Promise<TotalCountersType>;
101
131
  getServiceCounters: (jwtToken: string, macAddress: string) => Promise<ServiceCountersType>;
102
132
  getAlarmHistory: (jwtToken: string, macAddress: string) => Promise<AlarmsLogType>;