mclimate-payload-helper 1.1.15 → 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.
- package/dist/decoders/commandsReadingHelper.d.ts.map +1 -1
- package/dist/decoders/commandsReadingHelper.js +230 -4
- package/dist/decoders/commandsReadingHelper.js.map +1 -1
- package/dist/encoders/Co2DisplayCommonCommands.d.ts +4 -0
- package/dist/encoders/Co2DisplayCommonCommands.d.ts.map +1 -1
- package/dist/encoders/Co2DisplayCommonCommands.js +38 -0
- package/dist/encoders/Co2DisplayCommonCommands.js.map +1 -1
- package/dist/encoders/FanCoilThermostatCommands.d.ts.map +1 -1
- package/dist/encoders/FanCoilThermostatCommands.js +1 -7
- package/dist/encoders/FanCoilThermostatCommands.js.map +1 -1
- package/dist/encoders/VickiCommands.d.ts +22 -0
- package/dist/encoders/VickiCommands.d.ts.map +1 -1
- package/dist/encoders/VickiCommands.js +339 -0
- package/dist/encoders/VickiCommands.js.map +1 -1
- package/dist/encoders/types/schemas.d.ts +323 -11
- package/dist/encoders/types/schemas.d.ts.map +1 -1
- package/dist/encoders/types/schemas.js +55 -20
- package/dist/encoders/types/schemas.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/test/payloadDecoders.test.js +108 -0
- package/dist/test/payloadDecoders.test.js.map +1 -1
- package/dist/test/payloadEncoders.test.js +86 -0
- package/dist/test/payloadEncoders.test.js.map +1 -1
- package/package.json +1 -1
- package/src/decoders/commandsReadingHelper.ts +240 -4
- package/src/encoders/FanCoilThermostatCommands.ts +1 -7
- package/src/encoders/VickiCommands.ts +390 -0
- package/src/encoders/types/schemas.ts +75 -19
- package/src/index.ts +0 -1
- package/src/test/payloadDecoders.test.ts +110 -1
- package/src/test/payloadEncoders.test.ts +122 -0
- package/dist/encoders/FanCoilThermostat.d.ts +0 -61
- package/dist/encoders/FanCoilThermostat.d.ts.map +0 -1
- package/dist/encoders/FanCoilThermostat.js +0 -719
- package/dist/encoders/FanCoilThermostat.js.map +0 -1
- package/dist/encoders/SetAqiLed.d.ts +0 -6
- package/dist/encoders/SetAqiLed.d.ts.map +0 -1
- package/dist/encoders/SetAqiLed.js +0 -46
- package/dist/encoders/SetAqiLed.js.map +0 -1
- package/dist/encoders/types/enumValidation.d.ts +0 -6
- package/dist/encoders/types/enumValidation.d.ts.map +0 -1
- package/dist/encoders/types/enumValidation.js +0 -50
- package/dist/encoders/types/enumValidation.js.map +0 -1
- package/dist/encoders/types/schemaValidatedEnums.d.ts +0 -40
- package/dist/encoders/types/schemaValidatedEnums.d.ts.map +0 -1
- package/dist/encoders/types/schemaValidatedEnums.js +0 -181
- package/dist/encoders/types/schemaValidatedEnums.js.map +0 -1
- package/dist/types/deviceTypes.d.ts +0 -19
- package/dist/types/deviceTypes.d.ts.map +0 -1
- package/dist/types/deviceTypes.js +0 -23
- package/dist/types/deviceTypes.js.map +0 -1
- package/dist/types/index.d.ts +0 -2
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -18
- package/dist/types/index.js.map +0 -1
- package/dist/types/types.d.ts +0 -13
- package/dist/types/types.d.ts.map +0 -1
- package/dist/types/types.js +0 -9
- package/dist/types/types.js.map +0 -1
- package/dist/validation.d.ts +0 -3
- package/dist/validation.d.ts.map +0 -1
- package/dist/validation.js +0 -8
- 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,
|
|
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
|
-
|
|
2442
|
-
|
|
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
|
-
|
|
2460
|
-
|
|
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 {
|