edilkamin 1.11.0 → 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.
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/bluetooth-utils.js +2 -6
- package/dist/cjs/src/cli.js +9 -8
- package/dist/cjs/src/index.d.ts +4 -3
- package/dist/cjs/src/index.js +14 -1
- package/dist/cjs/src/library.d.ts +30 -0
- package/dist/cjs/src/library.js +97 -3
- package/dist/cjs/src/library.test.js +225 -4
- package/dist/cjs/src/mac-utils.d.ts +15 -0
- package/dist/cjs/src/mac-utils.js +24 -0
- package/dist/cjs/src/mac-utils.test.d.ts +1 -0
- package/dist/cjs/src/mac-utils.test.js +41 -0
- package/dist/cjs/src/types.d.ts +94 -2
- package/dist/cjs/src/types.js +95 -1
- package/dist/esm/package.json +1 -1
- package/dist/esm/src/bluetooth-utils.js +2 -6
- package/dist/esm/src/cli.js +9 -8
- package/dist/esm/src/index.d.ts +4 -3
- package/dist/esm/src/index.js +3 -2
- package/dist/esm/src/library.d.ts +30 -0
- package/dist/esm/src/library.js +94 -2
- package/dist/esm/src/library.test.js +226 -5
- package/dist/esm/src/mac-utils.d.ts +15 -0
- package/dist/esm/src/mac-utils.js +21 -0
- package/dist/esm/src/mac-utils.test.d.ts +1 -0
- package/dist/esm/src/mac-utils.test.js +39 -0
- package/dist/esm/src/types.d.ts +94 -2
- package/dist/esm/src/types.js +89 -1
- package/package.json +1 -1
- package/src/bluetooth-utils.ts +3 -7
- package/src/cli.ts +9 -8
- package/src/index.ts +24 -2
- package/src/library.test.ts +325 -4
- package/src/library.ts +109 -2
- package/src/mac-utils.test.ts +60 -0
- package/src/mac-utils.ts +22 -0
- package/src/types.ts +144 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { strict as assert } from "assert";
|
|
2
|
+
|
|
3
|
+
import { normalizeMac } from "./mac-utils";
|
|
4
|
+
|
|
5
|
+
describe("mac-utils", () => {
|
|
6
|
+
describe("normalizeMac", () => {
|
|
7
|
+
it("should normalize MAC address with colons", () => {
|
|
8
|
+
assert.equal(normalizeMac("AA:BB:CC:DD:EE:FF"), "aabbccddeeff");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("should normalize MAC address with dashes", () => {
|
|
12
|
+
assert.equal(normalizeMac("AA-BB-CC-DD-EE-FF"), "aabbccddeeff");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should normalize MAC address without separators", () => {
|
|
16
|
+
assert.equal(normalizeMac("AABBCCDDEEFF"), "aabbccddeeff");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should normalize lowercase MAC address", () => {
|
|
20
|
+
assert.equal(normalizeMac("aa:bb:cc:dd:ee:ff"), "aabbccddeeff");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should normalize mixed case MAC address", () => {
|
|
24
|
+
assert.equal(normalizeMac("Aa:Bb:Cc:Dd:Ee:Ff"), "aabbccddeeff");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should normalize MAC address with mixed separators", () => {
|
|
28
|
+
assert.equal(normalizeMac("AA:BB-CC:DD-EE:FF"), "aabbccddeeff");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should throw on MAC address with invalid length (too short)", () => {
|
|
32
|
+
assert.throws(
|
|
33
|
+
() => normalizeMac("AA:BB:CC:DD:EE"),
|
|
34
|
+
/Invalid MAC address format: AA:BB:CC:DD:EE/,
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should throw on MAC address with invalid length (too long)", () => {
|
|
39
|
+
assert.throws(
|
|
40
|
+
() => normalizeMac("AA:BB:CC:DD:EE:FF:00"),
|
|
41
|
+
/Invalid MAC address format: AA:BB:CC:DD:EE:FF:00/,
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should throw on MAC address with invalid characters", () => {
|
|
46
|
+
assert.throws(
|
|
47
|
+
() => normalizeMac("GG:HH:II:JJ:KK:LL"),
|
|
48
|
+
/Invalid MAC address format: GG:HH:II:JJ:KK:LL/,
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("should throw on empty string", () => {
|
|
53
|
+
assert.throws(() => normalizeMac(""), /Invalid MAC address format: /);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should throw on whitespace-only string", () => {
|
|
57
|
+
assert.throws(() => normalizeMac(" "), /Invalid MAC address format:/);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
package/src/mac-utils.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes a MAC address by removing separators and converting to lowercase.
|
|
3
|
+
* Accepts formats: AA:BB:CC:DD:EE:FF, AA-BB-CC-DD-EE-FF, AABBCCDDEEFF
|
|
4
|
+
*
|
|
5
|
+
* @param mac - MAC address in any common format
|
|
6
|
+
* @returns Normalized MAC address (12 lowercase hex chars, no separators)
|
|
7
|
+
* @throws Error if MAC address format is invalid
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* normalizeMac("AA:BB:CC:DD:EE:FF") // returns "aabbccddeeff"
|
|
11
|
+
* normalizeMac("AA-BB-CC-DD-EE-FF") // returns "aabbccddeeff"
|
|
12
|
+
* normalizeMac("AABBCCDDEEFF") // returns "aabbccddeeff"
|
|
13
|
+
*/
|
|
14
|
+
const normalizeMac = (mac: string): string => {
|
|
15
|
+
const normalized = mac.replace(/[:-]/g, "").toLowerCase();
|
|
16
|
+
if (!/^[0-9a-f]{12}$/.test(normalized)) {
|
|
17
|
+
throw new Error(`Invalid MAC address format: ${mac}`);
|
|
18
|
+
}
|
|
19
|
+
return normalized;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export { normalizeMac };
|
package/src/types.ts
CHANGED
|
@@ -31,12 +31,44 @@ interface StatusCountersType {
|
|
|
31
31
|
service_time: number;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Device operational state information.
|
|
36
|
+
* Retrieved from status.state in the API response.
|
|
37
|
+
*/
|
|
38
|
+
interface StateType {
|
|
39
|
+
/** Main operational phase (0=Off, 1=Standby, 2=Ignition, 6=On) */
|
|
40
|
+
operational_phase: number;
|
|
41
|
+
/** Sub-phase within current operation (0-6 during ignition) */
|
|
42
|
+
sub_operational_phase: number;
|
|
43
|
+
/** Combined stove state code */
|
|
44
|
+
stove_state: number;
|
|
45
|
+
/** Current alarm code (0 = no alarm) */
|
|
46
|
+
alarm_type: number;
|
|
47
|
+
/** Current actual power level (1-5) */
|
|
48
|
+
actual_power: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Fan speed information for all three fans.
|
|
53
|
+
* Retrieved from status.fans in the API response.
|
|
54
|
+
*/
|
|
55
|
+
interface FansType {
|
|
56
|
+
/** Fan 1 speed (0-5) */
|
|
57
|
+
fan_1_speed: number;
|
|
58
|
+
/** Fan 2 speed (0-5) */
|
|
59
|
+
fan_2_speed: number;
|
|
60
|
+
/** Fan 3 speed (0-5) */
|
|
61
|
+
fan_3_speed: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
34
64
|
interface StatusType {
|
|
35
65
|
commands: CommandsType;
|
|
36
66
|
temperatures: TemperaturesType;
|
|
37
67
|
flags: GeneralFlagsType;
|
|
38
68
|
pellet: PelletAutonomyType;
|
|
39
69
|
counters: StatusCountersType;
|
|
70
|
+
state: StateType;
|
|
71
|
+
fans: FansType;
|
|
40
72
|
}
|
|
41
73
|
|
|
42
74
|
interface UserParametersType {
|
|
@@ -212,6 +244,103 @@ const AlarmDescriptions: Record<AlarmCode, string> = {
|
|
|
212
244
|
[AlarmCode.BOARD_FUSE]: "Control board fuse issue",
|
|
213
245
|
};
|
|
214
246
|
|
|
247
|
+
/**
|
|
248
|
+
* Main operational phases of the stove.
|
|
249
|
+
* Values derived from device behavior observation.
|
|
250
|
+
*/
|
|
251
|
+
enum OperationalPhase {
|
|
252
|
+
OFF = 0,
|
|
253
|
+
STANDBY = 1,
|
|
254
|
+
IGNITION = 2,
|
|
255
|
+
ON = 6,
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Human-readable descriptions for operational phases.
|
|
260
|
+
*/
|
|
261
|
+
const OperationalPhaseDescriptions: Record<number, string> = {
|
|
262
|
+
[OperationalPhase.OFF]: "Off",
|
|
263
|
+
[OperationalPhase.STANDBY]: "Standby",
|
|
264
|
+
[OperationalPhase.IGNITION]: "Ignition",
|
|
265
|
+
[OperationalPhase.ON]: "On",
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Get description for an operational phase, with fallback for unknown values.
|
|
270
|
+
*/
|
|
271
|
+
const getOperationalPhaseDescription = (phase: number): string =>
|
|
272
|
+
OperationalPhaseDescriptions[phase] ?? `Unknown phase (${phase})`;
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Sub-phases during ignition sequence.
|
|
276
|
+
* These are only meaningful when operational_phase === IGNITION.
|
|
277
|
+
*/
|
|
278
|
+
enum IgnitionSubPhase {
|
|
279
|
+
STARTING_CLEANING = 0,
|
|
280
|
+
PELLET_LOAD = 1,
|
|
281
|
+
LOADING_BREAK = 2,
|
|
282
|
+
SMOKE_TEMPERATURE_CHECK = 3,
|
|
283
|
+
THRESHOLD_EXCEEDING_CHECK = 4,
|
|
284
|
+
WARMUP = 5,
|
|
285
|
+
TRANSITION_TO_ON = 6,
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Human-readable descriptions for ignition sub-phases.
|
|
290
|
+
*/
|
|
291
|
+
const IgnitionSubPhaseDescriptions: Record<number, string> = {
|
|
292
|
+
[IgnitionSubPhase.STARTING_CLEANING]: "Starting cleaning",
|
|
293
|
+
[IgnitionSubPhase.PELLET_LOAD]: "Pellet load",
|
|
294
|
+
[IgnitionSubPhase.LOADING_BREAK]: "Loading break",
|
|
295
|
+
[IgnitionSubPhase.SMOKE_TEMPERATURE_CHECK]: "Smoke temperature check",
|
|
296
|
+
[IgnitionSubPhase.THRESHOLD_EXCEEDING_CHECK]: "Threshold exceeding check",
|
|
297
|
+
[IgnitionSubPhase.WARMUP]: "Warmup",
|
|
298
|
+
[IgnitionSubPhase.TRANSITION_TO_ON]: "Starting up",
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Get description for an ignition sub-phase, with fallback for unknown values.
|
|
303
|
+
*/
|
|
304
|
+
const getIgnitionSubPhaseDescription = (subPhase: number): string =>
|
|
305
|
+
IgnitionSubPhaseDescriptions[subPhase] ?? `Unknown sub-phase (${subPhase})`;
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Combined stove states.
|
|
309
|
+
* This is a composite value combining operational phase and sub-phase.
|
|
310
|
+
*/
|
|
311
|
+
enum StoveState {
|
|
312
|
+
OFF = 0,
|
|
313
|
+
STANDBY = 1,
|
|
314
|
+
IGNITION_CLEANING = 2,
|
|
315
|
+
IGNITION_LOADING = 3,
|
|
316
|
+
IGNITION_WAITING = 4,
|
|
317
|
+
IGNITION_WARMUP = 5,
|
|
318
|
+
ON = 6,
|
|
319
|
+
COOLING = 7,
|
|
320
|
+
ALARM = 8,
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Human-readable descriptions for stove states.
|
|
325
|
+
*/
|
|
326
|
+
const StoveStateDescriptions: Record<number, string> = {
|
|
327
|
+
[StoveState.OFF]: "Off",
|
|
328
|
+
[StoveState.STANDBY]: "Standby",
|
|
329
|
+
[StoveState.IGNITION_CLEANING]: "Ignition - Cleaning",
|
|
330
|
+
[StoveState.IGNITION_LOADING]: "Ignition - Loading pellets",
|
|
331
|
+
[StoveState.IGNITION_WAITING]: "Ignition - Waiting",
|
|
332
|
+
[StoveState.IGNITION_WARMUP]: "Ignition - Warming up",
|
|
333
|
+
[StoveState.ON]: "On",
|
|
334
|
+
[StoveState.COOLING]: "Cooling down",
|
|
335
|
+
[StoveState.ALARM]: "Alarm",
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Get description for a stove state, with fallback for unknown values.
|
|
340
|
+
*/
|
|
341
|
+
const getStoveStateDescription = (state: number): string =>
|
|
342
|
+
StoveStateDescriptions[state] ?? `Unknown state (${state})`;
|
|
343
|
+
|
|
215
344
|
interface DeviceInfoType {
|
|
216
345
|
status: StatusType;
|
|
217
346
|
nvm: {
|
|
@@ -294,12 +423,14 @@ export type {
|
|
|
294
423
|
DeviceInfoType,
|
|
295
424
|
DiscoveredDevice,
|
|
296
425
|
EditDeviceAssociationBody,
|
|
426
|
+
FansType,
|
|
297
427
|
GeneralFlagsType,
|
|
298
428
|
PelletAutonomyType,
|
|
299
429
|
PowerDistributionType,
|
|
300
430
|
RegenerationDataType,
|
|
301
431
|
ServiceCountersType,
|
|
302
432
|
ServiceStatusType,
|
|
433
|
+
StateType,
|
|
303
434
|
StatusCountersType,
|
|
304
435
|
StatusType,
|
|
305
436
|
TemperaturesType,
|
|
@@ -308,4 +439,16 @@ export type {
|
|
|
308
439
|
UserParametersType,
|
|
309
440
|
};
|
|
310
441
|
|
|
311
|
-
export {
|
|
442
|
+
export {
|
|
443
|
+
AlarmCode,
|
|
444
|
+
AlarmDescriptions,
|
|
445
|
+
getIgnitionSubPhaseDescription,
|
|
446
|
+
getOperationalPhaseDescription,
|
|
447
|
+
getStoveStateDescription,
|
|
448
|
+
IgnitionSubPhase,
|
|
449
|
+
IgnitionSubPhaseDescriptions,
|
|
450
|
+
OperationalPhase,
|
|
451
|
+
OperationalPhaseDescriptions,
|
|
452
|
+
StoveState,
|
|
453
|
+
StoveStateDescriptions,
|
|
454
|
+
};
|