homebridge-melcloud-control 4.4.1-beta.33 → 4.4.1-beta.35
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/homebridge-ui/public/index.html +111 -125
- package/package.json +1 -1
|
@@ -204,19 +204,22 @@
|
|
|
204
204
|
}
|
|
205
205
|
});
|
|
206
206
|
|
|
207
|
-
//
|
|
208
|
-
function
|
|
209
|
-
const
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
for (let i =
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
207
|
+
// Generic remove function
|
|
208
|
+
function removeStaleEntities(configList, serverList, getConfigId, getServerId) {
|
|
209
|
+
const serverIds = new Set(serverList.map(item => String(getServerId(item))));
|
|
210
|
+
const removedEntities = [];
|
|
211
|
+
|
|
212
|
+
for (let i = configList.length - 1; i >= 0; i--) {
|
|
213
|
+
const entity = configList[i];
|
|
214
|
+
const entityId = String(getConfigId(entity));
|
|
215
|
+
|
|
216
|
+
if (!serverIds.has(entityId)) {
|
|
217
|
+
removedEntities.push(entity);
|
|
218
|
+
configList.splice(i, 1);
|
|
217
219
|
}
|
|
218
220
|
}
|
|
219
|
-
|
|
221
|
+
|
|
222
|
+
return removedEntities;
|
|
220
223
|
}
|
|
221
224
|
|
|
222
225
|
function updateInfo(id, text, color) {
|
|
@@ -227,10 +230,11 @@
|
|
|
227
230
|
}
|
|
228
231
|
}
|
|
229
232
|
|
|
233
|
+
// Login & Sync Logic
|
|
230
234
|
document.getElementById('logIn').addEventListener('click', async () => {
|
|
231
235
|
homebridge.showSpinner();
|
|
232
236
|
|
|
233
|
-
document.getElementById(
|
|
237
|
+
document.getElementById('logIn').className = "btn btn-primary";
|
|
234
238
|
updateInfo('info', '', 'white');
|
|
235
239
|
updateInfo('info1', '', 'white');
|
|
236
240
|
updateInfo('info2', '', 'white');
|
|
@@ -238,16 +242,17 @@
|
|
|
238
242
|
try {
|
|
239
243
|
const account = this.account;
|
|
240
244
|
const response = await homebridge.request('/connect', account);
|
|
245
|
+
|
|
241
246
|
if (!response.State) {
|
|
242
247
|
homebridge.hideSpinner();
|
|
243
|
-
updateInfo('info', response.Info);
|
|
248
|
+
updateInfo('info', response.Info, 'red');
|
|
244
249
|
return;
|
|
245
250
|
}
|
|
246
251
|
|
|
247
|
-
//
|
|
252
|
+
// Prepare MELCloud data
|
|
248
253
|
const newInMelCloud = { ata: [], ataPresets: [], ataSchedules: [], atw: [], atwPresets: [], atwSchedules: [], erv: [], ervPresets: [], ervSchedules: [], scenes: [] };
|
|
249
254
|
const devicesInMelCloudByType = { ata: [], atw: [], erv: [] };
|
|
250
|
-
const scenesInMelCloud = response.Scenes ?? []
|
|
255
|
+
const scenesInMelCloud = response.Scenes ?? [];
|
|
251
256
|
|
|
252
257
|
response.Devices.forEach(device => {
|
|
253
258
|
if (device.Type === 0) devicesInMelCloudByType.ata.push(device);
|
|
@@ -259,135 +264,116 @@
|
|
|
259
264
|
account.atwDevices = (account.atwDevices ?? []).filter(d => String(d.id) !== '0');
|
|
260
265
|
account.ervDevices = (account.ervDevices ?? []).filter(d => String(d.id) !== '0');
|
|
261
266
|
|
|
262
|
-
|
|
263
|
-
const
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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
|
-
scenesInConfig.push(sceneObj);
|
|
349
|
-
newScenes.push(sceneObj);
|
|
350
|
-
sceneIds.add(sceneId);
|
|
351
|
-
}
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
// Return filtered devicesInConfig to make sure upstream code uses it
|
|
357
|
-
return devicesInConfig;
|
|
358
|
-
} catch (error) {
|
|
359
|
-
updateInfo('info', `Error while processing device: ${JSON.stringify(error)}`, 'red');
|
|
360
|
-
}
|
|
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);
|
|
271
|
+
|
|
272
|
+
// Remove stale SCENES (global)
|
|
273
|
+
account.scenes = account.scenes ?? [];
|
|
274
|
+
removeStaleEntities(account.scenes, scenesInMelCloud, s => s.id, s => s.Id);
|
|
275
|
+
|
|
276
|
+
// Handle Devices
|
|
277
|
+
const handleDevices = (devicesInMelCloud, devicesInConfig, deviceTypeString, newDevices, newPresets, newSchedules) => {
|
|
278
|
+
const configDevicesMap = new Map(devicesInConfig.map(dev => [String(dev.id), dev]));
|
|
279
|
+
|
|
280
|
+
devicesInMelCloud.forEach(device => {
|
|
281
|
+
const deviceId = String(device.DeviceID);
|
|
282
|
+
let deviceInConfig = configDevicesMap.get(deviceId);
|
|
283
|
+
|
|
284
|
+
// === Create missing device ===
|
|
285
|
+
if (!deviceInConfig) {
|
|
286
|
+
deviceInConfig = {
|
|
287
|
+
id: deviceId,
|
|
288
|
+
type: device.Type,
|
|
289
|
+
deviceTypeString,
|
|
290
|
+
displayType: 0,
|
|
291
|
+
name: device.DeviceName
|
|
292
|
+
};
|
|
293
|
+
devicesInConfig.push(deviceInConfig);
|
|
294
|
+
newDevices.push(deviceInConfig);
|
|
295
|
+
configDevicesMap.set(deviceId, deviceInConfig);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// PRESETS (melcloud)
|
|
299
|
+
if (account.type === 'melcloud') {
|
|
300
|
+
deviceInConfig.presets = deviceInConfig.presets ?? [];
|
|
301
|
+
|
|
302
|
+
const presetsInMelCloud = device.Presets || [];
|
|
303
|
+
removeStaleEntities(deviceInConfig.presets, presetsInMelCloud, p => p.id, p => p.ID);
|
|
304
|
+
|
|
305
|
+
const presetIds = new Set(deviceInConfig.presets.map(p => String(p.id)));
|
|
306
|
+
presetsInMelCloud.forEach((preset, index) => {
|
|
307
|
+
const presetId = String(preset.ID);
|
|
308
|
+
if (!presetIds.has(presetId)) {
|
|
309
|
+
const presetObj = {
|
|
310
|
+
id: presetId,
|
|
311
|
+
displayType: 0,
|
|
312
|
+
name: preset.NumberDescription || `Preset ${index}`,
|
|
313
|
+
namePrefix: false
|
|
314
|
+
};
|
|
315
|
+
deviceInConfig.presets.push(presetObj);
|
|
316
|
+
newPresets.push(presetObj);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// SCHEDULES (melcloudhome)
|
|
322
|
+
if (account.type === 'melcloudhome') {
|
|
323
|
+
deviceInConfig.schedules = deviceInConfig.schedules ?? [];
|
|
324
|
+
|
|
325
|
+
const schedulesInMelCloud = device.Schedule || [];
|
|
326
|
+
removeStaleEntities(deviceInConfig.schedules, schedulesInMelCloud, s => s.id, s => s.Id);
|
|
327
|
+
|
|
328
|
+
const scheduleIds = new Set(deviceInConfig.schedules.map(s => String(s.id)));
|
|
329
|
+
schedulesInMelCloud.forEach((schedule, index) => {
|
|
330
|
+
const scheduleId = String(schedule.Id);
|
|
331
|
+
if (!scheduleIds.has(scheduleId)) {
|
|
332
|
+
const scheduleObj = {
|
|
333
|
+
id: scheduleId,
|
|
334
|
+
displayType: 0,
|
|
335
|
+
name: `Schedule ${index}`,
|
|
336
|
+
namePrefix: false
|
|
337
|
+
};
|
|
338
|
+
deviceInConfig.schedules.push(scheduleObj);
|
|
339
|
+
newSchedules.push(scheduleObj);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
return devicesInConfig;
|
|
361
346
|
};
|
|
362
347
|
|
|
363
|
-
|
|
364
|
-
account.
|
|
365
|
-
account.
|
|
348
|
+
// 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);
|
|
366
352
|
|
|
353
|
+
// Summary
|
|
367
354
|
const newDevicesCount = newInMelCloud.ata.length + newInMelCloud.atw.length + newInMelCloud.erv.length;
|
|
368
355
|
const newPresetsCount = newInMelCloud.ataPresets.length + newInMelCloud.atwPresets.length + newInMelCloud.ervPresets.length;
|
|
369
356
|
const newSchedulesCount = newInMelCloud.ataSchedules.length + newInMelCloud.atwSchedules.length + newInMelCloud.ervSchedules.length;
|
|
370
|
-
const newScenesCount = newInMelCloud.scenes.length;
|
|
371
357
|
const removedDevicesCount = removedAta.length + removedAtw.length + removedErv.length;
|
|
372
358
|
|
|
373
|
-
if (!newDevicesCount && !newPresetsCount && !newSchedulesCount && !
|
|
359
|
+
if (!newDevicesCount && !newPresetsCount && !newSchedulesCount && !removedDevicesCount) {
|
|
374
360
|
updateInfo('info', 'No changes detected.', 'white');
|
|
375
361
|
} else {
|
|
376
362
|
if (newDevicesCount)
|
|
377
|
-
updateInfo('info', `Found new devices: ${
|
|
363
|
+
updateInfo('info', `Found new devices: ${newDevicesCount}`, 'green');
|
|
378
364
|
if (newPresetsCount)
|
|
379
|
-
updateInfo('info1', `Found new presets: ${
|
|
380
|
-
if (
|
|
381
|
-
updateInfo('info1', `Found new
|
|
365
|
+
updateInfo('info1', `Found new presets: ${newPresetsCount}`, 'green');
|
|
366
|
+
if (newSchedulesCount)
|
|
367
|
+
updateInfo('info1', `Found new schedules: ${newSchedulesCount}`, 'green');
|
|
382
368
|
if (removedDevicesCount)
|
|
383
|
-
updateInfo('info2', `Removed devices: ${
|
|
369
|
+
updateInfo('info2', `Removed devices: ${removedDevicesCount}`, 'orange');
|
|
384
370
|
}
|
|
385
371
|
|
|
386
372
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
387
373
|
await homebridge.savePluginConfig(pluginConfig);
|
|
374
|
+
|
|
388
375
|
} catch (error) {
|
|
389
376
|
updateInfo('info', `Prepare config error ${JSON.stringify(error)}`, 'red');
|
|
390
|
-
document.getElementById('logIn').className = "btn btn-secondary";
|
|
391
377
|
} finally {
|
|
392
378
|
document.getElementById('logIn').className = "btn btn-secondary";
|
|
393
379
|
homebridge.hideSpinner();
|
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.
|
|
4
|
+
"version": "4.4.1-beta.35",
|
|
5
5
|
"description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "grzegorz914",
|