mclimate-payload-helper 1.2.2 → 1.2.4

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 (90) hide show
  1. package/dist/decoders/commandsReadingHelper.d.ts.map +1 -1
  2. package/dist/decoders/commandsReadingHelper.js +182 -41
  3. package/dist/decoders/commandsReadingHelper.js.map +1 -1
  4. package/dist/decoders/payloadParsers/index.d.ts +1 -0
  5. package/dist/decoders/payloadParsers/index.d.ts.map +1 -1
  6. package/dist/decoders/payloadParsers/index.js +1 -0
  7. package/dist/decoders/payloadParsers/index.js.map +1 -1
  8. package/dist/decoders/payloadParsers/melissaLorawanPayloadParser.d.ts.map +1 -1
  9. package/dist/decoders/payloadParsers/melissaLorawanPayloadParser.js +12 -12
  10. package/dist/decoders/payloadParsers/melissaLorawanPayloadParser.js.map +1 -1
  11. package/dist/decoders/payloadParsers/multisensorPayloadParser.d.ts +2 -0
  12. package/dist/decoders/payloadParsers/multisensorPayloadParser.d.ts.map +1 -0
  13. package/dist/decoders/payloadParsers/multisensorPayloadParser.js +96 -0
  14. package/dist/decoders/payloadParsers/multisensorPayloadParser.js.map +1 -0
  15. package/dist/decoders/payloadParsers/types/allDevices.d.ts +2 -1
  16. package/dist/decoders/payloadParsers/types/allDevices.d.ts.map +1 -1
  17. package/dist/decoders/payloadParsers/types/allDevices.js +1 -0
  18. package/dist/decoders/payloadParsers/types/allDevices.js.map +1 -1
  19. package/dist/encoders/Co2DisplayCommonCommands.d.ts +0 -4
  20. package/dist/encoders/Co2DisplayCommonCommands.d.ts.map +1 -1
  21. package/dist/encoders/Co2DisplayCommonCommands.js +0 -38
  22. package/dist/encoders/Co2DisplayCommonCommands.js.map +1 -1
  23. package/dist/encoders/CommandBuilder.d.ts.map +1 -1
  24. package/dist/encoders/CommandBuilder.js +2 -0
  25. package/dist/encoders/CommandBuilder.js.map +1 -1
  26. package/dist/encoders/FanCoilThermostat.d.ts +61 -0
  27. package/dist/encoders/FanCoilThermostat.d.ts.map +1 -0
  28. package/dist/encoders/FanCoilThermostat.js +719 -0
  29. package/dist/encoders/FanCoilThermostat.js.map +1 -0
  30. package/dist/encoders/MelissaCommands.d.ts +6 -0
  31. package/dist/encoders/MelissaCommands.d.ts.map +1 -0
  32. package/dist/encoders/MelissaCommands.js +35 -0
  33. package/dist/encoders/MelissaCommands.js.map +1 -0
  34. package/dist/encoders/MultiSensorCommands.d.ts +25 -0
  35. package/dist/encoders/MultiSensorCommands.d.ts.map +1 -0
  36. package/dist/encoders/MultiSensorCommands.js +256 -0
  37. package/dist/encoders/MultiSensorCommands.js.map +1 -0
  38. package/dist/encoders/SetAqiLed.d.ts +6 -0
  39. package/dist/encoders/SetAqiLed.d.ts.map +1 -0
  40. package/dist/encoders/SetAqiLed.js +46 -0
  41. package/dist/encoders/SetAqiLed.js.map +1 -0
  42. package/dist/encoders/index.d.ts +2 -0
  43. package/dist/encoders/index.d.ts.map +1 -1
  44. package/dist/encoders/index.js +2 -0
  45. package/dist/encoders/index.js.map +1 -1
  46. package/dist/encoders/types/enumValidation.d.ts +6 -0
  47. package/dist/encoders/types/enumValidation.d.ts.map +1 -0
  48. package/dist/encoders/types/enumValidation.js +50 -0
  49. package/dist/encoders/types/enumValidation.js.map +1 -0
  50. package/dist/encoders/types/schemaValidatedEnums.d.ts +40 -0
  51. package/dist/encoders/types/schemaValidatedEnums.d.ts.map +1 -0
  52. package/dist/encoders/types/schemaValidatedEnums.js +181 -0
  53. package/dist/encoders/types/schemaValidatedEnums.js.map +1 -0
  54. package/dist/encoders/types/schemas.d.ts +352 -0
  55. package/dist/encoders/types/schemas.d.ts.map +1 -1
  56. package/dist/encoders/types/schemas.js +29 -3
  57. package/dist/encoders/types/schemas.js.map +1 -1
  58. package/dist/test/payloadDecoders.test.js +28 -10
  59. package/dist/test/payloadDecoders.test.js.map +1 -1
  60. package/dist/test/payloadEncoders.test.js +6 -0
  61. package/dist/test/payloadEncoders.test.js.map +1 -1
  62. package/dist/types/deviceTypes.d.ts +19 -0
  63. package/dist/types/deviceTypes.d.ts.map +1 -0
  64. package/dist/types/deviceTypes.js +23 -0
  65. package/dist/types/deviceTypes.js.map +1 -0
  66. package/dist/types/index.d.ts +2 -0
  67. package/dist/types/index.d.ts.map +1 -0
  68. package/dist/types/index.js +18 -0
  69. package/dist/types/index.js.map +1 -0
  70. package/dist/types/types.d.ts +13 -0
  71. package/dist/types/types.d.ts.map +1 -0
  72. package/dist/types/types.js +9 -0
  73. package/dist/types/types.js.map +1 -0
  74. package/dist/validation.d.ts +3 -0
  75. package/dist/validation.d.ts.map +1 -0
  76. package/dist/validation.js +8 -0
  77. package/dist/validation.js.map +1 -0
  78. package/package.json +1 -1
  79. package/src/decoders/commandsReadingHelper.ts +327 -186
  80. package/src/decoders/payloadParsers/index.ts +1 -1
  81. package/src/decoders/payloadParsers/melissaLorawanPayloadParser.ts +19 -16
  82. package/src/decoders/payloadParsers/multisensorPayloadParser.ts +97 -0
  83. package/src/decoders/payloadParsers/types/allDevices.ts +1 -0
  84. package/src/encoders/CommandBuilder.ts +4 -0
  85. package/src/encoders/MelissaCommands.ts +33 -0
  86. package/src/encoders/MultiSensorCommands.ts +253 -0
  87. package/src/encoders/index.ts +2 -0
  88. package/src/encoders/types/schemas.ts +74 -4
  89. package/src/test/payloadDecoders.test.ts +30 -11
  90. package/src/test/payloadEncoders.test.ts +8 -0
@@ -22,6 +22,8 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
22
22
  decodeKeepalive = true
23
23
  } else if ((potentialKeepAlive[0] === '00' || potentialKeepAlive[0] === '88') && deviceType === DeviceType.TFlood) {
24
24
  decodeKeepalive = true
25
+ } else if (potentialKeepAlive[0] === '82' && deviceType === DeviceType.MultiSensor) {
26
+ decodeKeepalive = true
25
27
  } else if (
26
28
  (potentialKeepAlive[0] === '01' || potentialKeepAlive[0] === '20' || potentialKeepAlive[0] === '21') &&
27
29
  deviceType === DeviceType.OpenCloseSensor
@@ -198,6 +200,69 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
198
200
  }
199
201
  }
200
202
  break
203
+ case '0a':
204
+ {
205
+ try {
206
+ let data
207
+ if (deviceType === DeviceType.MelissaLorawan) {
208
+ command_len = 4
209
+ let recordedIrCodeSize = (parseInt(commands[i + 1], 16) << 8) | parseInt(commands[i + 2], 16)
210
+ let bytesSent = `${commands[i + 3]}${commands[i + 4]}`
211
+ data = { recordedIrInfo: { recordedIrCodeSize, bytesSent } }
212
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
213
+ }
214
+ } catch (e) {
215
+ throw new CustomError({
216
+ message: `Failed to process command '0a'`,
217
+ hexData,
218
+ command,
219
+ deviceType,
220
+ originalError: e as Error,
221
+ })
222
+ }
223
+ }
224
+ break
225
+ case '0b':
226
+ {
227
+ try {
228
+ let data
229
+ if (deviceType === DeviceType.MelissaLorawan) {
230
+ // First byte after command indicates how many bytes follow
231
+ const bytesCount = parseInt(commands[i + 1], 16)
232
+ command_len = 1 + bytesCount // 1 for bytesCount + the actual bytes
233
+
234
+ // Next two bytes are buffer offset
235
+ const bufferOffsetMSB = parseInt(commands[i + 2], 16)
236
+ const bufferOffsetLSB = parseInt(commands[i + 3], 16)
237
+ const address = (bufferOffsetMSB << 8) | bufferOffsetLSB
238
+
239
+ // The rest is IR code data
240
+ let irCodeDataString = ''
241
+ for (let j = 4; j < 4 + bytesCount - 2; j++) {
242
+ // -2 to account for the offset bytes
243
+ irCodeDataString += commands[i + j]
244
+ }
245
+
246
+ data = {
247
+ irCodeData: {
248
+ bytesCount: bytesCount - 2,
249
+ address,
250
+ data: irCodeDataString,
251
+ },
252
+ }
253
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
254
+ }
255
+ } catch (e) {
256
+ throw new CustomError({
257
+ message: `Failed to process command '0b'`,
258
+ hexData,
259
+ command,
260
+ deviceType,
261
+ originalError: e as Error,
262
+ })
263
+ }
264
+ }
265
+ break
201
266
  case '0e':
202
267
  {
203
268
  try {
@@ -547,6 +612,10 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
547
612
  overheatingThresholds: { trigger: parseInt(commands[i + 1], 16), recovery: parseInt(commands[i + 2], 16) },
548
613
  }
549
614
  Object.assign(resultToPass, { ...resultToPass }, { ...data })
615
+ } else if (deviceType === DeviceType.MultiSensor) {
616
+ command_len = 1
617
+ let data = { lightEnabled: parseInt(commands[i + 1], 16) === 1 }
618
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
550
619
  } else {
551
620
  command_len = 4
552
621
  let good_medium = parseInt(`${commands[i + 1]}${commands[i + 2]}`, 16)
@@ -587,6 +656,10 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
587
656
  },
588
657
  }
589
658
  Object.assign(resultToPass, { ...resultToPass }, { ...data })
659
+ } else if (deviceType === DeviceType.MultiSensor) {
660
+ command_len = 1
661
+ let data = { hallEnabled: parseInt(commands[i + 1], 16) === 1 }
662
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
590
663
  } else if (deviceType !== DeviceType.OpenCloseSensor) {
591
664
  command_len = 2
592
665
  let data = { autoZeroValue: parseInt(`${commands[i + 1]}${commands[i + 2]}`, 16) }
@@ -643,11 +716,16 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
643
716
  command_len = 1
644
717
  let data = { overcurrentThreshold: parseInt(commands[i + 1], 16) }
645
718
  Object.assign(resultToPass, { ...resultToPass }, { ...data })
719
+ } else if (deviceType === DeviceType.MultiSensor) {
720
+ command_len = 2
721
+ let data = { hallBlindPeriod: (parseInt(commands[i + 1], 16) << 8) | parseInt(commands[i + 2], 16) }
722
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
646
723
  } else {
647
724
  command_len = 3
648
725
  let good_zone = parseInt(commands[i + 1], 16)
649
726
  let medium_zone = parseInt(commands[i + 2], 16)
650
727
  let bad_zone = parseInt(commands[i + 3], 16)
728
+
651
729
  let data = {
652
730
  notifyPeriod: { good_zone: Number(good_zone), medium_zone: Number(medium_zone), bad_zone: Number(bad_zone) },
653
731
  }
@@ -667,7 +745,7 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
667
745
  case '25':
668
746
  {
669
747
  try {
670
- let data = {}
748
+ let data
671
749
  if (deviceType == DeviceType.Relay16) {
672
750
  command_len = 2
673
751
  data = { overpowerThreshold: (parseInt(commands[i + 1], 16) << 8) | parseInt(commands[i + 2], 16) }
@@ -717,6 +795,10 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
717
795
  parseInt(commands[i + 31], 16),
718
796
  },
719
797
  }
798
+ } else if (deviceType === DeviceType.MultiSensor) {
799
+ command_len = 1
800
+ data = { microphoneEnabled: parseInt(commands[i + 1], 16) === 1 }
801
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
720
802
  } else {
721
803
  command_len = 3
722
804
  let good_zone = parseInt(commands[i + 1], 16)
@@ -730,8 +812,8 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
730
812
  bad_zone: Number(bad_zone),
731
813
  },
732
814
  }
815
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
733
816
  }
734
- Object.assign(resultToPass, { ...resultToPass }, { ...data })
735
817
  } catch (e) {
736
818
  throw new CustomError({
737
819
  message: `Failed to process command '25'`,
@@ -750,6 +832,12 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
750
832
  command_len = 1
751
833
  let data = { OVAC: parseInt(commands[i + 1], 16) }
752
834
  Object.assign(resultToPass, { ...resultToPass }, { ...data })
835
+ } else if (deviceType === DeviceType.MultiSensor) {
836
+ command_len = 2
837
+ let data = {
838
+ microphoneSamplingPeriod: (parseInt(commands[i + 1], 16) << 8) | parseInt(commands[i + 2], 16),
839
+ }
840
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
753
841
  } else {
754
842
  command_len = 9
755
843
  let duration_good_beeping = parseInt(commands[i + 1], 16)
@@ -803,6 +891,10 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
803
891
  let period = parseInt(commands[i + 2], 16)
804
892
  let data = { proportionalAlgorithmParameters: { coefficient: Number(coefficient), period: Number(period) } }
805
893
  Object.assign(resultToPass, { ...resultToPass }, { ...data })
894
+ } else if (deviceType === DeviceType.MultiSensor) {
895
+ command_len = 1
896
+ let data = { gasEnabled: parseInt(commands[i + 1], 16) === 1 }
897
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
806
898
  } else {
807
899
  command_len = 15
808
900
  let red_good = parseInt(commands[i + 1], 16)
@@ -865,6 +957,10 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
865
957
  }
866
958
  let data = { temperatureControlAlgorithm: algo }
867
959
  Object.assign(resultToPass, { ...resultToPass }, { ...data })
960
+ } else if (deviceType === DeviceType.MultiSensor) {
961
+ command_len = 1
962
+ let data = { gasMeasurementPeriodMinutes: parseInt(commands[i + 1], 16) }
963
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
868
964
  } else {
869
965
  command_len = 1
870
966
  let data = { autoZeroPeriod: parseInt(commands[i + 1], 16) }
@@ -881,11 +977,34 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
881
977
  }
882
978
  }
883
979
  break
980
+ case '2d':
981
+ {
982
+ try {
983
+ if (deviceType === DeviceType.MultiSensor) {
984
+ command_len = 1
985
+ let data = { pirEnabled: parseInt(commands[i + 1], 16) === 1 }
986
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
987
+ }
988
+ } catch (e) {
989
+ throw new CustomError({
990
+ message: `Failed to process command '2d'`,
991
+ hexData,
992
+ command,
993
+ deviceType,
994
+ originalError: e as Error,
995
+ })
996
+ }
997
+ }
998
+ break
884
999
  case '2f':
885
1000
  {
886
1001
  try {
887
1002
  let data
888
- if (
1003
+ if (deviceType === DeviceType.MultiSensor) {
1004
+ command_len = 2
1005
+ data = { pirBlindPeriod: (parseInt(commands[i + 1], 16) << 8) | parseInt(commands[i + 2], 16) }
1006
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
1007
+ } else if (
889
1008
  deviceType === DeviceType.CO2DisplayLite ||
890
1009
  deviceType === DeviceType.CO2PirLite ||
891
1010
  deviceType === DeviceType.HTPirLite
@@ -933,6 +1052,24 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
933
1052
  }
934
1053
  }
935
1054
  break
1055
+
1056
+ case 'a4':
1057
+ {
1058
+ try {
1059
+ command_len = 1
1060
+ let data = { region: parseInt(commands[i + 1], 16) }
1061
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
1062
+ } catch (e) {
1063
+ throw new CustomError({
1064
+ message: `Failed to process command 'a4'`,
1065
+ hexData,
1066
+ command,
1067
+ deviceType,
1068
+ originalError: e as Error,
1069
+ })
1070
+ }
1071
+ }
1072
+ break
936
1073
  case '32':
937
1074
  {
938
1075
  try {
@@ -1589,18 +1726,18 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
1589
1726
  try {
1590
1727
  let data
1591
1728
  if (deviceType === DeviceType.Vicki) {
1592
- command_len = 2;
1593
- let notificationByte = parseInt(commands[i + 1], 16);
1729
+ command_len = 2
1730
+ let notificationByte = parseInt(commands[i + 1], 16)
1594
1731
  // Extract notification flags from bits
1595
- let temperatureRestoredAfterManualBoost = !!(notificationByte & 0x01); // Bit 0
1596
- let temperatureChangedByHeatingSchedule = !!(notificationByte & 0x02); // Bit 1
1732
+ let temperatureRestoredAfterManualBoost = !!(notificationByte & 0x01) // Bit 0
1733
+ let temperatureChangedByHeatingSchedule = !!(notificationByte & 0x02) // Bit 1
1597
1734
  data = {
1598
1735
  notifications: {
1599
1736
  temperatureRestoredAfterManualBoost: temperatureRestoredAfterManualBoost,
1600
- temperatureChangedByHeatingSchedule: temperatureChangedByHeatingSchedule
1601
- }
1602
- };
1603
- }else{
1737
+ temperatureChangedByHeatingSchedule: temperatureChangedByHeatingSchedule,
1738
+ },
1739
+ }
1740
+ } else {
1604
1741
  command_len = 3
1605
1742
  let state = parseInt(commands[i + 1], 16)
1606
1743
  let time = (parseInt(commands[i + 2], 16) << 8) | parseInt(commands[i + 3], 16)
@@ -1670,7 +1807,7 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
1670
1807
  if (deviceType === DeviceType.FanCoilThermostat) {
1671
1808
  command_len = 1
1672
1809
  data = { fanSpeedNotOccupied: parseInt(commands[i + 1], 16) }
1673
- }else{
1810
+ } else {
1674
1811
  command_len = 1
1675
1812
  data = { manualChangeRelayState: parseInt(commands[i + 1], 16) }
1676
1813
  }
@@ -1719,10 +1856,10 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
1719
1856
  overheatingEvents: { events: parseInt(commands[i + 1], 16), temperature: parseInt(commands[i + 2], 16) },
1720
1857
  }
1721
1858
  } else if (deviceType === DeviceType.Vicki) {
1722
- command_len = 1;
1723
- let offsetByte = parseInt(commands[i + 1], 16);
1724
- let offsetHours = (offsetByte & 0x80) ? (offsetByte - 256) : offsetByte;
1725
- data = { deviceTimeZone: offsetHours };
1859
+ command_len = 1
1860
+ let offsetByte = parseInt(commands[i + 1], 16)
1861
+ let offsetHours = offsetByte & 0x80 ? offsetByte - 256 : offsetByte
1862
+ data = { deviceTimeZone: offsetHours }
1726
1863
  }
1727
1864
  Object.assign(resultToPass, { ...resultToPass }, { ...data })
1728
1865
  } catch (e) {
@@ -1776,10 +1913,10 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
1776
1913
  current: (parseInt(commands[i + 2], 16) << 8) | parseInt(commands[i + 3], 16),
1777
1914
  },
1778
1915
  }
1779
- }else{
1780
- command_len = 1;
1781
- let timeValue = parseInt(commands[i + 1], 16);
1782
- data = { autoSetpointRestoreStatus: timeValue === 0 ? 0 : timeValue * 10 };
1916
+ } else {
1917
+ command_len = 1
1918
+ let timeValue = parseInt(commands[i + 1], 16)
1919
+ data = { autoSetpointRestoreStatus: timeValue === 0 ? 0 : timeValue * 10 }
1783
1920
  }
1784
1921
  Object.assign(resultToPass, { ...resultToPass }, { ...data })
1785
1922
  } catch (e) {
@@ -1919,9 +2056,9 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
1919
2056
  if (deviceType === DeviceType.FanCoilThermostat) {
1920
2057
  command_len = 1
1921
2058
  data = { frostProtectionStatus: parseInt(commands[i + 1], 16) }
1922
- }else{
1923
- command_len = 1;
1924
- data = { timeRequestByMACcommand: parseInt(commands[i + 1], 16) };
2059
+ } else {
2060
+ command_len = 1
2061
+ data = { timeRequestByMACcommand: parseInt(commands[i + 1], 16) }
1925
2062
  }
1926
2063
  Object.assign(resultToPass, { ...resultToPass }, { ...data })
1927
2064
  } catch (e) {
@@ -2302,23 +2439,6 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
2302
2439
  }
2303
2440
  }
2304
2441
  break
2305
- case 'a4':
2306
- {
2307
- try {
2308
- command_len = 1
2309
- let data = { region: parseInt(commands[i + 1], 16) }
2310
- Object.assign(resultToPass, { ...resultToPass }, { ...data })
2311
- } catch (e) {
2312
- throw new CustomError({
2313
- message: `Failed to process command 'a4'`,
2314
- hexData,
2315
- command,
2316
- deviceType,
2317
- originalError: e as Error,
2318
- })
2319
- }
2320
- }
2321
- break
2322
2442
  case 'a6':
2323
2443
  {
2324
2444
  try {
@@ -2339,66 +2459,72 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
2339
2459
  case '5a':
2340
2460
  {
2341
2461
  try {
2342
- let data;
2462
+ let data
2343
2463
  if (deviceType === DeviceType.Relay16 || deviceType === DeviceType.Relay16Dry) {
2344
2464
  command_len = 1
2345
2465
  data = { afterOverheatingProtectionRecovery: parseInt(commands[i + 1], 16) }
2346
2466
  } else {
2347
- command_len = 41;
2348
- let eventsGroup = parseInt(commands[i + 1], 16); // 0 = events 0-7, 1 = events 8-15, 2 = events 16-19
2349
- let eventGroupIndex = ['0-7', '8-15', '16-19'];
2350
- let heatingEvents = [];
2467
+ command_len = 41
2468
+ let eventsGroup = parseInt(commands[i + 1], 16) // 0 = events 0-7, 1 = events 8-15, 2 = events 16-19
2469
+ let eventGroupIndex = ['0-7', '8-15', '16-19']
2470
+ let heatingEvents = []
2351
2471
 
2352
2472
  // Process up to 8 events for groups 0 and 1, but only 4 events for group 2
2353
- let eventsToProcess = (eventsGroup === 2) ? 4 : 8;
2473
+ let eventsToProcess = eventsGroup === 2 ? 4 : 8
2354
2474
  for (let eventIdx = 0; eventIdx < eventsToProcess; eventIdx++) {
2355
2475
  // Each event takes 5 bytes (hour, minute, temp high, temp low, weekday bitmask)
2356
- let offset = i + 2 + (eventIdx * 5);
2476
+ let offset = i + 2 + eventIdx * 5
2357
2477
 
2358
2478
  // Check if this event is configured
2359
2479
  // Make sure we have valid values at this offset
2360
2480
  if (offset >= commands.length || offset + 4 >= commands.length) {
2361
- continue;
2481
+ continue
2362
2482
  }
2363
2483
 
2364
- let hour = parseInt(commands[offset], 16);
2365
- let minute = parseInt(commands[offset + 1], 16);
2366
- let tempHigh = parseInt(commands[offset + 2], 16);
2367
- let tempLow = parseInt(commands[offset + 3], 16);
2368
- let weekdayByte = parseInt(commands[offset + 4], 16);
2484
+ let hour = parseInt(commands[offset], 16)
2485
+ let minute = parseInt(commands[offset + 1], 16)
2486
+ let tempHigh = parseInt(commands[offset + 2], 16)
2487
+ let tempLow = parseInt(commands[offset + 3], 16)
2488
+ let weekdayByte = parseInt(commands[offset + 4], 16)
2369
2489
 
2370
2490
  // Skip events that are not configured (zeros or NaN values)
2371
- if (isNaN(hour) || isNaN(minute) || isNaN(tempHigh) || isNaN(tempLow) || isNaN(weekdayByte) ||
2372
- (hour === 0 && minute === 0 && tempHigh === 0 && tempLow === 0 && weekdayByte === 0)) {
2373
- continue;
2491
+ if (
2492
+ isNaN(hour) ||
2493
+ isNaN(minute) ||
2494
+ isNaN(tempHigh) ||
2495
+ isNaN(tempLow) ||
2496
+ isNaN(weekdayByte) ||
2497
+ (hour === 0 && minute === 0 && tempHigh === 0 && tempLow === 0 && weekdayByte === 0)
2498
+ ) {
2499
+ continue
2374
2500
  }
2375
2501
 
2376
2502
  // Calculate actual event index in the full range (0-23)
2377
- let globalEventIndex = (eventsGroup * 8) + eventIdx;
2503
+ let globalEventIndex = eventsGroup * 8 + eventIdx
2378
2504
  // Decode weekday bitmask (bit 0=Mon, bit 1=Tue, bit 2=Wed, bit 3=Thu, bit 4=Fri, bit 5=Sat, bit 6=Sun)
2379
2505
  let weekdays = {
2380
- monday: !!(weekdayByte & 0x01), // bit 0
2381
- tuesday: !!(weekdayByte & 0x02), // bit 1
2382
- wednesday: !!(weekdayByte & 0x04), // bit 2
2383
- thursday: !!(weekdayByte & 0x08), // bit 3
2384
- friday: !!(weekdayByte & 0x10), // bit 4
2385
- saturday: !!(weekdayByte & 0x20), // bit 5
2386
- sunday: !!(weekdayByte & 0x40) // bit 6
2387
- };
2506
+ monday: !!(weekdayByte & 0x01), // bit 0
2507
+ tuesday: !!(weekdayByte & 0x02), // bit 1
2508
+ wednesday: !!(weekdayByte & 0x04), // bit 2
2509
+ thursday: !!(weekdayByte & 0x08), // bit 3
2510
+ friday: !!(weekdayByte & 0x10), // bit 4
2511
+ saturday: !!(weekdayByte & 0x20), // bit 5
2512
+ sunday: !!(weekdayByte & 0x40), // bit 6
2513
+ }
2388
2514
 
2389
2515
  // Create heating event object
2390
2516
  let heatingEvent = {
2391
2517
  index: globalEventIndex,
2392
2518
  start: (hour < 10 ? '0' + hour : hour) + ':' + (minute < 10 ? '0' + minute : minute),
2393
2519
  targetTemperature: ((tempHigh << 8) | tempLow) / 10,
2394
- weekdays: weekdays
2395
- };
2396
- heatingEvents.push(heatingEvent);
2520
+ weekdays: weekdays,
2521
+ }
2522
+ heatingEvents.push(heatingEvent)
2397
2523
  }
2398
2524
  data = {
2399
2525
  heatingEventGroup: eventGroupIndex[eventsGroup],
2400
- heatingEvents: heatingEvents
2401
- };
2526
+ heatingEvents: heatingEvents,
2527
+ }
2402
2528
  }
2403
2529
  Object.assign(resultToPass, { ...resultToPass }, { ...data })
2404
2530
  } catch (e) {
@@ -2415,30 +2541,40 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
2415
2541
  case '5c':
2416
2542
  {
2417
2543
  try {
2418
- let data;
2544
+ let data
2419
2545
  if (deviceType === DeviceType.Vicki) {
2420
- command_len = 4;
2546
+ command_len = 4
2421
2547
  // Note: Months are 0-11 (January=0, December=11)
2422
- let startMonth = parseInt(commands[i + 1], 16);
2423
- let startDay = parseInt(commands[i + 2], 16);
2424
- let endMonth = parseInt(commands[i + 3], 16);
2425
- let endDay = parseInt(commands[i + 4], 16);
2548
+ let startMonth = parseInt(commands[i + 1], 16)
2549
+ let startDay = parseInt(commands[i + 2], 16)
2550
+ let endMonth = parseInt(commands[i + 3], 16)
2551
+ let endDay = parseInt(commands[i + 4], 16)
2426
2552
 
2427
2553
  // Convert to human-readable month names
2428
2554
  let monthNames = [
2429
- 'January', 'February', 'March', 'April', 'May', 'June',
2430
- 'July', 'August', 'September', 'October', 'November', 'December'
2431
- ];
2555
+ 'January',
2556
+ 'February',
2557
+ 'March',
2558
+ 'April',
2559
+ 'May',
2560
+ 'June',
2561
+ 'July',
2562
+ 'August',
2563
+ 'September',
2564
+ 'October',
2565
+ 'November',
2566
+ 'December',
2567
+ ]
2432
2568
 
2433
2569
  data = {
2434
2570
  heatingSchedule: {
2435
2571
  start: startDay + ' ' + monthNames[startMonth],
2436
2572
  end: endDay + ' ' + monthNames[endMonth],
2437
- }
2438
- };
2439
- Object.assign(resultToPass, { ...resultToPass }, { ...data });
2573
+ },
2574
+ }
2575
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
2440
2576
  } else {
2441
- command_len = 1;
2577
+ command_len = 1
2442
2578
  data = { ledIndicationMode: parseInt(commands[i + 1], 16) }
2443
2579
  }
2444
2580
  Object.assign(resultToPass, { ...resultToPass }, { ...data })
@@ -2456,20 +2592,21 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
2456
2592
  case '5e':
2457
2593
  {
2458
2594
  try {
2459
- command_len = 4;
2595
+ command_len = 4
2460
2596
  // Parse 32-bit UNIX timestamp (4 bytes)
2461
- var unixTimestamp = (parseInt(commands[i + 1], 16) << 24) |
2597
+ var unixTimestamp =
2598
+ (parseInt(commands[i + 1], 16) << 24) |
2462
2599
  (parseInt(commands[i + 2], 16) << 16) |
2463
2600
  (parseInt(commands[i + 3], 16) << 8) |
2464
- parseInt(commands[i + 4], 16);
2601
+ parseInt(commands[i + 4], 16)
2465
2602
 
2466
2603
  // Convert UNIX timestamp to JavaScript Date
2467
- let dateObj = new Date(unixTimestamp * 1000); // Convert seconds to milliseconds
2604
+ let dateObj = new Date(unixTimestamp * 1000) // Convert seconds to milliseconds
2468
2605
  let date = dateObj.getUTCDate() + '/' + (dateObj.getUTCMonth() + 1) + '/' + dateObj.getUTCFullYear()
2469
2606
  let time = dateObj.getUTCHours() + ':' + (dateObj.getUTCMinutes() < 10 ? '0' : '') + dateObj.getUTCMinutes()
2470
2607
  let data = {
2471
- deviceTime: "" + date + " " + time
2472
- };
2608
+ deviceTime: '' + date + ' ' + time,
2609
+ }
2473
2610
  Object.assign(resultToPass, { ...resultToPass }, { ...data })
2474
2611
  } catch (e) {
2475
2612
  throw new CustomError({
@@ -2481,131 +2618,135 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
2481
2618
  })
2482
2619
  }
2483
2620
  }
2484
- break;
2485
- case '64': {
2486
- try {
2487
- command_len = 1;
2488
- let ledDurationValue = parseInt(commands[i + 1], 16);
2489
- let durationInSeconds = ledDurationValue / 2; // As per the docs, value is divided by 2 to get seconds
2621
+ break
2622
+ case '64':
2623
+ {
2624
+ try {
2625
+ command_len = 1
2626
+ let ledDurationValue = parseInt(commands[i + 1], 16)
2627
+ let durationInSeconds = ledDurationValue / 2 // As per the docs, value is divided by 2 to get seconds
2490
2628
 
2491
- let data = {
2492
- ledIndicationDuration: durationInSeconds
2493
- };
2494
- Object.assign(resultToPass, { ...resultToPass }, { ...data })
2495
- } catch (e) {
2496
- throw new CustomError({
2497
- message: `Failed to process command '64'`,
2498
- hexData,
2499
- command,
2500
- deviceType,
2501
- originalError: e as Error,
2502
- })
2629
+ let data = {
2630
+ ledIndicationDuration: durationInSeconds,
2631
+ }
2632
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
2633
+ } catch (e) {
2634
+ throw new CustomError({
2635
+ message: `Failed to process command '64'`,
2636
+ hexData,
2637
+ command,
2638
+ deviceType,
2639
+ originalError: e as Error,
2640
+ })
2641
+ }
2503
2642
  }
2504
- }
2505
- break;
2506
- case '66': {
2507
- try {
2508
- command_len = 2;
2643
+ break
2644
+ case '66':
2645
+ {
2646
+ try {
2647
+ command_len = 2
2509
2648
 
2510
- let tempHigh = parseInt(commands[i + 1], 16);
2511
- let tempLow = parseInt(commands[i + 2], 16);
2512
- let targetTemp = (tempHigh << 8) | tempLow;
2513
- let data = {
2514
- offlineTargetTemperature: targetTemp === 0 ? 0 : targetTemp / 10
2515
- };
2516
- Object.assign(resultToPass, { ...resultToPass }, { ...data })
2517
- } catch (e) {
2518
- throw new CustomError({
2519
- message: `Failed to process command '66'`,
2520
- hexData,
2521
- command,
2522
- deviceType,
2523
- originalError: e as Error,
2524
- })
2649
+ let tempHigh = parseInt(commands[i + 1], 16)
2650
+ let tempLow = parseInt(commands[i + 2], 16)
2651
+ let targetTemp = (tempHigh << 8) | tempLow
2652
+ let data = {
2653
+ offlineTargetTemperature: targetTemp === 0 ? 0 : targetTemp / 10,
2654
+ }
2655
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
2656
+ } catch (e) {
2657
+ throw new CustomError({
2658
+ message: `Failed to process command '66'`,
2659
+ hexData,
2660
+ command,
2661
+ deviceType,
2662
+ originalError: e as Error,
2663
+ })
2664
+ }
2525
2665
  }
2526
- }
2527
- break;
2528
- case '68': {
2529
- try {
2530
- command_len = 1;
2531
- let data = { internalAlgoTemporaryState: parseInt(commands[i + 1], 16) === 0 ? true : false };
2532
- Object.assign(resultToPass, { ...resultToPass }, { ...data })
2533
- } catch (e) {
2534
- throw new CustomError({
2535
- message: `Failed to process command '68'`,
2536
- hexData,
2537
- command,
2538
- deviceType,
2539
- originalError: e as Error,
2540
- })
2666
+ break
2667
+ case '68':
2668
+ {
2669
+ try {
2670
+ command_len = 1
2671
+ let data = { internalAlgoTemporaryState: parseInt(commands[i + 1], 16) === 0 ? true : false }
2672
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
2673
+ } catch (e) {
2674
+ throw new CustomError({
2675
+ message: `Failed to process command '68'`,
2676
+ hexData,
2677
+ command,
2678
+ deviceType,
2679
+ originalError: e as Error,
2680
+ })
2681
+ }
2541
2682
  }
2542
- }
2543
- break;
2544
- case '6a': {
2545
- try {
2546
- command_len = 12;
2547
- let temperatureLevels: { [key: string]: number } = {};
2683
+ break
2684
+ case '6a':
2685
+ {
2686
+ try {
2687
+ command_len = 12
2688
+ let temperatureLevels: { [key: string]: number } = {}
2548
2689
 
2549
- // Process 6 scale levels (0-5), each with a 2-byte temperature value
2550
- for (let level = 0; level < 6; level++) {
2551
- let tempHighByte = parseInt(commands[i + 1 + (level * 2)], 16);
2552
- let tempLowByte = parseInt(commands[i + 2 + (level * 2)], 16);
2553
- let tempValue = (tempHighByte << 8) | tempLowByte;
2690
+ // Process 6 scale levels (0-5), each with a 2-byte temperature value
2691
+ for (let level = 0; level < 6; level++) {
2692
+ let tempHighByte = parseInt(commands[i + 1 + level * 2], 16)
2693
+ let tempLowByte = parseInt(commands[i + 2 + level * 2], 16)
2694
+ let tempValue = (tempHighByte << 8) | tempLowByte
2554
2695
 
2555
- // The temperature values are pre-multiplied by 10
2556
- temperatureLevels['level' + level] = tempValue / 10;
2557
- }
2696
+ // The temperature values are pre-multiplied by 10
2697
+ temperatureLevels['level' + level] = tempValue / 10
2698
+ }
2558
2699
 
2559
- let data = {
2560
- temperatureLevels: temperatureLevels
2561
- };
2700
+ let data = {
2701
+ temperatureLevels: temperatureLevels,
2702
+ }
2562
2703
 
2563
- Object.assign(resultToPass, { ...resultToPass }, { ...data })
2564
- } catch (e) {
2565
- throw new CustomError({
2566
- message: `Failed to process command '6a'`,
2567
- hexData,
2568
- command,
2569
- deviceType,
2570
- originalError: e as Error,
2571
- })
2704
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
2705
+ } catch (e) {
2706
+ throw new CustomError({
2707
+ message: `Failed to process command '6a'`,
2708
+ hexData,
2709
+ command,
2710
+ deviceType,
2711
+ originalError: e as Error,
2712
+ })
2713
+ }
2572
2714
  }
2573
- }
2574
- break;
2715
+ break
2575
2716
  case '6c': {
2576
2717
  try {
2577
- command_len = 4;
2578
- let eventsHighByte = parseInt(commands[i + 2], 16); // Events 19-16
2579
- let eventsMidByte = parseInt(commands[i + 3], 16); // Events 15-8
2580
- let eventsLowByte = parseInt(commands[i + 4], 16); // Events 7-0
2718
+ command_len = 4
2719
+ let eventsHighByte = parseInt(commands[i + 2], 16) // Events 19-16
2720
+ let eventsMidByte = parseInt(commands[i + 3], 16) // Events 15-8
2721
+ let eventsLowByte = parseInt(commands[i + 4], 16) // Events 7-0
2581
2722
 
2582
2723
  // Create a more structured and readable format for heating events
2583
- let heatingEventStates: { [key: string]: boolean } = {};
2724
+ let heatingEventStates: { [key: string]: boolean } = {}
2584
2725
 
2585
2726
  // Process all 20 events (0-19) in a single loop
2586
2727
  for (let eventIdx = 0; eventIdx < 20; eventIdx++) {
2587
2728
  // Calculate which bit to check
2588
- let bitPosition;
2729
+ let bitPosition
2589
2730
  if (eventIdx >= 16) {
2590
2731
  // Events 16-19 in high byte
2591
- bitPosition = eventIdx - 16;
2592
- heatingEventStates[eventIdx] = !!(eventsHighByte & (1 << bitPosition));
2732
+ bitPosition = eventIdx - 16
2733
+ heatingEventStates[eventIdx] = !!(eventsHighByte & (1 << bitPosition))
2593
2734
  } else if (eventIdx >= 8) {
2594
2735
  // Events 8-15 in mid byte
2595
- bitPosition = eventIdx - 8;
2596
- heatingEventStates[eventIdx] = !!(eventsMidByte & (1 << bitPosition));
2736
+ bitPosition = eventIdx - 8
2737
+ heatingEventStates[eventIdx] = !!(eventsMidByte & (1 << bitPosition))
2597
2738
  } else {
2598
2739
  // Events 0-7 in low byte
2599
- bitPosition = eventIdx;
2600
- heatingEventStates[eventIdx] = !!(eventsLowByte & (1 << bitPosition));
2740
+ bitPosition = eventIdx
2741
+ heatingEventStates[eventIdx] = !!(eventsLowByte & (1 << bitPosition))
2601
2742
  }
2602
2743
  }
2603
2744
 
2604
2745
  let data = {
2605
- heatingEventStates: heatingEventStates
2606
- };
2746
+ heatingEventStates: heatingEventStates,
2747
+ }
2607
2748
 
2608
- Object.assign(resultToPass, { ...resultToPass }, { ...data });
2749
+ Object.assign(resultToPass, { ...resultToPass }, { ...data })
2609
2750
  } catch (e) {
2610
2751
  throw new CustomError({
2611
2752
  message: `Failed to process command '6c'`,
@@ -2615,7 +2756,7 @@ export const commandsReadingHelper = (hexData: string, payloadLength: number, de
2615
2756
  originalError: e as Error,
2616
2757
  })
2617
2758
  }
2618
- break;
2759
+ break
2619
2760
  }
2620
2761
  case '9b':
2621
2762
  {