mclimate-payload-helper 1.1.16 → 1.2.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 (66) hide show
  1. package/dist/decoders/commandsReadingHelper.d.ts.map +1 -1
  2. package/dist/decoders/commandsReadingHelper.js +230 -4
  3. package/dist/decoders/commandsReadingHelper.js.map +1 -1
  4. package/dist/encoders/Co2DisplayCommonCommands.d.ts +4 -0
  5. package/dist/encoders/Co2DisplayCommonCommands.d.ts.map +1 -1
  6. package/dist/encoders/Co2DisplayCommonCommands.js +38 -0
  7. package/dist/encoders/Co2DisplayCommonCommands.js.map +1 -1
  8. package/dist/encoders/FanCoilThermostatCommands.d.ts.map +1 -1
  9. package/dist/encoders/FanCoilThermostatCommands.js +1 -7
  10. package/dist/encoders/FanCoilThermostatCommands.js.map +1 -1
  11. package/dist/encoders/VickiCommands.d.ts +22 -0
  12. package/dist/encoders/VickiCommands.d.ts.map +1 -1
  13. package/dist/encoders/VickiCommands.js +339 -0
  14. package/dist/encoders/VickiCommands.js.map +1 -1
  15. package/dist/encoders/types/schemas.d.ts +323 -11
  16. package/dist/encoders/types/schemas.d.ts.map +1 -1
  17. package/dist/encoders/types/schemas.js +56 -21
  18. package/dist/encoders/types/schemas.js.map +1 -1
  19. package/dist/index.d.ts +1 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +1 -2
  22. package/dist/index.js.map +1 -1
  23. package/dist/test/payloadDecoders.test.js +108 -0
  24. package/dist/test/payloadDecoders.test.js.map +1 -1
  25. package/dist/test/payloadEncoders.test.js +86 -0
  26. package/dist/test/payloadEncoders.test.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/decoders/commandsReadingHelper.ts +240 -4
  29. package/src/encoders/FanCoilThermostatCommands.ts +1 -7
  30. package/src/encoders/VickiCommands.ts +390 -0
  31. package/src/encoders/types/schemas.ts +76 -20
  32. package/src/index.ts +0 -1
  33. package/src/test/payloadDecoders.test.ts +110 -1
  34. package/src/test/payloadEncoders.test.ts +122 -0
  35. package/dist/encoders/FanCoilThermostat.d.ts +0 -61
  36. package/dist/encoders/FanCoilThermostat.d.ts.map +0 -1
  37. package/dist/encoders/FanCoilThermostat.js +0 -719
  38. package/dist/encoders/FanCoilThermostat.js.map +0 -1
  39. package/dist/encoders/SetAqiLed.d.ts +0 -6
  40. package/dist/encoders/SetAqiLed.d.ts.map +0 -1
  41. package/dist/encoders/SetAqiLed.js +0 -46
  42. package/dist/encoders/SetAqiLed.js.map +0 -1
  43. package/dist/encoders/types/enumValidation.d.ts +0 -6
  44. package/dist/encoders/types/enumValidation.d.ts.map +0 -1
  45. package/dist/encoders/types/enumValidation.js +0 -50
  46. package/dist/encoders/types/enumValidation.js.map +0 -1
  47. package/dist/encoders/types/schemaValidatedEnums.d.ts +0 -40
  48. package/dist/encoders/types/schemaValidatedEnums.d.ts.map +0 -1
  49. package/dist/encoders/types/schemaValidatedEnums.js +0 -181
  50. package/dist/encoders/types/schemaValidatedEnums.js.map +0 -1
  51. package/dist/types/deviceTypes.d.ts +0 -19
  52. package/dist/types/deviceTypes.d.ts.map +0 -1
  53. package/dist/types/deviceTypes.js +0 -23
  54. package/dist/types/deviceTypes.js.map +0 -1
  55. package/dist/types/index.d.ts +0 -2
  56. package/dist/types/index.d.ts.map +0 -1
  57. package/dist/types/index.js +0 -18
  58. package/dist/types/index.js.map +0 -1
  59. package/dist/types/types.d.ts +0 -13
  60. package/dist/types/types.d.ts.map +0 -1
  61. package/dist/types/types.js +0 -9
  62. package/dist/types/types.js.map +0 -1
  63. package/dist/validation.d.ts +0 -3
  64. package/dist/validation.d.ts.map +0 -1
  65. package/dist/validation.js +0 -8
  66. package/dist/validation.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"commandsReadingHelper.d.ts","sourceRoot":"","sources":["../../src/decoders/commandsReadingHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAG5D,eAAO,MAAM,qBAAqB,YAAa,MAAM,iBAAiB,MAAM,cAAc,UAAU,mBAi1EnG,CAAA"}
1
+ {"version":3,"file":"commandsReadingHelper.d.ts","sourceRoot":"","sources":["../../src/decoders/commandsReadingHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAG5D,eAAO,MAAM,qBAAqB,YAAa,MAAM,iBAAiB,MAAM,cAAc,UAAU,mBA6jFnG,CAAA"}
@@ -2435,11 +2435,81 @@ const commandsReadingHelper = (hexData, payloadLength, deviceType) => {
2435
2435
  }
2436
2436
  }
2437
2437
  break;
2438
+ case '58':
2439
+ {
2440
+ command_len = 1;
2441
+ let notificationByte = parseInt(commands[i + 1], 16);
2442
+ // Extract notification flags from bits
2443
+ let temperatureRestoredAfterManualBoost = !!(notificationByte & 0x01); // Bit 0
2444
+ let temperatureChangedByHeatingSchedule = !!(notificationByte & 0x02); // Bit 1
2445
+ let data = {
2446
+ notifications: {
2447
+ temperatureRestoredAfterManualBoost: temperatureRestoredAfterManualBoost,
2448
+ temperatureChangedByHeatingSchedule: temperatureChangedByHeatingSchedule
2449
+ }
2450
+ };
2451
+ Object.assign(resultToPass, Object.assign({}, resultToPass), Object.assign({}, data));
2452
+ }
2453
+ break;
2438
2454
  case '5a':
2439
2455
  {
2440
2456
  try {
2441
- command_len = 1;
2442
- let data = { afterOverheatingProtectionRecovery: parseInt(commands[i + 1], 16) };
2457
+ let data;
2458
+ if (deviceType === types_1.DeviceType.Relay16 || deviceType === types_1.DeviceType.Relay16Dry) {
2459
+ command_len = 1;
2460
+ data = { afterOverheatingProtectionRecovery: parseInt(commands[i + 1], 16) };
2461
+ }
2462
+ else {
2463
+ command_len = 41;
2464
+ let eventsGroup = parseInt(commands[i + 1], 16); // 0 = events 0-7, 1 = events 8-15, 2 = events 16-19
2465
+ let eventGroupIndex = ['0-7', '8-15', '16-19'];
2466
+ let heatingEvents = [];
2467
+ // Process up to 8 events for groups 0 and 1, but only 4 events for group 2
2468
+ let eventsToProcess = (eventsGroup === 2) ? 4 : 8;
2469
+ for (let eventIdx = 0; eventIdx < eventsToProcess; eventIdx++) {
2470
+ // Each event takes 5 bytes (hour, minute, temp high, temp low, weekday bitmask)
2471
+ let offset = i + 2 + (eventIdx * 5);
2472
+ // Check if this event is configured
2473
+ // Make sure we have valid values at this offset
2474
+ if (offset >= commands.length || offset + 4 >= commands.length) {
2475
+ continue;
2476
+ }
2477
+ let hour = parseInt(commands[offset], 16);
2478
+ let minute = parseInt(commands[offset + 1], 16);
2479
+ let tempHigh = parseInt(commands[offset + 2], 16);
2480
+ let tempLow = parseInt(commands[offset + 3], 16);
2481
+ let weekdayByte = parseInt(commands[offset + 4], 16);
2482
+ // Skip events that are not configured (zeros or NaN values)
2483
+ if (isNaN(hour) || isNaN(minute) || isNaN(tempHigh) || isNaN(tempLow) || isNaN(weekdayByte) ||
2484
+ (hour === 0 && minute === 0 && tempHigh === 0 && tempLow === 0 && weekdayByte === 0)) {
2485
+ continue;
2486
+ }
2487
+ // Calculate actual event index in the full range (0-23)
2488
+ let globalEventIndex = (eventsGroup * 8) + eventIdx;
2489
+ // Decode weekday bitmask (bit 0=Mon, bit 1=Tue, bit 2=Wed, bit 3=Thu, bit 4=Fri, bit 5=Sat, bit 6=Sun)
2490
+ let weekdays = {
2491
+ monday: !!(weekdayByte & 0x01), // bit 0
2492
+ tuesday: !!(weekdayByte & 0x02), // bit 1
2493
+ wednesday: !!(weekdayByte & 0x04), // bit 2
2494
+ thursday: !!(weekdayByte & 0x08), // bit 3
2495
+ friday: !!(weekdayByte & 0x10), // bit 4
2496
+ saturday: !!(weekdayByte & 0x20), // bit 5
2497
+ sunday: !!(weekdayByte & 0x40) // bit 6
2498
+ };
2499
+ // Create heating event object
2500
+ let heatingEvent = {
2501
+ index: globalEventIndex,
2502
+ start: (hour < 10 ? '0' + hour : hour) + ':' + (minute < 10 ? '0' + minute : minute),
2503
+ targetTemperature: ((tempHigh << 8) | tempLow) / 10,
2504
+ weekdays: weekdays
2505
+ };
2506
+ heatingEvents.push(heatingEvent);
2507
+ }
2508
+ data = {
2509
+ heatingEventGroup: eventGroupIndex[eventsGroup],
2510
+ heatingEvents: heatingEvents
2511
+ };
2512
+ }
2443
2513
  Object.assign(resultToPass, Object.assign({}, resultToPass), Object.assign({}, data));
2444
2514
  }
2445
2515
  catch (e) {
@@ -2456,8 +2526,31 @@ const commandsReadingHelper = (hexData, payloadLength, deviceType) => {
2456
2526
  case '5c':
2457
2527
  {
2458
2528
  try {
2459
- command_len = 1;
2460
- let data = { ledIndicationMode: parseInt(commands[i + 1], 16) };
2529
+ let data;
2530
+ if (deviceType === types_1.DeviceType.Vicki) {
2531
+ command_len = 4;
2532
+ // Note: Months are 0-11 (January=0, December=11)
2533
+ let startMonth = parseInt(commands[i + 1], 16);
2534
+ let startDay = parseInt(commands[i + 2], 16);
2535
+ let endMonth = parseInt(commands[i + 3], 16);
2536
+ let endDay = parseInt(commands[i + 4], 16);
2537
+ // Convert to human-readable month names
2538
+ let monthNames = [
2539
+ 'January', 'February', 'March', 'April', 'May', 'June',
2540
+ 'July', 'August', 'September', 'October', 'November', 'December'
2541
+ ];
2542
+ data = {
2543
+ heatingSchedule: {
2544
+ start: startDay + ' ' + monthNames[startMonth],
2545
+ end: endDay + ' ' + monthNames[endMonth],
2546
+ }
2547
+ };
2548
+ Object.assign(resultToPass, Object.assign({}, resultToPass), Object.assign({}, data));
2549
+ }
2550
+ else {
2551
+ command_len = 1;
2552
+ data = { ledIndicationMode: parseInt(commands[i + 1], 16) };
2553
+ }
2461
2554
  Object.assign(resultToPass, Object.assign({}, resultToPass), Object.assign({}, data));
2462
2555
  }
2463
2556
  catch (e) {
@@ -2489,6 +2582,139 @@ const commandsReadingHelper = (hexData, payloadLength, deviceType) => {
2489
2582
  }
2490
2583
  }
2491
2584
  break;
2585
+ case '5e':
2586
+ {
2587
+ try {
2588
+ command_len = 4;
2589
+ // Parse 32-bit UNIX timestamp (4 bytes)
2590
+ var unixTimestamp = (parseInt(commands[i + 1], 16) << 24) |
2591
+ (parseInt(commands[i + 2], 16) << 16) |
2592
+ (parseInt(commands[i + 3], 16) << 8) |
2593
+ parseInt(commands[i + 4], 16);
2594
+ // Convert UNIX timestamp to JavaScript Date
2595
+ let dateObj = new Date(unixTimestamp * 1000); // Convert seconds to milliseconds
2596
+ let date = dateObj.getUTCDate() + '/' + (dateObj.getUTCMonth() + 1) + '/' + dateObj.getUTCFullYear();
2597
+ let time = dateObj.getUTCHours() + ':' + (dateObj.getUTCMinutes() < 10 ? '0' : '') + dateObj.getUTCMinutes();
2598
+ let data = {
2599
+ deviceTime: "" + date + " " + time
2600
+ };
2601
+ Object.assign(resultToPass, Object.assign({}, resultToPass), Object.assign({}, data));
2602
+ }
2603
+ catch (e) {
2604
+ throw new utils_1.CustomError({
2605
+ message: `Failed to process command '5e'`,
2606
+ hexData,
2607
+ command,
2608
+ deviceType,
2609
+ originalError: e,
2610
+ });
2611
+ }
2612
+ }
2613
+ break;
2614
+ case '60':
2615
+ {
2616
+ command_len = 1;
2617
+ let offsetByte = parseInt(commands[i + 1], 16);
2618
+ let offsetHours = (offsetByte & 0x80) ? (offsetByte - 256) : offsetByte;
2619
+ let data = { deviceTimeZone: offsetHours };
2620
+ Object.assign(resultToPass, Object.assign({}, resultToPass), Object.assign({}, data));
2621
+ }
2622
+ break;
2623
+ case '62':
2624
+ {
2625
+ command_len = 1;
2626
+ let timeValue = parseInt(commands[i + 1], 16);
2627
+ let data = { autoSetpointRestoreStatus: timeValue === 0 ? 0 : timeValue * 10 };
2628
+ Object.assign(resultToPass, Object.assign({}, resultToPass), Object.assign({}, data));
2629
+ }
2630
+ break;
2631
+ case '64':
2632
+ {
2633
+ command_len = 1;
2634
+ let ledDurationValue = parseInt(commands[i + 1], 16);
2635
+ let durationInSeconds = ledDurationValue / 2; // As per the docs, value is divided by 2 to get seconds
2636
+ let data = {
2637
+ ledIndicationDuration: durationInSeconds
2638
+ };
2639
+ Object.assign(resultToPass, Object.assign({}, resultToPass), Object.assign({}, data));
2640
+ }
2641
+ break;
2642
+ case '66':
2643
+ {
2644
+ command_len = 2;
2645
+ let tempHigh = parseInt(commands[i + 1], 16);
2646
+ let tempLow = parseInt(commands[i + 2], 16);
2647
+ let targetTemp = (tempHigh << 8) | tempLow;
2648
+ let data = {
2649
+ offlineTargetTemperature: targetTemp === 0 ? 0 : targetTemp / 10
2650
+ };
2651
+ Object.assign(resultToPass, Object.assign({}, resultToPass), Object.assign({}, data));
2652
+ }
2653
+ break;
2654
+ case '68':
2655
+ {
2656
+ command_len = 1;
2657
+ let data = { internalAlgoTemporaryState: parseInt(commands[i + 1], 16) === 0 ? true : false };
2658
+ Object.assign(resultToPass, Object.assign({}, resultToPass), Object.assign({}, data));
2659
+ }
2660
+ break;
2661
+ case '6a':
2662
+ {
2663
+ command_len = 12;
2664
+ let temperatureLevels = {};
2665
+ // Process 6 scale levels (0-5), each with a 2-byte temperature value
2666
+ for (let level = 0; level < 6; level++) {
2667
+ let tempHighByte = parseInt(commands[i + 1 + (level * 2)], 16);
2668
+ let tempLowByte = parseInt(commands[i + 2 + (level * 2)], 16);
2669
+ let tempValue = (tempHighByte << 8) | tempLowByte;
2670
+ // The temperature values are pre-multiplied by 10
2671
+ temperatureLevels['level' + level] = tempValue / 10;
2672
+ }
2673
+ let data = {
2674
+ temperatureLevels: temperatureLevels
2675
+ };
2676
+ Object.assign(resultToPass, Object.assign({}, resultToPass), Object.assign({}, data));
2677
+ }
2678
+ break;
2679
+ case '6c': {
2680
+ command_len = 4;
2681
+ let eventsHighByte = parseInt(commands[i + 2], 16); // Events 19-16
2682
+ let eventsMidByte = parseInt(commands[i + 3], 16); // Events 15-8
2683
+ let eventsLowByte = parseInt(commands[i + 4], 16); // Events 7-0
2684
+ // Create a more structured and readable format for heating events
2685
+ let heatingEventStates = {};
2686
+ // Process all 20 events (0-19) in a single loop
2687
+ for (let eventIdx = 0; eventIdx < 20; eventIdx++) {
2688
+ // Calculate which bit to check
2689
+ let bitPosition;
2690
+ if (eventIdx >= 16) {
2691
+ // Events 16-19 in high byte
2692
+ bitPosition = eventIdx - 16;
2693
+ heatingEventStates[eventIdx] = !!(eventsHighByte & (1 << bitPosition));
2694
+ }
2695
+ else if (eventIdx >= 8) {
2696
+ // Events 8-15 in mid byte
2697
+ bitPosition = eventIdx - 8;
2698
+ heatingEventStates[eventIdx] = !!(eventsMidByte & (1 << bitPosition));
2699
+ }
2700
+ else {
2701
+ // Events 0-7 in low byte
2702
+ bitPosition = eventIdx;
2703
+ heatingEventStates[eventIdx] = !!(eventsLowByte & (1 << bitPosition));
2704
+ }
2705
+ }
2706
+ let data = {
2707
+ heatingEventStates: heatingEventStates
2708
+ };
2709
+ Object.assign(resultToPass, Object.assign({}, resultToPass), Object.assign({}, data));
2710
+ break;
2711
+ }
2712
+ case '6e': {
2713
+ command_len = 1;
2714
+ let data = { timeRequestByMACcommand: parseInt(commands[i + 1], 16) };
2715
+ Object.assign(resultToPass, Object.assign({}, resultToPass), Object.assign({}, data));
2716
+ break;
2717
+ }
2492
2718
  case '9b':
2493
2719
  {
2494
2720
  try {