homebridge-melcloud-control 4.4.1-beta.35 → 4.4.1-beta.37

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.
@@ -205,17 +205,17 @@
205
205
  });
206
206
 
207
207
  // Generic remove function
208
- function removeStaleEntities(configList, serverList, getConfigId, getServerId) {
209
- const serverIds = new Set(serverList.map(item => String(getServerId(item))));
208
+ function removeStaleEntities(configEntities, MelcloudEntities, getConfigId, getMelcloudId) {
209
+ const serverIds = new Set(MelcloudEntities.map(item => String(getMelcloudId(item))));
210
210
  const removedEntities = [];
211
211
 
212
- for (let i = configList.length - 1; i >= 0; i--) {
213
- const entity = configList[i];
212
+ for (let i = configEntities.length - 1; i >= 0; i--) {
213
+ const entity = configEntities[i];
214
214
  const entityId = String(getConfigId(entity));
215
215
 
216
216
  if (!serverIds.has(entityId)) {
217
217
  removedEntities.push(entity);
218
- configList.splice(i, 1);
218
+ configEntities.splice(i, 1);
219
219
  }
220
220
  }
221
221
 
@@ -233,7 +233,6 @@
233
233
  // Login & Sync Logic
234
234
  document.getElementById('logIn').addEventListener('click', async () => {
235
235
  homebridge.showSpinner();
236
-
237
236
  document.getElementById('logIn').className = "btn btn-primary";
238
237
  updateInfo('info', '', 'white');
239
238
  updateInfo('info1', '', 'white');
@@ -250,7 +249,7 @@
250
249
  }
251
250
 
252
251
  // Prepare MELCloud data
253
- const newInMelCloud = { ata: [], ataPresets: [], ataSchedules: [], atw: [], atwPresets: [], atwSchedules: [], erv: [], ervPresets: [], ervSchedules: [], scenes: [] };
252
+ const newInMelCloud = { ata: [], ataPresets: [], ataSchedules: [], ataScenes: [], atw: [], atwPresets: [], atwSchedules: [], atwScenes: [], erv: [], ervPresets: [], ervSchedules: [], ervScenes: [], scenes: [] };
254
253
  const devicesInMelCloudByType = { ata: [], atw: [], erv: [] };
255
254
  const scenesInMelCloud = response.Scenes ?? [];
256
255
 
@@ -264,44 +263,38 @@
264
263
  account.atwDevices = (account.atwDevices ?? []).filter(d => String(d.id) !== '0');
265
264
  account.ervDevices = (account.ervDevices ?? []).filter(d => String(d.id) !== '0');
266
265
 
267
- // Remove stale DEVICES
268
- const removedAta = removeStaleEntities(account.ataDevices, devicesInMelCloudByType.ata, d => d.id, d => d.DeviceID);
269
- const removedAtw = removeStaleEntities(account.atwDevices, devicesInMelCloudByType.atw, d => d.id, d => d.DeviceID);
270
- const removedErv = removeStaleEntities(account.ervDevices, devicesInMelCloudByType.erv, d => d.id, d => d.DeviceID);
266
+ const removedFromConfigAta = removeStaleEntities(account.ataDevices, devicesInMelCloudByType.ata, d => d.id, d => d.DeviceID);
267
+ const removedFromConfigAtw = removeStaleEntities(account.atwDevices, devicesInMelCloudByType.atw, d => d.id, d => d.DeviceID);
268
+ const removedFromConfigErv = removeStaleEntities(account.ervDevices, devicesInMelCloudByType.erv, d => d.id, d => d.DeviceID);
269
+ const removedFromConfig = { ataPresets: [], atwPresets: [], ervPresets: [], ataSchedules: [], atwSchedules: [], ervSchedules: [], scenes: [] };
271
270
 
272
- // Remove stale SCENES (global)
273
- account.scenes = account.scenes ?? [];
274
- removeStaleEntities(account.scenes, scenesInMelCloud, s => s.id, s => s.Id);
275
271
 
276
272
  // Handle Devices
277
- const handleDevices = (devicesInMelCloud, devicesInConfig, deviceTypeString, newDevices, newPresets, newSchedules) => {
273
+ const handleDevices = (devicesInMelCloud, devicesInConfig, deviceTypeString, newDevices, newPresets, newSchedules, newScenes) => {
278
274
  const configDevicesMap = new Map(devicesInConfig.map(dev => [String(dev.id), dev]));
279
275
 
280
276
  devicesInMelCloud.forEach(device => {
281
- const deviceId = String(device.DeviceID);
277
+ const deviceId = String(device.DeviceID); // Make sure this matches MelCloud data
282
278
  let deviceInConfig = configDevicesMap.get(deviceId);
283
279
 
284
- // === Create missing device ===
285
280
  if (!deviceInConfig) {
286
281
  deviceInConfig = {
287
282
  id: deviceId,
288
283
  type: device.Type,
289
284
  deviceTypeString,
290
285
  displayType: 0,
291
- name: device.DeviceName
286
+ name: device.DeviceName,
292
287
  };
293
288
  devicesInConfig.push(deviceInConfig);
294
289
  newDevices.push(deviceInConfig);
295
290
  configDevicesMap.set(deviceId, deviceInConfig);
296
291
  }
297
292
 
298
- // PRESETS (melcloud)
293
+ //ONLY MELCLOUD - PRESETS
299
294
  if (account.type === 'melcloud') {
300
295
  deviceInConfig.presets = deviceInConfig.presets ?? [];
301
-
302
296
  const presetsInMelCloud = device.Presets || [];
303
- removeStaleEntities(deviceInConfig.presets, presetsInMelCloud, p => p.id, p => p.ID);
304
-
297
+ removedFromConfig.ataPresets.push(...removeStaleEntities(deviceInConfig.presets, presetsInMelCloud, p => p.id, p => p.ID));
305
298
  const presetIds = new Set(deviceInConfig.presets.map(p => String(p.id)));
306
299
  presetsInMelCloud.forEach((preset, index) => {
307
300
  const presetId = String(preset.ID);
@@ -318,13 +311,12 @@
318
311
  });
319
312
  }
320
313
 
321
- // SCHEDULES (melcloudhome)
314
+ //ONLY MELCLOUD HOME - SCHEDULES & SCENES
322
315
  if (account.type === 'melcloudhome') {
316
+ // SCHEDULES
323
317
  deviceInConfig.schedules = deviceInConfig.schedules ?? [];
324
-
325
318
  const schedulesInMelCloud = device.Schedule || [];
326
- removeStaleEntities(deviceInConfig.schedules, schedulesInMelCloud, s => s.id, s => s.Id);
327
-
319
+ removedFromConfig.ataSchedules.push(...removeStaleEntities(deviceInConfig.schedules, schedulesInMelCloud, s => s.id, s => s.Id));
328
320
  const scheduleIds = new Set(deviceInConfig.schedules.map(s => String(s.id)));
329
321
  schedulesInMelCloud.forEach((schedule, index) => {
330
322
  const scheduleId = String(schedule.Id);
@@ -339,6 +331,24 @@
339
331
  newSchedules.push(scheduleObj);
340
332
  }
341
333
  });
334
+
335
+ // SCENES
336
+ deviceInConfig.scenes = deviceInConfig.scenes ?? [];
337
+ removedFromConfig.scenes.push(...removeStaleEntities(deviceInConfig.scenes, scenesInMelCloud, s => s.id, s => s.Id));
338
+ const sceneIds = new Set(deviceInConfig.scenes.map(s => String(s.id)));
339
+ scenesInMelCloud.forEach((scene, index) => {
340
+ const sceneId = String(scene.Id);
341
+ if (!sceneIds.has(sceneId)) {
342
+ const sceneObj = {
343
+ id: sceneId,
344
+ displayType: 0,
345
+ name: scene.Name || `Scene ${index}`,
346
+ namePrefix: false
347
+ };
348
+ deviceInConfig.scenes.push(sceneObj);
349
+ newScenes.push(sceneObj);
350
+ }
351
+ });
342
352
  }
343
353
  });
344
354
 
@@ -346,27 +356,35 @@
346
356
  };
347
357
 
348
358
  // Execute device handlers
349
- account.ataDevices = handleDevices(devicesInMelCloudByType.ata, account.ataDevices, "Air Conditioner", newInMelCloud.ata, newInMelCloud.ataPresets, newInMelCloud.ataSchedules);
350
- account.atwDevices = handleDevices(devicesInMelCloudByType.atw, account.atwDevices, "Heat Pump", newInMelCloud.atw, newInMelCloud.atwPresets, newInMelCloud.atwSchedules);
351
- account.ervDevices = handleDevices(devicesInMelCloudByType.erv, account.ervDevices, "Energy Recovery Ventilation", newInMelCloud.erv, newInMelCloud.ervPresets, newInMelCloud.ervSchedules);
359
+ account.ataDevices = handleDevices(devicesInMelCloudByType.ata, account.ataDevices, "Air Conditioner", newInMelCloud.ata, newInMelCloud.ataPresets, newInMelCloud.ataSchedules, newInMelCloud.ataScenes);
360
+ account.atwDevices = handleDevices(devicesInMelCloudByType.atw, account.atwDevices, "Heat Pump", newInMelCloud.atw, newInMelCloud.atwPresets, newInMelCloud.atwSchedules, newInMelCloud.atwScenes);
361
+ account.ervDevices = handleDevices(devicesInMelCloudByType.erv, account.ervDevices, "Energy Recovery Ventilation", newInMelCloud.erv, newInMelCloud.ervPresets, newInMelCloud.ervSchedules, newInMelCloud.ervScenes);
352
362
 
353
363
  // Summary
354
364
  const newDevicesCount = newInMelCloud.ata.length + newInMelCloud.atw.length + newInMelCloud.erv.length;
355
365
  const newPresetsCount = newInMelCloud.ataPresets.length + newInMelCloud.atwPresets.length + newInMelCloud.ervPresets.length;
356
366
  const newSchedulesCount = newInMelCloud.ataSchedules.length + newInMelCloud.atwSchedules.length + newInMelCloud.ervSchedules.length;
357
- const removedDevicesCount = removedAta.length + removedAtw.length + removedErv.length;
367
+ const newScenesCount = newInMelCloud.scenes.length;
368
+ const removedDevicesCount = removedFromConfigAta.length + removedFromConfigAtw.length + removedFromConfigErv.length;
369
+ const removedPresetsCount = removedFromConfig.ataPresets.length + removedFromConfig.atwPresets.length + removedFromConfig.ervPresets.length;
370
+ const removedSchedulesCount = removedFromConfig.ataSchedules.length + removedFromConfig.atwSchedules.length + removedFromConfig.ervSchedules.length;
371
+ const removedScenesCount = removedFromConfig.scenes.length
358
372
 
359
- if (!newDevicesCount && !newPresetsCount && !newSchedulesCount && !removedDevicesCount) {
373
+ if (!newDevicesCount && !newPresetsCount && !newSchedulesCount && !newScenesCount && !removedDevicesCount && !removedPresetsCount && !removedSchedulesCount && !removedScenesCount) {
360
374
  updateInfo('info', 'No changes detected.', 'white');
361
375
  } else {
362
376
  if (newDevicesCount)
363
- updateInfo('info', `Found new devices: ${newDevicesCount}`, 'green');
377
+ updateInfo('info', `Found new devices: ${newInMelCloud.ata.length ? `ATA: ${newInMelCloud.ata.length},` : ''} ${newInMelCloud.atw.length ? `ATW: ${newInMelCloud.atw.length},` : ''} ${newInMelCloud.erv.length ? `ERV: ${newInMelCloud.erv.length},` : ''}.`, 'green');
364
378
  if (newPresetsCount)
365
- updateInfo('info1', `Found new presets: ${newPresetsCount}`, 'green');
366
- if (newSchedulesCount)
367
- updateInfo('info1', `Found new schedules: ${newSchedulesCount}`, 'green');
379
+ updateInfo('info1', `Found new presets: ${newInMelCloud.ataPresets.length ? `ATA: ${newInMelCloud.ataPresets.length},` : ''} ${newInMelCloud.atwPresets.length ? `ATW: ${newInMelCloud.atwPresets.length},` : ''} ${newInMelCloud.ervPresets.length ? `ERV: ${newInMelCloud.ervPresets.length}` : ''}.`, 'green');
380
+ if (newScenesCount || newSchedulesCount)
381
+ updateInfo('info1', `Found new ${newSchedulesCount ? `schedules:` : ''} ${newInMelCloud.ataSchedules.length ? `ATA: ${newInMelCloud.ataSchedules.length},` : ''} ${newInMelCloud.atwSchedules.length ? `ATW: ${newInMelCloud.atwSchedules.length},` : ''} ${newInMelCloud.ervSchedules.length ? `ERV: ${newInMelCloud.ervSchedules.length},` : ''} ${newScenesCount ? `scenes: ${newScenesCount}` : ''}.`, 'green');
368
382
  if (removedDevicesCount)
369
- updateInfo('info2', `Removed devices: ${removedDevicesCount}`, 'orange');
383
+ updateInfo('info', `Removed devices: ${removedFromConfigAta.length ? `ATA: ${removedFromConfigAta.length},` : ''} ${removedFromConfigAtw.length ? `ATW: ${removedFromConfigAtw.length},` : ''} ${removedFromConfigErv.length ? `ERV: ${removedFromConfigErv.length}` : ''}.`, 'orange');
384
+ if (removedPresetsCount)
385
+ updateInfo('info1', `Rempved presets: ${removedFromConfig.ataPresets.length ? `ATA: ${removedFromConfig.ataPresets.length},` : ''} ${removedFromConfig.atwPresets.length ? `ATW: ${removedFromConfig.atwPresets.length},` : ''} ${removedFromConfig.ervPresets.length ? `ERV: ${removedFromConfig.ervPresets.length}` : ''}.`, 'orange');
386
+ if (removedSchedulesCount || removedScenesCount)
387
+ updateInfo('info1', `Rempved ${removedScenesCount ? `schedules:` : ''} ${removedFromConfig.ataSchedules.length ? `ATA: ${removedFromConfig.ataSchedules.length},` : ''} ${removedFromConfig.atwSchedules.length ? `ATW: ${removedFromConfig.atwSchedules.length},` : ''} ${removedFromConfig.ervSchedules.length ? `ERV: ${removedFromConfig.ervSchedules.length},` : ''} ${removedScenesCount ? `scenes: ${removedScenesCount}` : ''}.`, 'orange');
370
388
  }
371
389
 
372
390
  await homebridge.updatePluginConfig(pluginConfig);
@@ -380,5 +398,6 @@
380
398
  }
381
399
  });
382
400
 
401
+
383
402
  })();
384
403
  </script>
package/index.js CHANGED
@@ -137,12 +137,24 @@ class MelCloudPlatform {
137
137
  }
138
138
 
139
139
  //chack device from config exist on melcloud
140
- const deviceExistInMelCloud = melcloudDevicesList.Devices.some(dev => dev.DeviceID === device.id);
141
- if (!deviceExistInMelCloud) {
140
+ const deviceInMelCloud = melcloudDevicesList.Devices.find(d => d.DeviceID === device.id);
141
+ if (!deviceInMelCloud) {
142
142
  if (logLevel.warn) log.warn(`${name}, ${deviceTypeString}, ${deviceName}, not exist on server, please login to MELCLoud from plugin UI to fix this issue.`);
143
143
  continue;
144
144
  }
145
145
 
146
+ //presets
147
+ const presetIds = (deviceInMelCloud.Presets ?? []).map(p => String(p.ID));
148
+ const presets = account.type === 'melcloud' ? (device.presets || []).filter(p => (p.displayType ?? 0) > 0 && p.id !== '0' && presetIds.includes(p.id)) : [];
149
+
150
+ //schedules
151
+ const schedulesIds = (deviceInMelCloud.Schedule ?? []).map(s => String(s.Id));
152
+ const schedules = account.type === 'melcloudhome' ? (device.schedules || []).filter(s => (s.displayType ?? 0) > 0 && s.id !== '0' && schedulesIds.includes(s.id)) : [];
153
+
154
+ //scenes
155
+ const scenesIds = (melcloudDevicesList.Scenes ?? []).map(s => String(s.Id));
156
+ const scenes = account.type === 'melcloudhome' ? (device.scenes || []).filter(s => (s.displayType ?? 0) > 0 && s.id !== '0' && scenesIds.includes(s.id)) : [];
157
+
146
158
  // set rest ful port
147
159
  account.restFul.port = (device.id).slice(-4).replace(/^0/, '9');
148
160
 
@@ -168,15 +180,15 @@ class MelCloudPlatform {
168
180
  let configuredDevice;
169
181
  switch (deviceType) {
170
182
  case 0: //ATA
171
- configuredDevice = new DeviceAta(api, account, device, defaultTempsFile, accountInfo, accountFile, melcloud, melcloudDevicesList);
183
+ configuredDevice = new DeviceAta(api, account, device, presets, schedules, scenes, defaultTempsFile, accountInfo, accountFile, melcloud, melcloudDevicesList);
172
184
  break;
173
185
  case 1: //ATW
174
- configuredDevice = new DeviceAtw(api, account, device, defaultTempsFile, accountInfo, accountFile, melcloud, melcloudDevicesList);
186
+ configuredDevice = new DeviceAtw(api, account, device, presets, schedules, scenes, defaultTempsFile, accountInfo, accountFile, melcloud, melcloudDevicesList);
175
187
  break;
176
188
  case 2:
177
189
  break;
178
190
  case 3: //ERV
179
- configuredDevice = new DeviceErv(api, account, device, defaultTempsFile, accountInfo, accountFile, melcloud, melcloudDevicesList);
191
+ configuredDevice = new DeviceErv(api, account, device, presets, schedules, scenes, defaultTempsFile, accountInfo, accountFile, melcloud, melcloudDevicesList);
180
192
  break;
181
193
  default:
182
194
  if (logLevel.warn) log.warn(`${name}, ${deviceTypeString}, ${deviceName}, unknown device: ${deviceType}.`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "MELCloud Control",
3
3
  "name": "homebridge-melcloud-control",
4
- "version": "4.4.1-beta.35",
4
+ "version": "4.4.1-beta.37",
5
5
  "description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
package/src/deviceata.js CHANGED
@@ -7,7 +7,7 @@ import { TemperatureDisplayUnits, AirConditioner } from './constants.js';
7
7
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
8
8
 
9
9
  class DeviceAta extends EventEmitter {
10
- constructor(api, account, device, defaultTempsFile, accountInfo, accountFile, melcloud, melcloudDevicesList) {
10
+ constructor(api, account, device, presets, schedules, scenes, defaultTempsFile, accountInfo, accountFile, melcloud, melcloudDevicesList) {
11
11
  super();
12
12
 
13
13
  Accessory = api.platformAccessory;
@@ -44,9 +44,9 @@ class DeviceAta extends EventEmitter {
44
44
  this.frostProtectionSupport = device.frostProtectionSupport || false;
45
45
  this.overheatProtectionSupport = device.overheatProtectionSupport || false;
46
46
  this.holidayModeSupport = device.holidayModeSupport || false;
47
- this.presets = this.accountType === 'melcloud' ? (device.presets || []).filter(preset => (preset.displayType ?? 0) > 0 && preset.id !== '0') : [];
48
- this.schedules = this.accountType === 'melcloudhome' ? (device.schedules || []).filter(schedule => (schedule.displayType ?? 0) > 0 && schedule.id !== '0') : [];
49
- this.scenes = this.accountType === 'melcloudhome' ? (device.scenes || []).filter(scene => (scene.displayType ?? 0) > 0 && scene.id !== '0') : [];
47
+ this.presets = presets;
48
+ this.schedules = schedules;
49
+ this.scenes = scenes;
50
50
  this.buttons = (device.buttonsSensors || []).filter(button => (button.displayType ?? 0) > 0);
51
51
 
52
52
  //files
package/src/deviceatw.js CHANGED
@@ -7,7 +7,7 @@ import { TemperatureDisplayUnits, HeatPump } from './constants.js';
7
7
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
8
8
 
9
9
  class DeviceAtw extends EventEmitter {
10
- constructor(api, account, device, defaultTempsFile, accountInfo, accountFile, melcloud, melcloudDevicesList) {
10
+ constructor(api, account, device, presets, schedules, scenes, defaultTempsFile, accountInfo, accountFile, melcloud, melcloudDevicesList) {
11
11
  super();
12
12
 
13
13
  Accessory = api.platformAccessory;
@@ -48,9 +48,9 @@ class DeviceAtw extends EventEmitter {
48
48
  this.errorSensor = device.errorSensor || false;
49
49
  this.frostProtectionSupport = device.frostProtectionSupport || false;
50
50
  this.holidayModeSupport = device.holidayModeSupport || false;
51
- this.presets = this.accountType === 'melcloud' ? (device.presets || []).filter(preset => (preset.displayType ?? 0) > 0 && preset.id !== '0') : [];
52
- this.schedules = this.accountType === 'melcloudhome' ? (device.schedules || []).filter(schedule => (schedule.displayType ?? 0) > 0 && schedule.id !== '0') : [];
53
- this.scenes = this.accountType === 'melcloudhome' ? (device.scenes || []).filter(scene => (scene.displayType ?? 0) > 0 && scene.id !== '0') : [];
51
+ this.presets = presets;
52
+ this.schedules = schedules;
53
+ this.scenes = scenes;
54
54
  this.buttons = (device.buttonsSensors || []).filter(button => (button.displayType ?? 0) > 0);
55
55
 
56
56
  //files
package/src/deviceerv.js CHANGED
@@ -7,7 +7,7 @@ import { TemperatureDisplayUnits, Ventilation } from './constants.js';
7
7
  let Accessory, Characteristic, Service, Categories, AccessoryUUID;
8
8
 
9
9
  class DeviceErv extends EventEmitter {
10
- constructor(api, account, device, defaultTempsFile, accountInfo, accountFile, melcloud, melcloudDevicesList) {
10
+ constructor(api, account, device, presets, schedules, scenes, defaultTempsFile, accountInfo, accountFile, melcloud, melcloudDevicesList) {
11
11
  super();
12
12
 
13
13
  Accessory = api.platformAccessory;
@@ -40,9 +40,9 @@ class DeviceErv extends EventEmitter {
40
40
  this.connectSensor = device.connectSensor || false;
41
41
  this.errorSensor = device.errorSensor || false;
42
42
  this.holidayModeSupport = device.holidayModeSupport || false;
43
- this.presets = this.accountType === 'melcloud' ? (device.presets || []).filter(preset => (preset.displayType ?? 0) > 0 && preset.id !== '0') : [];
44
- this.schedules = this.accountType === 'melcloudhome' ? (device.schedules || []).filter(schedule => (schedule.displayType ?? 0) > 0 && schedule.id !== '0') : [];
45
- this.scenes = this.accountType === 'melcloudhome' ? (device.scenes || []).filter(scene => (scene.displayType ?? 0) > 0 && scene.id !== '0') : [];
43
+ this.presets = presets;
44
+ this.schedules = schedules;
45
+ this.scenes = scenes;
46
46
  this.buttons = (device.buttonsSensors || []).filter(button => (button.displayType ?? 0) > 0);
47
47
 
48
48
  //files