homebridge-melcloud-control 4.3.16-beta.0 → 4.3.16-beta.10

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/src/deviceatw.js CHANGED
@@ -118,33 +118,31 @@ class DeviceAtw extends EventEmitter {
118
118
  if (restFulEnabled) {
119
119
  try {
120
120
 
121
- if (!this.restFulConnected) {
122
- this.restFul1 = new RestFul({
123
- port: this.restFul.port,
124
- logWarn: this.logWarn,
125
- logDebug: this.logDebug
121
+ this.restFul1 = new RestFul({
122
+ port: this.restFul.port,
123
+ logWarn: this.logWarn,
124
+ logDebug: this.logDebug
125
+ })
126
+ .on('connected', (message) => {
127
+ this.restFulConnected = true;
128
+ this.emit('success', message);
126
129
  })
127
- .on('connected', (message) => {
128
- this.restFulConnected = true;
129
- this.emit('success', message);
130
- })
131
- .on('set', async (key, value) => {
132
- try {
133
- await this.setOverExternalIntegration('RESTFul', this.deviceData, key, value);
134
- } catch (error) {
135
- this.emit('warn', error);
136
- };
137
- })
138
- .on('debug', (debug) => {
139
- this.emit('debug', debug);
140
- })
141
- .on('warn', (warn) => {
142
- this.emit('warn', warn);
143
- })
144
- .on('error', (error) => {
145
- this.emit('error', error);
146
- });
147
- }
130
+ .on('set', async (key, value) => {
131
+ try {
132
+ await this.setOverExternalIntegration('RESTFul', this.deviceData, key, value);
133
+ } catch (error) {
134
+ this.emit('warn', error);
135
+ };
136
+ })
137
+ .on('debug', (debug) => {
138
+ this.emit('debug', debug);
139
+ })
140
+ .on('warn', (warn) => {
141
+ this.emit('warn', warn);
142
+ })
143
+ .on('error', (error) => {
144
+ this.emit('error', error);
145
+ });
148
146
  } catch (error) {
149
147
  if (this.logWarn) this.emit('warn', `RESTFul integration start error: ${error}`);
150
148
  };
@@ -154,41 +152,39 @@ class DeviceAtw extends EventEmitter {
154
152
  const mqttEnabled = this.mqtt.enable || false;
155
153
  if (mqttEnabled) {
156
154
  try {
157
- if (!this.mqttConnected) {
158
- this.mqtt1 = new Mqtt({
159
- host: this.mqtt.host,
160
- port: this.mqtt.port || 1883,
161
- clientId: this.mqtt.clientId ? `melcloud_${this.mqtt.clientId}_${Math.random().toString(16).slice(3)}` : `melcloud_${Math.random().toString(16).slice(3)}`,
162
- prefix: this.mqtt.prefix ? `melcloud/${this.mqtt.prefix}/${this.deviceTypeString}/${this.deviceName}` : `melcloud/${this.deviceTypeString}/${this.deviceName}`,
163
- user: this.mqtt.auth?.user,
164
- passwd: this.mqtt.auth?.passwd,
165
- logWarn: this.logWarn,
166
- logDebug: this.logDebug
155
+ this.mqtt1 = new Mqtt({
156
+ host: this.mqtt.host,
157
+ port: this.mqtt.port || 1883,
158
+ clientId: this.mqtt.clientId ? `melcloud_${this.mqtt.clientId}_${Math.random().toString(16).slice(3)}` : `melcloud_${Math.random().toString(16).slice(3)}`,
159
+ prefix: this.mqtt.prefix ? `melcloud/${this.mqtt.prefix}/${this.deviceTypeString}/${this.deviceName}` : `melcloud/${this.deviceTypeString}/${this.deviceName}`,
160
+ user: this.mqtt.auth?.user,
161
+ passwd: this.mqtt.auth?.passwd,
162
+ logWarn: this.logWarn,
163
+ logDebug: this.logDebug
164
+ })
165
+ .on('connected', (message) => {
166
+ this.mqttConnected = true;
167
+ this.emit('success', message);
167
168
  })
168
- .on('connected', (message) => {
169
- this.mqttConnected = true;
170
- this.emit('success', message);
171
- })
172
- .on('subscribed', (message) => {
173
- this.emit('success', message);
174
- })
175
- .on('set', async (key, value) => {
176
- try {
177
- await this.setOverExternalIntegration('MQTT', this.deviceData, key, value);
178
- } catch (error) {
179
- this.emit('warn', error);
180
- };
181
- })
182
- .on('debug', (debug) => {
183
- this.emit('debug', debug);
184
- })
185
- .on('warn', (warn) => {
186
- this.emit('warn', warn);
187
- })
188
- .on('error', (error) => {
189
- this.emit('error', error);
190
- });
191
- }
169
+ .on('subscribed', (message) => {
170
+ this.emit('success', message);
171
+ })
172
+ .on('set', async (key, value) => {
173
+ try {
174
+ await this.setOverExternalIntegration('MQTT', this.deviceData, key, value);
175
+ } catch (error) {
176
+ this.emit('warn', error);
177
+ };
178
+ })
179
+ .on('debug', (debug) => {
180
+ this.emit('debug', debug);
181
+ })
182
+ .on('warn', (warn) => {
183
+ this.emit('warn', warn);
184
+ })
185
+ .on('error', (error) => {
186
+ this.emit('error', error);
187
+ });
192
188
  } catch (error) {
193
189
  if (this.logWarn) this.emit('warn', `MQTT integration start error: ${error}`);
194
190
  };
@@ -1058,27 +1054,95 @@ class DeviceAtw extends EventEmitter {
1058
1054
  }
1059
1055
 
1060
1056
  //frost protection
1061
- if (this.frostProtectionSupport && this.accessory.frostProtectionEnabled !== null) {
1057
+ if (this.frostProtectionSupport && this.accessory.frostProtection.Enabled !== null) {
1062
1058
  //control
1063
1059
  if (this.logDebug) this.emit('debug', `Prepare frost protection control service`);
1064
- this.frostProtectionControlService = new Service.Switch(`${serviceName} Frost Protection`, `frostProtectionControlService${deviceId}`);
1065
- this.frostProtectionControlService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1066
- this.frostProtectionControlService.setCharacteristic(Characteristic.ConfiguredName, `${accessoryName} Frost Protection`);
1067
- this.frostProtectionControlService.getCharacteristic(Characteristic.On)
1060
+ const frostProtectionControlService = new Service.HeaterCooler(`${serviceName} Frost Protection`, `frostProtectionControlService${deviceId}`);
1061
+ frostProtectionControlService.addOptionalCharacteristic(Characteristic.ConfiguredName);
1062
+ frostProtectionControlService.setCharacteristic(Characteristic.ConfiguredName, `${accessoryName} Frost Protection`);
1063
+ frostProtectionControlService.getCharacteristic(Characteristic.Active)
1068
1064
  .onGet(async () => {
1069
- const state = this.accessory.frostProtectionEnabled;
1065
+ const state = this.accessory.frostProtection.Enabled;
1070
1066
  return state;
1071
1067
  })
1072
1068
  .onSet(async (state) => {
1073
1069
  try {
1074
- deviceData.FrostProtection.Enabled = state;
1070
+ deviceData.FrostProtection.Enabled = state ? true : false;
1075
1071
  if (this.logInfo) this.emit('info', `Frost protection: ${state ? 'Enabled' : 'Disabled'}`);
1076
1072
  await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'frostprotection');
1077
1073
  } catch (error) {
1078
1074
  if (this.logWarn) this.emit('warn', `Set frost protection error: ${error}`);
1079
1075
  };
1080
1076
  });
1081
- accessory.addService(this.frostProtectionControlService);
1077
+ frostProtectionControlService.getCharacteristic(Characteristic.CurrentHeaterCoolerState)
1078
+ .onGet(async () => {
1079
+ const value = this.accessory.frostProtection.Active ? 2 : 1;
1080
+ return value;
1081
+ })
1082
+ frostProtectionControlService.getCharacteristic(Characteristic.TargetHeaterCoolerState)
1083
+ .setProps({
1084
+ minValue: 0,
1085
+ maxValue: 0,
1086
+ validValues: [0]
1087
+ })
1088
+ .onGet(async () => {
1089
+ const value = 0
1090
+ return value;
1091
+ })
1092
+ .onSet(async (value) => {
1093
+ try {
1094
+ deviceData.FrostProtection.Enabled = true;
1095
+ if (this.logInfo) this.emit('info', `Frost protection: Enabled`);
1096
+ await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'frostprotection');
1097
+ } catch (error) {
1098
+ if (this.logWarn) this.emit('warn', `Set frost protection error: ${error}`);
1099
+ };
1100
+ });
1101
+ frostProtectionControlService.getCharacteristic(Characteristic.CurrentTemperature)
1102
+ .onGet(async () => {
1103
+ const value = this.accessory.roomTemperature;
1104
+ return value;
1105
+ });
1106
+ frostProtectionControlService.getCharacteristic(Characteristic.CoolingThresholdTemperature) //max
1107
+ .setProps({
1108
+ minValue: 6,
1109
+ maxValue: 16,
1110
+ minStep: 1
1111
+ })
1112
+ .onGet(async () => {
1113
+ const value = this.accessory.frostProtection.Max;
1114
+ return value;
1115
+ })
1116
+ .onSet(async (value) => {
1117
+ try {
1118
+ deviceData.FrostProtection.Max = value;
1119
+ if (this.logInfo) this.emit('info', `Set frost protection max. temperature: ${value}${this.accessory.temperatureUnit}`);
1120
+ await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'frostprotection');
1121
+ } catch (error) {
1122
+ if (this.logWarn) this.emit('warn', `Set frost protection max. temperature error: ${error}`);
1123
+ };
1124
+ });
1125
+ frostProtectionControlService.getCharacteristic(Characteristic.HeatingThresholdTemperature) //min
1126
+ .setProps({
1127
+ minValue: 4,
1128
+ maxValue: 14,
1129
+ minStep: 1
1130
+ })
1131
+ .onGet(async () => {
1132
+ const value = this.accessory.frostProtection.Min;
1133
+ return value;
1134
+ })
1135
+ .onSet(async (value) => {
1136
+ try {
1137
+ deviceData.FrostProtection.Min = value;
1138
+ if (this.logInfo) this.emit('info', `Set frost protection min. temperature: ${value}${this.accessory.temperatureUnit}`);
1139
+ await this.melCloudAta.send(this.accountType, this.displayType, deviceData, 'frostprotection');
1140
+ } catch (error) {
1141
+ if (this.logWarn) this.emit('warn', `Set frost protection min. temperature error: ${error}`);
1142
+ };
1143
+ });
1144
+ this.frostProtectionControlService = frostProtectionControlService;
1145
+ accessory.addService(frostProtectionControlService);
1082
1146
 
1083
1147
  if (this.logDebug) this.emit('debug', `Prepare frost protection control sensor service`);
1084
1148
  this.frostProtectionControlSensorService = new Service.ContactSensor(`${serviceName} Frost Protection Control`, `frostProtectionControlSensorService${deviceId}`);
@@ -1086,7 +1150,7 @@ class DeviceAtw extends EventEmitter {
1086
1150
  this.frostProtectionControlSensorService.setCharacteristic(Characteristic.ConfiguredName, `${accessoryName} Frost Protection Control`);
1087
1151
  this.frostProtectionControlSensorService.getCharacteristic(Characteristic.ContactSensorState)
1088
1152
  .onGet(async () => {
1089
- const state = this.accessory.frostProtectionEnabled;
1153
+ const state = this.accessory.frostProtection.Enabled;
1090
1154
  return state;
1091
1155
  })
1092
1156
  accessory.addService(this.frostProtectionControlSensorService);
@@ -1098,7 +1162,7 @@ class DeviceAtw extends EventEmitter {
1098
1162
  this.frostProtectionSensorService.setCharacteristic(Characteristic.ConfiguredName, `${accessoryName} Frost Protection`);
1099
1163
  this.frostProtectionSensorService.getCharacteristic(Characteristic.ContactSensorState)
1100
1164
  .onGet(async () => {
1101
- const state = this.accessory.frostProtectionActive;
1165
+ const state = this.accessory.frostProtection.Active;
1102
1166
  return state;
1103
1167
  })
1104
1168
  accessory.addService(this.frostProtectionSensorService);
@@ -1613,8 +1677,7 @@ class DeviceAtw extends EventEmitter {
1613
1677
  const holidayModeActive = deviceData.HolidayMode?.Active ?? false;
1614
1678
 
1615
1679
  //protection
1616
- const frostProtectionEnabled = deviceData.FrostProtection?.Enabled;
1617
- const frostProtectionActive = deviceData.FrostProtection?.Active ?? false;
1680
+ const frostProtection = deviceData.FrostProtection ?? {};
1618
1681
 
1619
1682
  //device info
1620
1683
  const supportsStanbyMode = deviceData.Device[supportStandbyKey];
@@ -1723,8 +1786,7 @@ class DeviceAtw extends EventEmitter {
1723
1786
  temperatureUnit: TemperatureDisplayUnits[this.accountInfo.useFahrenheit ? 1 : 0],
1724
1787
  isConnected: isConnected,
1725
1788
  isInError: isInError,
1726
- frostProtectionEnabled: frostProtectionEnabled,
1727
- frostProtectionActive: frostProtectionActive,
1789
+ frostProtection: frostProtection,
1728
1790
  scheduleEnabled: scheduleEnabled,
1729
1791
  holidayModeEnabled: holidayModeEnabled,
1730
1792
  holidayModeActive: holidayModeActive,
@@ -2124,10 +2186,15 @@ class DeviceAtw extends EventEmitter {
2124
2186
  this.errorService?.updateCharacteristic(Characteristic.ContactSensorState, isInError);
2125
2187
 
2126
2188
  //frost protection
2127
- if (this.frostProtectionSupport && frostProtectionEnabled !== null) {
2128
- this.frostProtectionControlService?.updateCharacteristic(Characteristic.On, frostProtectionEnabled);
2129
- this.frostProtectionControlSensorService?.updateCharacteristic(Characteristic.ContactSensorState, frostProtectionEnabled);
2130
- this.frostProtectionSensorService?.updateCharacteristic(Characteristic.ContactSensorState, frostProtectionActive);
2189
+ if (this.frostProtectionSupport && frostProtection.Enabled !== null) {
2190
+ this.frostProtectionControlService?.updateCharacteristic(Characteristic.Active, frostProtection.Enabled);
2191
+ this.frostProtectionControlService?.updateCharacteristic(Characteristic.CurrentHeaterCoolerState, frostProtection.Active ? 2 : 1);
2192
+ this.frostProtectionControlService?.updateCharacteristic(Characteristic.TargetHeaterCoolerState, frostProtection.Active ? 2 : 1);
2193
+ this.frostProtectionControlService?.updateCharacteristic(Characteristic.CurrentTemperature, roomTemperature);
2194
+ this.frostProtectionControlService?.updateCharacteristic(Characteristic.CoolingThresholdTemperature, frostProtection.Max);
2195
+ this.frostProtectionControlService?.updateCharacteristic(Characteristic.HeatingThresholdTemperature, frostProtection.Min);
2196
+ this.frostProtectionControlSensorService?.updateCharacteristic(Characteristic.ContactSensorState, frostProtection.Enabled);
2197
+ this.frostProtectionSensorService?.updateCharacteristic(Characteristic.ContactSensorState, frostProtection.Active);
2131
2198
  }
2132
2199
 
2133
2200
  //holiday mode
package/src/deviceerv.js CHANGED
@@ -109,34 +109,31 @@ class DeviceErv extends EventEmitter {
109
109
  const restFulEnabled = this.restFul.enable || false;
110
110
  if (restFulEnabled) {
111
111
  try {
112
-
113
- if (!this.restFulConnected) {
114
- this.restFul1 = new RestFul({
115
- port: this.restFul.port,
116
- logWarn: this.logWarn,
117
- logDebug: this.logDebug
112
+ this.restFul1 = new RestFul({
113
+ port: this.restFul.port,
114
+ logWarn: this.logWarn,
115
+ logDebug: this.logDebug
116
+ })
117
+ .on('connected', (message) => {
118
+ this.restFulConnected = true;
119
+ this.emit('success', message);
118
120
  })
119
- .on('connected', (message) => {
120
- this.restFulConnected = true;
121
- this.emit('success', message);
122
- })
123
- .on('set', async (key, value) => {
124
- try {
125
- await this.setOverExternalIntegration('RESTFul', this.deviceData, key, value);
126
- } catch (error) {
127
- this.emit('warn', error);
128
- };
129
- })
130
- .on('debug', (debug) => {
131
- this.emit('debug', debug);
132
- })
133
- .on('warn', (warn) => {
134
- this.emit('warn', warn);
135
- })
136
- .on('error', (error) => {
137
- this.emit('error', error);
138
- });
139
- }
121
+ .on('set', async (key, value) => {
122
+ try {
123
+ await this.setOverExternalIntegration('RESTFul', this.deviceData, key, value);
124
+ } catch (error) {
125
+ this.emit('warn', error);
126
+ };
127
+ })
128
+ .on('debug', (debug) => {
129
+ this.emit('debug', debug);
130
+ })
131
+ .on('warn', (warn) => {
132
+ this.emit('warn', warn);
133
+ })
134
+ .on('error', (error) => {
135
+ this.emit('error', error);
136
+ });
140
137
  } catch (error) {
141
138
  if (this.logWarn) this.emit('warn', `RESTFul integration start error: ${error}`);
142
139
  };
@@ -146,41 +143,39 @@ class DeviceErv extends EventEmitter {
146
143
  const mqttEnabled = this.mqtt.enable || false;
147
144
  if (mqttEnabled) {
148
145
  try {
149
- if (!this.mqttConnected) {
150
- this.mqtt1 = new Mqtt({
151
- host: this.mqtt.host,
152
- port: this.mqtt.port || 1883,
153
- clientId: this.mqtt.clientId ? `melcloud_${this.mqtt.clientId}_${Math.random().toString(16).slice(3)}` : `melcloud_${Math.random().toString(16).slice(3)}`,
154
- prefix: this.mqtt.prefix ? `melcloud/${this.mqtt.prefix}/${this.deviceTypeString}/${this.deviceName}` : `melcloud/${this.deviceTypeString}/${this.deviceName}`,
155
- user: this.mqtt.auth?.user,
156
- passwd: this.mqtt.auth?.passwd,
157
- logWarn: this.logWarn,
158
- logDebug: this.logDebug
146
+ this.mqtt1 = new Mqtt({
147
+ host: this.mqtt.host,
148
+ port: this.mqtt.port || 1883,
149
+ clientId: this.mqtt.clientId ? `melcloud_${this.mqtt.clientId}_${Math.random().toString(16).slice(3)}` : `melcloud_${Math.random().toString(16).slice(3)}`,
150
+ prefix: this.mqtt.prefix ? `melcloud/${this.mqtt.prefix}/${this.deviceTypeString}/${this.deviceName}` : `melcloud/${this.deviceTypeString}/${this.deviceName}`,
151
+ user: this.mqtt.auth?.user,
152
+ passwd: this.mqtt.auth?.passwd,
153
+ logWarn: this.logWarn,
154
+ logDebug: this.logDebug
155
+ })
156
+ .on('connected', (message) => {
157
+ this.mqttConnected = true;
158
+ this.emit('success', message);
159
159
  })
160
- .on('connected', (message) => {
161
- this.mqttConnected = true;
162
- this.emit('success', message);
163
- })
164
- .on('subscribed', (message) => {
165
- this.emit('success', message);
166
- })
167
- .on('set', async (key, value) => {
168
- try {
169
- await this.setOverExternalIntegration('MQTT', this.deviceData, key, value);
170
- } catch (error) {
171
- this.emit('warn', error);
172
- };
173
- })
174
- .on('debug', (debug) => {
175
- this.emit('debug', debug);
176
- })
177
- .on('warn', (warn) => {
178
- this.emit('warn', warn);
179
- })
180
- .on('error', (error) => {
181
- this.emit('error', error);
182
- });
183
- }
160
+ .on('subscribed', (message) => {
161
+ this.emit('success', message);
162
+ })
163
+ .on('set', async (key, value) => {
164
+ try {
165
+ await this.setOverExternalIntegration('MQTT', this.deviceData, key, value);
166
+ } catch (error) {
167
+ this.emit('warn', error);
168
+ };
169
+ })
170
+ .on('debug', (debug) => {
171
+ this.emit('debug', debug);
172
+ })
173
+ .on('warn', (warn) => {
174
+ this.emit('warn', warn);
175
+ })
176
+ .on('error', (error) => {
177
+ this.emit('error', error);
178
+ });
184
179
  } catch (error) {
185
180
  if (this.logWarn) this.emit('warn', `MQTT integration start error: ${error}`);
186
181
  };
package/src/functions.js CHANGED
@@ -56,7 +56,7 @@ class Functions extends EventEmitter {
56
56
 
57
57
  async ensureChromiumInstalled() {
58
58
  try {
59
- // --- Detect OS ---
59
+ // Detect OS
60
60
  const { stdout: osOut } = await execPromise("uname -s");
61
61
  const osName = osOut.trim();
62
62
  const { stdout: archOut } = await execPromise("uname -m");
@@ -66,7 +66,7 @@ class Functions extends EventEmitter {
66
66
  const isMac = osName === "Darwin";
67
67
  const isLinux = osName === "Linux";
68
68
 
69
- // --- Detect Docker ---
69
+ // Detect Docker
70
70
  let isDocker = false;
71
71
  try {
72
72
  await access("/.dockerenv");
@@ -77,7 +77,7 @@ class Functions extends EventEmitter {
77
77
  if (stdout.includes("docker") || stdout.includes("containerd")) isDocker = true;
78
78
  } catch { }
79
79
 
80
- // --- macOS ---
80
+ // macOS
81
81
  if (isMac) {
82
82
  const macCandidates = [
83
83
  "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
@@ -92,7 +92,7 @@ class Functions extends EventEmitter {
92
92
  return null;
93
93
  }
94
94
 
95
- // --- ARM / Raspberry Pi ---
95
+ // ARM / Raspberry Pi
96
96
  if (isARM && isLinux) {
97
97
  const armCandidates = [
98
98
  "/usr/bin/chromium-browser",
@@ -132,7 +132,7 @@ class Functions extends EventEmitter {
132
132
  return null;
133
133
  }
134
134
 
135
- // --- QNAP / Entware ---
135
+ // QNAP / Entware
136
136
  let entwareExists = false;
137
137
  try {
138
138
  await access("/opt/bin/opkg", fs.constants.X_OK);
@@ -147,7 +147,7 @@ class Functions extends EventEmitter {
147
147
  } catch { }
148
148
  }
149
149
 
150
- // --- Synology DSM 7 ---
150
+ // Synology DSM 7
151
151
  const synoCandidates = [
152
152
  "/var/packages/Chromium/target/usr/bin/chromium",
153
153
  "/usr/local/chromium/bin/chromium"
@@ -159,7 +159,7 @@ class Functions extends EventEmitter {
159
159
  } catch { }
160
160
  }
161
161
 
162
- // --- Linux x64 ---
162
+ // Linux x64
163
163
  if (isLinux) {
164
164
  const linuxCandidates = [
165
165
  "/usr/bin/chromium",
@@ -237,6 +237,48 @@ class Functions extends EventEmitter {
237
237
  })
238
238
  );
239
239
  }
240
+
241
+ async normalizeFrostProtection(min, max) {
242
+ // Clamp to allowed ranges
243
+ min = Math.min(Math.max(min, 4), 14);
244
+ max = Math.min(Math.max(max, 6), 16);
245
+
246
+ // Ensure difference of at least 2 degrees
247
+ if (max - min < 2) {
248
+ // Try increasing max if possible
249
+ const newMax = min + 2;
250
+ if (newMax <= 18) {
251
+ max = newMax;
252
+ } else {
253
+ // Otherwise lower min
254
+ const newMin = max - 2;
255
+ min = Math.max(newMin, 4);
256
+ }
257
+ }
258
+
259
+ return { min, max };
260
+ }
261
+
262
+ async normalizeOverheatProtection(min, max) {
263
+ // Clamp to allowed ranges
264
+ min = Math.min(Math.max(min, 31), 38);
265
+ max = Math.min(Math.max(max, 33), 40);
266
+
267
+ // Ensure difference of at least 2 degrees
268
+ if (max - min < 2) {
269
+ // Try increasing max if possible
270
+ const newMax = min + 2;
271
+ if (newMax <= 18) {
272
+ max = newMax;
273
+ } else {
274
+ // Otherwise lower min
275
+ const newMin = max - 2;
276
+ min = Math.max(newMin, 4);
277
+ }
278
+ }
279
+
280
+ return { min, max };
281
+ }
240
282
  }
241
283
 
242
284
  export default Functions
@@ -240,20 +240,22 @@ class MelCloudAta extends EventEmitter {
240
240
  case "melcloudhome":
241
241
  switch (flag) {
242
242
  case 'frostprotection':
243
+ let { frostMin, frostMax } = await this.functions.normalizeFrostProtection(deviceData.FrostProtection.Min, deviceData.FrostProtection.Max);
243
244
  payload = {
244
245
  enabled: deviceData.FrostProtection.Enabled,
245
- min: deviceData.FrostProtection.Min,
246
- max: deviceData.FrostProtection.Max,
246
+ min: frostMin,
247
+ max: frostMax,
247
248
  units: { ATA: [deviceData.DeviceID] }
248
249
  };
249
250
  method = 'POST';
250
251
  path = ApiUrlsHome.PostProtectionFrost;
251
252
  break;
252
253
  case 'overheatprotection':
254
+ let { overMin, overMax } = await this.functions.normalizeOverheatProtection(deviceData.OverheatProtection.Min, deviceData.OverheatProtection.Max);
253
255
  payload = {
254
256
  enabled: deviceData.OverheatProtection.Enabled,
255
- min: deviceData.OverheatProtection.Min,
256
- max: deviceData.OverheatProtection.Max,
257
+ min: overMin,
258
+ max: overMax,
257
259
  units: { ATA: [deviceData.DeviceID] }
258
260
  };
259
261
  method = 'POST';
@@ -228,7 +228,7 @@ class MelCloudHome extends EventEmitter {
228
228
  // Get Chromium path
229
229
  let chromiumPath = await this.functions.ensureChromiumInstalled();
230
230
 
231
- // === Fallback to Puppeteer's bundled Chromium ===
231
+ // Fallback to Puppeteer's bundled Chromium
232
232
  if (!chromiumPath) {
233
233
  try {
234
234
  const puppeteerPath = puppeteer.executablePath();
@@ -245,7 +245,7 @@ class MelCloudHome extends EventEmitter {
245
245
  }
246
246
  }
247
247
 
248
- // === Verify Chromium executable ===
248
+ // Verify Chromium executable
249
249
  try {
250
250
  const { stdout } = await execPromise(`"${chromiumPath}" --version`);
251
251
  if (this.logDebug) this.emit('debug', `Chromium detected: ${stdout.trim()}`);
@@ -277,7 +277,7 @@ class MelCloudHome extends EventEmitter {
277
277
  page.setDefaultTimeout(GLOBAL_TIMEOUT);
278
278
  page.setDefaultNavigationTimeout(GLOBAL_TIMEOUT);
279
279
 
280
- // === CDP session ===
280
+ // CDP session
281
281
  const client = await page.createCDPSession();
282
282
  await client.send('Network.enable')
283
283
  client.on('Network.webSocketCreated', ({ url }) => {
@@ -311,7 +311,7 @@ class MelCloudHome extends EventEmitter {
311
311
  .on('open', () => {
312
312
  this.socketConnected = true;
313
313
  this.connecting = false;
314
- if (this.logDebug) this.emit('debug', `Web Socket Connect Success`);
314
+ if (this.logDebug) this.emit('debug', `Web Socket Connected`);
315
315
 
316
316
  // heartbeat
317
317
  this.heartbeat = setInterval(() => {
@@ -400,7 +400,6 @@ class MelCloudHome extends EventEmitter {
400
400
  `__Secure-monitorandcontrolC2=${c2}`
401
401
  ].join('; ');
402
402
 
403
-
404
403
  const userAgent = await page.evaluate(() => navigator.userAgent);
405
404
  const headers = {
406
405
  'Accept': '*/*',
@@ -424,7 +423,7 @@ class MelCloudHome extends EventEmitter {
424
423
  this.emit('client', this.client);
425
424
 
426
425
  accountInfo.State = true;
427
- accountInfo.Info = `Connect Success ${this.socketConnected ? ', Web Socket Connected' : ''}`;
426
+ accountInfo.Info = `Connect Success${this.socketConnected ? ', Web Socket Connected' : ''}`;
428
427
  await this.functions.saveData(this.accountFile, accountInfo);
429
428
 
430
429
  return accountInfo;