homebridge-melcloud-control 4.1.2-beta.79 → 4.1.2-beta.80

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.
@@ -159,8 +159,6 @@
159
159
  formElements.language.value = account.language || '0';
160
160
  formElements.accountType.value = account.type || 'disabled';
161
161
  formElements.logIn.disabled = !(account.name && account.user && account.passwd && account.language && account.type);
162
-
163
- await homebridge.updatePluginConfig(pluginConfig);
164
162
  });
165
163
  });
166
164
 
@@ -208,15 +206,6 @@
208
206
  }
209
207
  });
210
208
 
211
- // Update info
212
- function updateInfo(id, text, color) {
213
- const el = document.getElementById(id);
214
- if (el) {
215
- el.innerText = text;
216
- el.style.color = color;
217
- }
218
- }
219
-
220
209
  // Device Handling & Login Logic
221
210
  function removeStaleDevices(configDevices, melcloudDevices) {
222
211
  const melcloudIds = melcloudDevices.map(d => d.DeviceID);
@@ -224,7 +213,7 @@
224
213
 
225
214
  for (let i = configDevices.length - 1; i >= 0; i--) {
226
215
  const device = configDevices[i];
227
- if (!melcloudIds.includes(device.id)) {
216
+ if (device.id !== "0" && !melcloudIds.includes(device.id)) {
228
217
  removedDevices.push(device);
229
218
  configDevices.splice(i, 1);
230
219
  }
@@ -232,55 +221,110 @@
232
221
  return removedDevices;
233
222
  }
234
223
 
235
- document.getElementById('logIn').addEventListener('click', async () => {
236
- const toggleLoginButton = (loading) => {
237
- const btn = document.getElementById('logIn');
238
- btn.className = loading ? "btn btn-primary" : "btn btn-secondary";
239
- loading ? homebridge.showSpinner() : homebridge.hideSpinner();
240
- };
224
+ function updateInfo(id, text, color) {
225
+ const el = document.getElementById(id);
226
+ if (el) {
227
+ el.innerText = text;
228
+ el.style.color = color;
229
+ }
230
+ }
241
231
 
242
- toggleLoginButton(true);
243
- updateInfo('info', ''); updateInfo('info1', ''); updateInfo('info2', '');
232
+ document.getElementById('logIn').addEventListener('click', async () => {
233
+ document.getElementById(`logIn`).className = "btn btn-primary";
234
+ updateInfo('info', '', 'white');
235
+ updateInfo('info1', '', 'white');
236
+ updateInfo('info2', '', 'white');
237
+ homebridge.showSpinner();
244
238
 
245
239
  try {
246
- const account = structuredClone(this.account);
240
+ const account = this.account;
247
241
  const response = await homebridge.request('/connect', account);
248
-
249
- if (!response?.State) {
250
- updateInfo('info', response?.Info || 'Login failed.', 'red');
242
+ if (!response.State) {
243
+ homebridge.hideSpinner();
244
+ updateInfo('info', response.Info);
251
245
  return;
252
246
  }
253
247
 
254
- // Group devices
255
- const DEVICE_TYPES = { ATA: 0, ATW: 1, ERV: 3 };
256
- const melcloudDevices = { ata: [], atw: [], erv: [] };
248
+ // Initialize devices arrays
257
249
  const newDevices = { ata: [], ataPresets: [], atw: [], atwPresets: [], erv: [], ervPresets: [] };
250
+ const devicesByType = { ata: [], atw: [], erv: [] };
258
251
 
259
- (response.Devices || []).forEach(d => {
260
- switch (d.Type) {
261
- case DEVICE_TYPES.ATA: melcloudDevices.ata.push(d); break;
262
- case DEVICE_TYPES.ATW: melcloudDevices.atw.push(d); break;
263
- case DEVICE_TYPES.ERV: melcloudDevices.erv.push(d); break;
264
- }
252
+ response.Devices.forEach(d => {
253
+ if (d.Type === 0) devicesByType.ata.push(d);
254
+ if (d.Type === 1) devicesByType.atw.push(d);
255
+ if (d.Type === 3) devicesByType.erv.push(d);
265
256
  });
266
257
 
267
- // Filter invalid devices
268
258
  account.ataDevices = (account.ataDevices || []).filter(d => String(d.id) !== '0');
269
259
  account.atwDevices = (account.atwDevices || []).filter(d => String(d.id) !== '0');
270
260
  account.ervDevices = (account.ervDevices || []).filter(d => String(d.id) !== '0');
271
261
 
272
- // Remove stale devices
273
- const removedAta = removeStaleDevices(account.ataDevices, melcloudDevices.ata);
274
- const removedAtw = removeStaleDevices(account.atwDevices, melcloudDevices.atw);
275
- const removedErv = removeStaleDevices(account.ervDevices, melcloudDevices.erv);
276
- await homebridge.updatePluginConfig(pluginConfig);
262
+ const removedAta = removeStaleDevices(account.ataDevices, devicesByType.ata);
263
+ const removedAtw = removeStaleDevices(account.atwDevices, devicesByType.atw);
264
+ const removedErv = removeStaleDevices(account.ervDevices, devicesByType.erv);
265
+
266
+ const handleDevices = (devicesInMelCloud, devicesInConfig, typeString, newArr, newPresets) => {
267
+ try {
268
+ const configDevicesMap = new Map(devicesInConfig.map(dev => [dev.id, dev]));
269
+ const isMelcloud = account.type === 'melcloud';
270
+
271
+ const idKey = isMelcloud ? 'ID' : 'Id';
272
+ const typeKey = isMelcloud ? 'Presets' : 'Schedule';
273
+ const typeKey1 = isMelcloud ? 'presets' : 'schedules';
274
+
275
+ devicesInMelCloud.forEach(device => {
276
+ const deviceId = String(device.DeviceID);
277
+ let deviceInConfig = configDevicesMap.get(deviceId);
278
+
279
+ // === Create device if missing ===
280
+ if (!deviceInConfig) {
281
+ deviceInConfig = {
282
+ id: device.DeviceID,
283
+ type: device.Type,
284
+ typeString,
285
+ displayType: 0,
286
+ name: device.DeviceName,
287
+ presets: [],
288
+ schedules: [],
289
+ buttonsSensors: []
290
+ };
291
+ devicesInConfig.push(deviceInConfig);
292
+ newArr.push(deviceInConfig);
293
+ configDevicesMap.set(deviceId, deviceInConfig);
294
+ }
295
+
296
+ // === Process presets/schedules ===
297
+ const presets = device[typeKey] || [];
298
+ const presetsInConfig = (deviceInConfig[typeKey1] || []).filter(p => String(p.id) !== '0');
299
+ const presetIds = new Set(presetsInConfig.map(p => String(p.id)));
300
+
301
+ presets.forEach((preset, index) => {
302
+ const presetId = String(preset[idKey]);
303
+ if (!presetIds.has(presetId)) {
304
+ const presetObj = {
305
+ id: presetId,
306
+ displayType: 0,
307
+ name: preset.NumberDescription || `Schedule ${index}`,
308
+ namePrefix: false
309
+ };
310
+ presetsInConfig.push(presetObj);
311
+ newPresets.push(presetObj);
312
+ presetIds.add(presetId);
313
+ }
314
+ });
315
+ });
316
+
317
+ // Return filtered devicesInConfig to make sure upstream code uses it
318
+ return devicesInConfig;
319
+ } catch (error) {
320
+ updateInfo('info', `Error while processing device: ${JSON.stringify(error)}`, 'red');
321
+ }
322
+ };
277
323
 
278
- // Sync devices
279
- account.ataDevices = handleDevices(account, melcloudDevices.ata, account.ataDevices, "Air Conditioner", newDevices.ata, newDevices.ataPresets);
280
- account.atwDevices = handleDevices(account, melcloudDevices.atw, account.atwDevices, "Heat Pump", newDevices.atw, newDevices.atwPresets);
281
- account.ervDevices = handleDevices(account, melcloudDevices.erv, account.ervDevices, "Energy Recovery Ventilation", newDevices.erv, newDevices.ervPresets);
324
+ account.ataDevices = handleDevices(devicesByType.ata, account.ataDevices, "Air Conditioner", newDevices.ata, newDevices.ataPresets);
325
+ account.atwDevices = handleDevices(devicesByType.atw, account.atwDevices, "Heat Pump", newDevices.atw, newDevices.atwPresets);
326
+ account.ervDevices = handleDevices(devicesByType.erv, account.ervDevices, "Energy Recovery Ventilation", newDevices.erv, newDevices.ervPresets);
282
327
 
283
- // Summaries
284
328
  const newDevicesCount = newDevices.ata.length + newDevices.atw.length + newDevices.erv.length;
285
329
  const newPresetsCount = newDevices.ataPresets.length + newDevices.atwPresets.length + newDevices.ervPresets.length;
286
330
  const removedDevicesCount = removedAta.length + removedAtw.length + removedErv.length;
@@ -288,21 +332,25 @@
288
332
  if (!newDevicesCount && !newPresetsCount && !removedDevicesCount) {
289
333
  updateInfo('info', 'No changes detected.', 'white');
290
334
  } else {
291
- if (newDevicesCount) updateInfo('info', `New devices — ATA: ${newDevices.ata.length}, ATW: ${newDevices.atw.length}, ERV: ${newDevices.erv.length}`, 'green');
292
- if (newPresetsCount) updateInfo('info1', `New ${account.type === 'melcloud' ? 'presets' : 'schedules'} — ATA: ${newDevices.ataPresets.length}, ATW: ${newDevices.atwPresets.length}, ERV: ${newDevices.ervPresets.length}`, 'green');
293
- if (removedDevicesCount) updateInfo('info2', `Removed devices — ATA: ${removedAta.length}, ATW: ${removedAtw.length}, ERV: ${removedErv.length}`, 'orange');
335
+ if (newDevicesCount)
336
+ updateInfo('info', `Found new devices: ATA: ${newDevices.ata.length}, ATW: ${newDevices.atw.length}, ERV: ${newDevices.erv.length}.`, 'green');
337
+ if (newPresetsCount)
338
+ updateInfo('info1', `Found new ${account.type === 'melcloud' ? 'presets' : 'schedules'}: ATA: ${newDevices.ataPresets.length}, ATW: ${newDevices.atwPresets.length}, ERV: ${newDevices.ervPresets.length}.`, 'green');
339
+ if (removedDevicesCount)
340
+ updateInfo('info2', `Removed devices: ATA: ${removedAta.length}, ATW: ${removedAtw.length}, ERV: ${removedErv.length}.`, 'orange');
294
341
  }
295
342
 
296
343
  await homebridge.updatePluginConfig(pluginConfig);
297
344
  await homebridge.savePluginConfig(pluginConfig);
298
345
  } catch (error) {
299
- updateInfo('info', `Error connecting to MelCloud: ${error.message}`, 'red');
346
+ updateInfo('info', `Connect error ${JSON.stringify(error)}`, 'red');
347
+ document.getElementById('logIn').className = "btn btn-secondary";
300
348
  } finally {
301
- toggleLoginButton(false);
349
+ document.getElementById('logIn').className = "btn btn-secondary";
350
+ homebridge.hideSpinner();
302
351
  }
303
352
  });
304
353
 
305
-
306
354
  })();
307
355
  </script>
308
356
  </body>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "MELCloud Control",
3
3
  "name": "homebridge-melcloud-control",
4
- "version": "4.1.2-beta.79",
4
+ "version": "4.1.2-beta.80",
5
5
  "description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",