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.
@@ -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
+ });
@@ -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 { AlarmCode, AlarmDescriptions };
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
+ };