homebridge-melcloud-control 3.9.0-beta.17 → 3.9.0-beta.18
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 +88 -179
- package/package.json +1 -1
|
@@ -94,60 +94,56 @@
|
|
|
94
94
|
homebridge.showSchemaForm();
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
|
-
this.configButtonState = false;
|
|
98
97
|
|
|
99
|
-
const accountsCount = pluginConfig[0].accounts.length;
|
|
100
98
|
this.deviceIndex = 0;
|
|
99
|
+
|
|
100
|
+
const accountsCount = pluginConfig[0].accounts.length;
|
|
101
101
|
for (let i = 0; i < accountsCount; i++) {
|
|
102
102
|
const button = document.createElement("button");
|
|
103
|
-
button.
|
|
104
|
-
button.
|
|
105
|
-
button.
|
|
103
|
+
button.type = "button";
|
|
104
|
+
button.id = `button${i}`;
|
|
105
|
+
button.className = "btn btn-primary";
|
|
106
106
|
button.style.textTransform = 'none';
|
|
107
107
|
button.innerText = pluginConfig[0].accounts[i].name;
|
|
108
108
|
document.getElementById("accountButton").appendChild(button);
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
button.addEventListener('click', async () => {
|
|
111
111
|
for (let j = 0; j < accountsCount; j++) {
|
|
112
|
-
j === i
|
|
113
|
-
? document.getElementById(`button${j}`).setAttribute("class", "btn btn-secondary")
|
|
114
|
-
: document.getElementById(`button${j}`).setAttribute("class", "btn btn-primary");
|
|
112
|
+
document.getElementById(`button${j}`).className = (j === i ? 'btn btn-secondary' : 'btn btn-primary');
|
|
115
113
|
}
|
|
116
114
|
|
|
117
|
-
|
|
118
|
-
document.getElementById('
|
|
119
|
-
document.getElementById('
|
|
120
|
-
document.getElementById('
|
|
121
|
-
document.getElementById('
|
|
115
|
+
const acc = pluginConfig[0].accounts[i];
|
|
116
|
+
document.getElementById('accountName').innerText = acc.name || '';
|
|
117
|
+
document.getElementById('name').value = acc.name || '';
|
|
118
|
+
document.getElementById('user').value = acc.user || '';
|
|
119
|
+
document.getElementById('passwd').value = acc.passwd || '';
|
|
120
|
+
document.getElementById('language').value = acc.language || '';
|
|
122
121
|
|
|
123
|
-
|
|
124
|
-
document.getElementById('logIn').disabled = !accountConfigured;
|
|
122
|
+
document.getElementById('logIn').disabled = !(acc.name && acc.user && acc.passwd && acc.language);
|
|
125
123
|
|
|
126
|
-
await homebridge.updatePluginConfig(pluginConfig);
|
|
127
124
|
this.deviceIndex = i;
|
|
128
|
-
});
|
|
129
|
-
if (i === accountsCount - 1) {
|
|
130
|
-
document.getElementById(`button0`).click();
|
|
131
125
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
132
|
-
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
if (i === accountsCount - 1) document.getElementById(`button0`).click();
|
|
133
129
|
}
|
|
134
130
|
|
|
135
131
|
document.getElementById('melCloudAccount').style.display = 'block';
|
|
136
132
|
|
|
137
133
|
document.getElementById('configForm').addEventListener('input', async () => {
|
|
138
|
-
pluginConfig[0].accounts[this.deviceIndex]
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
134
|
+
const acc = pluginConfig[0].accounts[this.deviceIndex];
|
|
135
|
+
acc.name = document.querySelector('#name').value;
|
|
136
|
+
acc.user = document.querySelector('#user').value;
|
|
137
|
+
acc.passwd = document.querySelector('#passwd').value;
|
|
138
|
+
acc.language = document.querySelector('#language').value;
|
|
142
139
|
|
|
143
|
-
|
|
144
|
-
document.getElementById('logIn').disabled = !accountConfigured;
|
|
140
|
+
document.getElementById('logIn').disabled = !(acc.name && acc.user && acc.passwd && acc.language);
|
|
145
141
|
|
|
146
142
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
147
143
|
await homebridge.savePluginConfig(pluginConfig);
|
|
148
144
|
});
|
|
149
145
|
|
|
150
|
-
// Config
|
|
146
|
+
// --- Config Button Toggle ---
|
|
151
147
|
const configButton = document.getElementById('configButton');
|
|
152
148
|
let configButtonState = false;
|
|
153
149
|
configButton.addEventListener('click', () => {
|
|
@@ -156,28 +152,30 @@
|
|
|
156
152
|
configButton.className = configButtonState ? 'btn btn-primary' : 'btn btn-secondary';
|
|
157
153
|
});
|
|
158
154
|
|
|
159
|
-
//
|
|
155
|
+
// --- Improved Show/Hide Password ---
|
|
160
156
|
const passwdInput = document.getElementById('passwd');
|
|
161
157
|
const togglePassword = document.getElementById('togglePassword');
|
|
162
158
|
|
|
163
159
|
togglePassword.addEventListener('click', () => {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
160
|
+
const hidden = passwdInput.type === 'password';
|
|
161
|
+
passwdInput.type = hidden ? 'text' : 'password';
|
|
162
|
+
togglePassword.innerHTML = `<i class="fas fa-${hidden ? 'eye-slash' : 'eye'}"></i>`;
|
|
163
|
+
togglePassword.dataset.clicked = hidden; // remember permanent toggle
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
togglePassword.addEventListener('mouseenter', () => {
|
|
167
|
+
passwdInput.type = 'text';
|
|
168
|
+
togglePassword.innerHTML = `<i class="fas fa-eye-slash"></i>`;
|
|
171
169
|
});
|
|
172
170
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
togglePassword.click();
|
|
171
|
+
togglePassword.addEventListener('mouseleave', () => {
|
|
172
|
+
if (!togglePassword.dataset.clicked || togglePassword.dataset.clicked === 'false') {
|
|
173
|
+
passwdInput.type = 'password';
|
|
174
|
+
togglePassword.innerHTML = `<i class="fas fa-eye"></i>`;
|
|
178
175
|
}
|
|
179
176
|
});
|
|
180
177
|
|
|
178
|
+
// --- Device Handling & Login Logic ---
|
|
181
179
|
function removeStaleDevices(configDevices, melcloudDevices) {
|
|
182
180
|
const melcloudIds = melcloudDevices.map(d => d.DeviceID);
|
|
183
181
|
const removedDevices = [];
|
|
@@ -194,181 +192,92 @@
|
|
|
194
192
|
function updateInfo(id, text, color) {
|
|
195
193
|
const el = document.getElementById(id);
|
|
196
194
|
if (el) {
|
|
197
|
-
el.
|
|
195
|
+
el.innerText = text;
|
|
198
196
|
el.style.color = color;
|
|
199
197
|
}
|
|
200
198
|
}
|
|
201
199
|
|
|
202
200
|
document.getElementById('logIn').addEventListener('click', async () => {
|
|
203
201
|
homebridge.showSpinner();
|
|
204
|
-
document.getElementById(`logIn`).
|
|
202
|
+
document.getElementById(`logIn`).className = "btn btn-primary";
|
|
205
203
|
updateInfo('info', 'Connecting...', 'yellow');
|
|
206
204
|
|
|
207
205
|
try {
|
|
208
|
-
const
|
|
209
|
-
const {
|
|
210
|
-
const payload = { accountName, user, passwd, language };
|
|
206
|
+
const acc = pluginConfig[0].accounts[this.deviceIndex];
|
|
207
|
+
const payload = { accountName: acc.name, user: acc.user, passwd: acc.passwd, language: acc.language };
|
|
211
208
|
const devicesInMelCloud = await homebridge.request('/connect', payload);
|
|
212
209
|
|
|
210
|
+
// Initialize devices arrays
|
|
213
211
|
const newDevices = { ata: [], ataPresets: [], atw: [], atwPresets: [], erv: [], ervPresets: [] };
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
for (const deviceInMelcloud of devicesInMelCloud) {
|
|
217
|
-
switch (deviceInMelcloud.Type) {
|
|
218
|
-
case 0: devicesByTypeInMelCloud.ata.push(deviceInMelcloud); break;
|
|
219
|
-
case 1: devicesByTypeInMelCloud.atw.push(deviceInMelcloud); break;
|
|
220
|
-
case 3: devicesByTypeInMelCloud.erv.push(deviceInMelcloud); break;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
212
|
+
const devicesByType = { ata: [], atw: [], erv: [] };
|
|
223
213
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const removedAta = removeStaleDevices(ataDevicesInConfig, devicesByTypeInMelCloud.ata);
|
|
229
|
-
const removedAtw = removeStaleDevices(atwDevicesInConfig, devicesByTypeInMelCloud.atw);
|
|
230
|
-
const removedErv = removeStaleDevices(ervDevicesInConfig, devicesByTypeInMelCloud.erv);
|
|
231
|
-
|
|
232
|
-
// === Handle ATA devices ===
|
|
233
|
-
devicesByTypeInMelCloud.ata.forEach(device => {
|
|
234
|
-
const { DeviceID: deviceId, Type: deviceType, DeviceName: deviceName, Presets: devicePresets = [] } = device;
|
|
235
|
-
const deviceAta = {
|
|
236
|
-
id: deviceId,
|
|
237
|
-
type: deviceType,
|
|
238
|
-
typeString: "Air Conditioner",
|
|
239
|
-
name: deviceName,
|
|
240
|
-
displayMode: 1,
|
|
241
|
-
heatDryFanMode: 1,
|
|
242
|
-
coolDryFanMode: 1,
|
|
243
|
-
autoDryFanMode: 1,
|
|
244
|
-
temperatureSensor: false,
|
|
245
|
-
temperatureSensorOutdoor: false,
|
|
246
|
-
presets: [],
|
|
247
|
-
buttonsSensors: []
|
|
248
|
-
};
|
|
249
|
-
if (!ataDevicesInConfig.some(d => d.id === deviceId)) {
|
|
250
|
-
ataDevicesInConfig.push(deviceAta);
|
|
251
|
-
newDevices.ata.push(deviceAta);
|
|
252
|
-
}
|
|
253
|
-
devicePresets.forEach(preset => {
|
|
254
|
-
const { ID: presetId, NumberDescription: presetName } = preset;
|
|
255
|
-
preset.id = presetId;
|
|
256
|
-
preset.name = presetName;
|
|
257
|
-
preset.displayType = 0;
|
|
258
|
-
preset.namePrefix = false;
|
|
259
|
-
const ataDevice = ataDevicesInConfig.find(d => d.id === deviceId);
|
|
260
|
-
if (ataDevice && !ataDevice.presets.some(p => p.id === presetId)) {
|
|
261
|
-
ataDevice.presets.push(preset);
|
|
262
|
-
newDevices.ataPresets.push(preset);
|
|
263
|
-
}
|
|
264
|
-
});
|
|
214
|
+
devicesInMelCloud.forEach(d => {
|
|
215
|
+
if (d.Type === 0) devicesByType.ata.push(d);
|
|
216
|
+
if (d.Type === 1) devicesByType.atw.push(d);
|
|
217
|
+
if (d.Type === 3) devicesByType.erv.push(d);
|
|
265
218
|
});
|
|
266
219
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
buttonsSensors: []
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
newDevices.atw.push(deviceAtw);
|
|
284
|
-
}
|
|
285
|
-
devicePresets.forEach(preset => {
|
|
286
|
-
const { ID: presetId, NumberDescription: presetName } = preset;
|
|
287
|
-
preset.id = presetId;
|
|
288
|
-
preset.name = presetName;
|
|
289
|
-
preset.displayType = 0;
|
|
290
|
-
preset.namePrefix = false;
|
|
291
|
-
const atwDevice = atwDevicesInConfig.find(d => d.id === deviceId);
|
|
292
|
-
if (atwDevice && !atwDevice.presets.some(p => p.id === presetId)) {
|
|
293
|
-
atwDevice.presets.push(preset);
|
|
294
|
-
newDevices.atwPresets.push(preset);
|
|
220
|
+
acc.ataDevices ??= [];
|
|
221
|
+
acc.atwDevices ??= [];
|
|
222
|
+
acc.ervDevices ??= [];
|
|
223
|
+
|
|
224
|
+
const removedAta = removeStaleDevices(acc.ataDevices, devicesByType.ata);
|
|
225
|
+
const removedAtw = removeStaleDevices(acc.atwDevices, devicesByType.atw);
|
|
226
|
+
const removedErv = removeStaleDevices(acc.ervDevices, devicesByType.erv);
|
|
227
|
+
|
|
228
|
+
// Function to handle device & presets
|
|
229
|
+
const handleDevices = (devicesInCloud, devicesInConfig, typeString, newArr, newPresets) => {
|
|
230
|
+
devicesInCloud.forEach(device => {
|
|
231
|
+
const { DeviceID: id, Type: type, DeviceName: name, Presets: presets = [] } = device;
|
|
232
|
+
const devObj = { id, type, typeString, name, displayMode: 1, presets: [], buttonsSensors: [] };
|
|
233
|
+
if (!devicesInConfig.some(d => d.id === id)) {
|
|
234
|
+
devicesInConfig.push(devObj);
|
|
235
|
+
newArr.push(devObj);
|
|
295
236
|
}
|
|
237
|
+
presets.forEach(p => {
|
|
238
|
+
p.id = p.ID;
|
|
239
|
+
p.name = p.NumberDescription;
|
|
240
|
+
p.displayType = 0;
|
|
241
|
+
p.namePrefix = false;
|
|
242
|
+
const devConfig = devicesInConfig.find(d => d.id === id);
|
|
243
|
+
if (devConfig && !devConfig.presets.some(x => x.id === p.ID)) {
|
|
244
|
+
devConfig.presets.push(p);
|
|
245
|
+
newPresets.push(p);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
296
248
|
});
|
|
297
|
-
}
|
|
249
|
+
};
|
|
298
250
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
const deviceErv = {
|
|
303
|
-
id: deviceId,
|
|
304
|
-
type: deviceType,
|
|
305
|
-
typeString: "ERV",
|
|
306
|
-
name: deviceName,
|
|
307
|
-
displayMode: 1,
|
|
308
|
-
temperatureSensor: false,
|
|
309
|
-
presets: [],
|
|
310
|
-
buttonsSensors: []
|
|
311
|
-
};
|
|
312
|
-
if (!ervDevicesInConfig.some(d => d.id === deviceId)) {
|
|
313
|
-
ervDevicesInConfig.push(deviceErv);
|
|
314
|
-
newDevices.erv.push(deviceErv);
|
|
315
|
-
}
|
|
316
|
-
devicePresets.forEach(preset => {
|
|
317
|
-
const { ID: presetId, NumberDescription: presetName } = preset;
|
|
318
|
-
preset.id = presetId;
|
|
319
|
-
preset.name = presetName;
|
|
320
|
-
preset.displayType = 0;
|
|
321
|
-
preset.namePrefix = false;
|
|
322
|
-
const ervDevice = ervDevicesInConfig.find(d => d.id === deviceId);
|
|
323
|
-
if (ervDevice && !ervDevice.presets.some(p => p.id === presetId)) {
|
|
324
|
-
ervDevice.presets.push(preset);
|
|
325
|
-
newDevices.ervPresets.push(preset);
|
|
326
|
-
}
|
|
327
|
-
});
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
// --- Display Info Section ---
|
|
331
|
-
const textAta = `ATA: ${newDevices.ata.length}`;
|
|
332
|
-
const textAtw = `ATW: ${newDevices.atw.length}`;
|
|
333
|
-
const textErv = `ERV: ${newDevices.erv.length}`;
|
|
334
|
-
const textAtaPresets = `ATA Presets: ${newDevices.ataPresets.length}`;
|
|
335
|
-
const textAtwPresets = `ATW Presets: ${newDevices.atwPresets.length}`;
|
|
336
|
-
const textErvPresets = `ERV Presets: ${newDevices.ervPresets.length}`;
|
|
337
|
-
const textRemovedAta = `ATA: ${removedAta.length}`;
|
|
338
|
-
const textRemovedAtw = `ATW: ${removedAtw.length}`;
|
|
339
|
-
const textRemovedErv = `ERV: ${removedErv.length}`;
|
|
251
|
+
handleDevices(devicesByType.ata, acc.ataDevices, "Air Conditioner", newDevices.ata, newDevices.ataPresets);
|
|
252
|
+
handleDevices(devicesByType.atw, acc.atwDevices, "Heat Pump", newDevices.atw, newDevices.atwPresets);
|
|
253
|
+
handleDevices(devicesByType.erv, acc.ervDevices, "ERV", newDevices.erv, newDevices.ervPresets);
|
|
340
254
|
|
|
255
|
+
// Display summary
|
|
341
256
|
const newDevicesCount = newDevices.ata.length + newDevices.atw.length + newDevices.erv.length;
|
|
342
257
|
const newPresetsCount = newDevices.ataPresets.length + newDevices.atwPresets.length + newDevices.ervPresets.length;
|
|
343
258
|
const removedCount = removedAta.length + removedAtw.length + removedErv.length;
|
|
344
259
|
|
|
345
|
-
if (newDevicesCount
|
|
260
|
+
if (!newDevicesCount && !newPresetsCount && !removedCount) {
|
|
346
261
|
updateInfo('info', 'No changes detected.', 'white');
|
|
347
262
|
} else {
|
|
348
|
-
if (newDevicesCount
|
|
349
|
-
|
|
350
|
-
}
|
|
351
|
-
if (newPresetsCount > 0) {
|
|
352
|
-
updateInfo('info1', `Found new presets: ${textAtaPresets}, ${textAtwPresets}, ${textErvPresets}.`, 'green');
|
|
353
|
-
}
|
|
354
|
-
if (removedCount > 0) {
|
|
355
|
-
updateInfo('info2', `Removed devices: ${textRemovedAta}, ${textRemovedAtw}, ${textRemovedErv}.`, 'orange');
|
|
356
|
-
}
|
|
263
|
+
if (newDevicesCount) updateInfo('info', `Found new devices: ATA: ${newDevices.ata.length}, ATW: ${newDevices.atw.length}, ERV: ${newDevices.erv.length}.`, 'green');
|
|
264
|
+
if (newPresetsCount) updateInfo('info1', `Found new presets: ATA: ${newDevices.ataPresets.length}, ATW: ${newDevices.atwPresets.length}, ERV: ${newDevices.ervPresets.length}.`, 'green');
|
|
265
|
+
if (removedCount) updateInfo('info2', `Removed devices: ATA: ${removedAta.length}, ATW: ${removedAtw.length}, ERV: ${removedErv.length}.`, 'orange');
|
|
357
266
|
}
|
|
358
267
|
|
|
359
268
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
360
269
|
await homebridge.savePluginConfig(pluginConfig);
|
|
361
|
-
document.getElementById('logIn').
|
|
362
|
-
homebridge.hideSpinner();
|
|
270
|
+
document.getElementById('logIn').className = "btn btn-secondary";
|
|
363
271
|
|
|
364
272
|
} catch (error) {
|
|
365
273
|
updateInfo('info', 'Check Your credentials data and try again.', 'yellow');
|
|
366
274
|
updateInfo('info1', `Error: ${error}`, 'red');
|
|
367
|
-
document.getElementById('logIn').
|
|
275
|
+
document.getElementById('logIn').className = "btn btn-secondary";
|
|
368
276
|
} finally {
|
|
369
277
|
homebridge.hideSpinner();
|
|
370
278
|
}
|
|
371
279
|
});
|
|
280
|
+
|
|
372
281
|
})();
|
|
373
282
|
</script>
|
|
374
283
|
</body>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"displayName": "MELCloud Control",
|
|
3
3
|
"name": "homebridge-melcloud-control",
|
|
4
|
-
"version": "3.9.0-beta.
|
|
4
|
+
"version": "3.9.0-beta.18",
|
|
5
5
|
"description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "grzegorz914",
|