homebridge-melcloud-control 3.9.0-beta.5 → 3.9.0-beta.7
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 +64 -104
- package/package.json +1 -1
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
<form id="configForm">
|
|
21
21
|
<div class="text-center">
|
|
22
22
|
<label id="accountName" class="fw-bold" style="font-size: 23px;">Account</label><br>
|
|
23
|
-
<label id="info" class="d-block" style="font-size:
|
|
24
|
-
<label id="info1" class="d-block" style="font-size:
|
|
25
|
-
<label id="info2" class="d-block" style="font-size:
|
|
23
|
+
<label id="info" class="d-block" style="font-size: 16px;"></label>
|
|
24
|
+
<label id="info1" class="d-block" style="font-size: 14px;"></label>
|
|
25
|
+
<label id="info2" class="d-block" style="font-size: 14px;"></label>
|
|
26
26
|
</div>
|
|
27
27
|
|
|
28
28
|
<div class="mb-3">
|
|
@@ -83,9 +83,7 @@
|
|
|
83
83
|
|
|
84
84
|
<script>
|
|
85
85
|
(async () => {
|
|
86
|
-
//get the plugin config array
|
|
87
86
|
const pluginConfig = await homebridge.getPluginConfig();
|
|
88
|
-
|
|
89
87
|
if (!pluginConfig.length) {
|
|
90
88
|
pluginConfig.push({});
|
|
91
89
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
@@ -94,11 +92,9 @@
|
|
|
94
92
|
}
|
|
95
93
|
this.configButtonState = false;
|
|
96
94
|
|
|
97
|
-
//get accounts count
|
|
98
95
|
const accountsCount = pluginConfig[0].accounts.length;
|
|
99
96
|
this.deviceIndex = 0;
|
|
100
97
|
for (let i = 0; i < accountsCount; i++) {
|
|
101
|
-
//create buttons
|
|
102
98
|
const button = document.createElement("button");
|
|
103
99
|
button.setAttribute("type", "button");
|
|
104
100
|
button.setAttribute("id", `button${i}`);
|
|
@@ -107,10 +103,11 @@
|
|
|
107
103
|
button.innerText = pluginConfig[0].accounts[i].name;
|
|
108
104
|
document.getElementById("accountButton").appendChild(button);
|
|
109
105
|
|
|
110
|
-
//get actuall value on account select
|
|
111
106
|
document.getElementById(`button${i}`).addEventListener('click', async () => {
|
|
112
107
|
for (let j = 0; j < accountsCount; j++) {
|
|
113
|
-
|
|
108
|
+
j === i
|
|
109
|
+
? document.getElementById(`button${j}`).setAttribute("class", "btn btn-secondary")
|
|
110
|
+
: document.getElementById(`button${j}`).setAttribute("class", "btn btn-primary");
|
|
114
111
|
}
|
|
115
112
|
|
|
116
113
|
document.getElementById('accountName').innerHTML = pluginConfig[0].accounts[i].name || '';
|
|
@@ -120,20 +117,19 @@
|
|
|
120
117
|
document.getElementById('language').value = pluginConfig[0].accounts[i].language || '';
|
|
121
118
|
|
|
122
119
|
const accountConfigured = pluginConfig[0].accounts[i].name && pluginConfig[0].accounts[i].user && pluginConfig[0].accounts[i].passwd && pluginConfig[0].accounts[i].language;
|
|
123
|
-
|
|
124
|
-
const setButtonState = accountConfigured ? button.disabled = false : button.disabled = true;
|
|
120
|
+
document.getElementById('logIn').disabled = !accountConfigured;
|
|
125
121
|
|
|
126
122
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
127
123
|
this.deviceIndex = i;
|
|
128
124
|
});
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
125
|
+
if (i === accountsCount - 1) {
|
|
126
|
+
document.getElementById(`button0`).click();
|
|
127
|
+
await homebridge.updatePluginConfig(pluginConfig);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
132
130
|
|
|
133
|
-
//load melCloudAccount form
|
|
134
131
|
document.getElementById('melCloudAccount').style.display = 'block';
|
|
135
132
|
|
|
136
|
-
//watch for changes to the form
|
|
137
133
|
document.getElementById('configForm').addEventListener('input', async () => {
|
|
138
134
|
pluginConfig[0].accounts[this.deviceIndex].name = document.querySelector('#name').value;
|
|
139
135
|
pluginConfig[0].accounts[this.deviceIndex].user = document.querySelector('#user').value;
|
|
@@ -141,58 +137,55 @@
|
|
|
141
137
|
pluginConfig[0].accounts[this.deviceIndex].language = document.querySelector('#language').value;
|
|
142
138
|
|
|
143
139
|
const accountConfigured = pluginConfig[0].accounts[this.deviceIndex].name && pluginConfig[0].accounts[this.deviceIndex].user && pluginConfig[0].accounts[this.deviceIndex].passwd && pluginConfig[0].accounts[this.deviceIndex].language;
|
|
144
|
-
|
|
145
|
-
const setButtonState = accountConfigured ? button.disabled = false : button.disabled = true;
|
|
140
|
+
document.getElementById('logIn').disabled = !accountConfigured;
|
|
146
141
|
|
|
147
142
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
148
143
|
await homebridge.savePluginConfig(pluginConfig);
|
|
149
144
|
});
|
|
150
145
|
|
|
151
|
-
//watch for changes to the config button
|
|
152
146
|
document.getElementById('configButton').addEventListener('click', async () => {
|
|
153
|
-
|
|
154
|
-
|
|
147
|
+
this.configButtonState ? homebridge.hideSchemaForm() : homebridge.showSchemaForm();
|
|
148
|
+
this.configButtonState
|
|
149
|
+
? document.getElementById(`configButton`).setAttribute("class", "btn btn-secondary")
|
|
150
|
+
: document.getElementById(`configButton`).setAttribute("class", "btn btn-primary");
|
|
155
151
|
this.configButtonState = !this.configButtonState;
|
|
156
152
|
});
|
|
157
153
|
|
|
158
|
-
// Helper to remove stale devices by comparing with MELCloud
|
|
159
154
|
function removeStaleDevices(configDevices, melcloudDevices) {
|
|
160
155
|
const melcloudIds = melcloudDevices.map(d => d.DeviceID);
|
|
156
|
+
const removedDevices = [];
|
|
161
157
|
for (let i = configDevices.length - 1; i >= 0; i--) {
|
|
162
158
|
const device = configDevices[i];
|
|
163
159
|
if (device.id !== 0 && !melcloudIds.includes(device.id)) {
|
|
160
|
+
removedDevices.push(device);
|
|
164
161
|
configDevices.splice(i, 1);
|
|
165
162
|
}
|
|
166
163
|
}
|
|
164
|
+
return removedDevices;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function updateInfo(id, text, color) {
|
|
168
|
+
const el = document.getElementById(id);
|
|
169
|
+
if (el) {
|
|
170
|
+
el.innerHTML = text;
|
|
171
|
+
el.style.color = color;
|
|
172
|
+
}
|
|
167
173
|
}
|
|
168
174
|
|
|
169
|
-
//watch for click on the login button
|
|
170
175
|
document.getElementById('logIn').addEventListener('click', async () => {
|
|
171
176
|
homebridge.showSpinner();
|
|
172
|
-
|
|
173
177
|
document.getElementById(`logIn`).setAttribute("class", "btn btn-primary");
|
|
174
|
-
|
|
175
|
-
document.getElementById('info').style.color = 'yellow';
|
|
178
|
+
updateInfo('info', 'Connecting...', 'yellow');
|
|
176
179
|
|
|
177
180
|
try {
|
|
178
181
|
const account = pluginConfig[0].accounts[this.deviceIndex];
|
|
179
182
|
const { name: accountName, user, passwd, language } = account;
|
|
180
|
-
|
|
181
183
|
const payload = { accountName, user, passwd, language };
|
|
182
184
|
const devicesInMelCloud = await homebridge.request('/connect', payload);
|
|
183
185
|
|
|
184
|
-
const newDevices = {
|
|
185
|
-
ata: [],
|
|
186
|
-
ataPresets: [],
|
|
187
|
-
atw: [],
|
|
188
|
-
atwPresets: [],
|
|
189
|
-
erv: [],
|
|
190
|
-
ervPresets: [],
|
|
191
|
-
};
|
|
192
|
-
|
|
186
|
+
const newDevices = { ata: [], ataPresets: [], atw: [], atwPresets: [], erv: [], ervPresets: [] };
|
|
193
187
|
const devicesByTypeInMelCloud = { ata: [], atw: [], erv: [] };
|
|
194
188
|
|
|
195
|
-
// Categorize devices by type
|
|
196
189
|
for (const deviceInMelcloud of devicesInMelCloud) {
|
|
197
190
|
switch (deviceInMelcloud.Type) {
|
|
198
191
|
case 0: devicesByTypeInMelCloud.ata.push(deviceInMelcloud); break;
|
|
@@ -201,27 +194,16 @@
|
|
|
201
194
|
}
|
|
202
195
|
}
|
|
203
196
|
|
|
204
|
-
// Ensure config arrays exist
|
|
205
197
|
const ataDevicesInConfig = account.ataDevices ?? (account.ataDevices = []);
|
|
206
198
|
const atwDevicesInConfig = account.atwDevices ?? (account.atwDevices = []);
|
|
207
199
|
const ervDevicesInConfig = account.ervDevices ?? (account.ervDevices = []);
|
|
208
200
|
|
|
209
|
-
|
|
210
|
-
removeStaleDevices(
|
|
211
|
-
removeStaleDevices(
|
|
212
|
-
removeStaleDevices(ervDevicesInConfig, devicesByTypeInMelCloud.erv);
|
|
213
|
-
|
|
214
|
-
// Helper for updating UI
|
|
215
|
-
const updateInfo = (id, text, color) => {
|
|
216
|
-
const el = document.getElementById(id);
|
|
217
|
-
if (el) {
|
|
218
|
-
el.innerHTML = text;
|
|
219
|
-
el.style.color = color;
|
|
220
|
-
}
|
|
221
|
-
};
|
|
201
|
+
const removedAta = removeStaleDevices(ataDevicesInConfig, devicesByTypeInMelCloud.ata);
|
|
202
|
+
const removedAtw = removeStaleDevices(atwDevicesInConfig, devicesByTypeInMelCloud.atw);
|
|
203
|
+
const removedErv = removeStaleDevices(ervDevicesInConfig, devicesByTypeInMelCloud.erv);
|
|
222
204
|
|
|
223
|
-
// Handle ATA devices
|
|
224
|
-
devicesByTypeInMelCloud.ata.forEach(
|
|
205
|
+
// === Handle ATA devices ===
|
|
206
|
+
devicesByTypeInMelCloud.ata.forEach(device => {
|
|
225
207
|
const { DeviceID: deviceId, Type: deviceType, DeviceName: deviceName, Presets: devicePresets = [] } = device;
|
|
226
208
|
const deviceAta = {
|
|
227
209
|
id: deviceId,
|
|
@@ -237,29 +219,26 @@
|
|
|
237
219
|
presets: [],
|
|
238
220
|
buttonsSensors: []
|
|
239
221
|
};
|
|
240
|
-
|
|
241
|
-
if (!ataDevicesInConfig.some(device => device.id === deviceId)) {
|
|
222
|
+
if (!ataDevicesInConfig.some(d => d.id === deviceId)) {
|
|
242
223
|
ataDevicesInConfig.push(deviceAta);
|
|
243
224
|
newDevices.ata.push(deviceAta);
|
|
244
225
|
}
|
|
245
|
-
|
|
246
|
-
devicePresets.forEach((preset) => {
|
|
226
|
+
devicePresets.forEach(preset => {
|
|
247
227
|
const { ID: presetId, NumberDescription: presetName } = preset;
|
|
248
228
|
preset.id = presetId;
|
|
249
229
|
preset.name = presetName;
|
|
250
230
|
preset.displayType = 0;
|
|
251
231
|
preset.namePrefix = false;
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if (ataDevice && !ataDevice.presets.some((p) => p.id === presetId)) {
|
|
232
|
+
const ataDevice = ataDevicesInConfig.find(d => d.id === deviceId);
|
|
233
|
+
if (ataDevice && !ataDevice.presets.some(p => p.id === presetId)) {
|
|
255
234
|
ataDevice.presets.push(preset);
|
|
256
235
|
newDevices.ataPresets.push(preset);
|
|
257
236
|
}
|
|
258
237
|
});
|
|
259
238
|
});
|
|
260
239
|
|
|
261
|
-
// Handle ATW devices
|
|
262
|
-
devicesByTypeInMelCloud.atw.forEach(
|
|
240
|
+
// === Handle ATW devices ===
|
|
241
|
+
devicesByTypeInMelCloud.atw.forEach(device => {
|
|
263
242
|
const { DeviceID: deviceId, Type: deviceType, DeviceName: deviceName, Presets: devicePresets = [] } = device;
|
|
264
243
|
const deviceAtw = {
|
|
265
244
|
id: deviceId,
|
|
@@ -269,107 +248,89 @@
|
|
|
269
248
|
displayMode: 1,
|
|
270
249
|
hideZone: 0,
|
|
271
250
|
temperatureSensor: false,
|
|
272
|
-
temperatureSensorFlow: false,
|
|
273
|
-
temperatureSensorReturn: false,
|
|
274
|
-
temperatureSensorFlowZone1: false,
|
|
275
|
-
temperatureSensorReturnZone1: false,
|
|
276
|
-
temperatureSensorFlowWaterTank: false,
|
|
277
|
-
temperatureSensorReturnWaterTank: false,
|
|
278
|
-
temperatureSensorFlowZone2: false,
|
|
279
|
-
temperatureSensorReturnZone2: false,
|
|
280
|
-
temperatureSensorOutdoor: false,
|
|
281
251
|
presets: [],
|
|
282
252
|
buttonsSensors: []
|
|
283
253
|
};
|
|
284
|
-
|
|
285
|
-
if (!atwDevicesInConfig.some(device => device.id === deviceId)) {
|
|
254
|
+
if (!atwDevicesInConfig.some(d => d.id === deviceId)) {
|
|
286
255
|
atwDevicesInConfig.push(deviceAtw);
|
|
287
256
|
newDevices.atw.push(deviceAtw);
|
|
288
257
|
}
|
|
289
|
-
|
|
290
|
-
devicePresets.forEach((preset) => {
|
|
258
|
+
devicePresets.forEach(preset => {
|
|
291
259
|
const { ID: presetId, NumberDescription: presetName } = preset;
|
|
292
260
|
preset.id = presetId;
|
|
293
261
|
preset.name = presetName;
|
|
294
262
|
preset.displayType = 0;
|
|
295
263
|
preset.namePrefix = false;
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
if (atwDevice && !atwDevice.presets.some((p) => p.id === presetId)) {
|
|
264
|
+
const atwDevice = atwDevicesInConfig.find(d => d.id === deviceId);
|
|
265
|
+
if (atwDevice && !atwDevice.presets.some(p => p.id === presetId)) {
|
|
299
266
|
atwDevice.presets.push(preset);
|
|
300
267
|
newDevices.atwPresets.push(preset);
|
|
301
268
|
}
|
|
302
269
|
});
|
|
303
270
|
});
|
|
304
271
|
|
|
305
|
-
// Handle ERV devices
|
|
306
|
-
devicesByTypeInMelCloud.erv.forEach(
|
|
272
|
+
// === Handle ERV devices ===
|
|
273
|
+
devicesByTypeInMelCloud.erv.forEach(device => {
|
|
307
274
|
const { DeviceID: deviceId, Type: deviceType, DeviceName: deviceName, Presets: devicePresets = [] } = device;
|
|
308
275
|
const deviceErv = {
|
|
309
276
|
id: deviceId,
|
|
310
277
|
type: deviceType,
|
|
311
|
-
typeString: "
|
|
278
|
+
typeString: "ERV",
|
|
312
279
|
name: deviceName,
|
|
313
280
|
displayMode: 1,
|
|
314
281
|
temperatureSensor: false,
|
|
315
|
-
temperatureSensorOutdoor: false,
|
|
316
|
-
temperatureSensorSupply: false,
|
|
317
282
|
presets: [],
|
|
318
283
|
buttonsSensors: []
|
|
319
284
|
};
|
|
320
|
-
|
|
321
|
-
if (!ervDevicesInConfig.some(device => device.id === deviceId)) {
|
|
285
|
+
if (!ervDevicesInConfig.some(d => d.id === deviceId)) {
|
|
322
286
|
ervDevicesInConfig.push(deviceErv);
|
|
323
287
|
newDevices.erv.push(deviceErv);
|
|
324
288
|
}
|
|
325
|
-
|
|
326
|
-
devicePresets.forEach((preset) => {
|
|
289
|
+
devicePresets.forEach(preset => {
|
|
327
290
|
const { ID: presetId, NumberDescription: presetName } = preset;
|
|
328
291
|
preset.id = presetId;
|
|
329
292
|
preset.name = presetName;
|
|
330
293
|
preset.displayType = 0;
|
|
331
294
|
preset.namePrefix = false;
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if (ervDevice && !ervDevice.presets.some((p) => p.id === presetId)) {
|
|
295
|
+
const ervDevice = ervDevicesInConfig.find(d => d.id === deviceId);
|
|
296
|
+
if (ervDevice && !ervDevice.presets.some(p => p.id === presetId)) {
|
|
335
297
|
ervDevice.presets.push(preset);
|
|
336
298
|
newDevices.ervPresets.push(preset);
|
|
337
299
|
}
|
|
338
300
|
});
|
|
339
301
|
});
|
|
340
302
|
|
|
341
|
-
// Display
|
|
303
|
+
// --- Display Info Section ---
|
|
342
304
|
const textAta = `ATA: ${newDevices.ata.length}`;
|
|
343
305
|
const textAtw = `ATW: ${newDevices.atw.length}`;
|
|
344
306
|
const textErv = `ERV: ${newDevices.erv.length}`;
|
|
345
307
|
const textAtaPresets = `ATA Presets: ${newDevices.ataPresets.length}`;
|
|
346
308
|
const textAtwPresets = `ATW Presets: ${newDevices.atwPresets.length}`;
|
|
347
309
|
const textErvPresets = `ERV Presets: ${newDevices.ervPresets.length}`;
|
|
310
|
+
const textRemovedAta = `ATA: ${removedAta.length}`;
|
|
311
|
+
const textRemovedAtw = `ATW: ${removedAtw.length}`;
|
|
312
|
+
const textRemovedErv = `ERV: ${removedErv.length}`;
|
|
348
313
|
|
|
349
314
|
const newDevicesCount = newDevices.ata.length + newDevices.atw.length + newDevices.erv.length;
|
|
350
315
|
const newPresetsCount = newDevices.ataPresets.length + newDevices.atwPresets.length + newDevices.ervPresets.length;
|
|
316
|
+
const removedCount = removedAta.length + removedAtw.length + removedErv.length;
|
|
351
317
|
|
|
352
|
-
if (newDevicesCount === 0 && newPresetsCount === 0) {
|
|
353
|
-
updateInfo('info', 'No
|
|
318
|
+
if (newDevicesCount === 0 && newPresetsCount === 0 && removedCount === 0) {
|
|
319
|
+
updateInfo('info', 'No changes detected.', 'white');
|
|
354
320
|
} else {
|
|
355
321
|
if (newDevicesCount > 0) {
|
|
356
|
-
updateInfo('info', `Found
|
|
357
|
-
updateInfo('info2', 'Now You can configure it.', 'green');
|
|
322
|
+
updateInfo('info', `Found new devices: ${textAta}, ${textAtw}, ${textErv}.`, 'green');
|
|
358
323
|
}
|
|
359
324
|
if (newPresetsCount > 0) {
|
|
360
|
-
updateInfo('info1',
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
325
|
+
updateInfo('info1', `Found new presets: ${textAtaPresets}, ${textAtwPresets}, ${textErvPresets}.`, 'green');
|
|
326
|
+
}
|
|
327
|
+
if (removedCount > 0) {
|
|
328
|
+
updateInfo('info2', `Removed devices: ${textRemovedAta}, ${textRemovedAtw}, ${textRemovedErv}.`, 'orange');
|
|
365
329
|
}
|
|
366
330
|
}
|
|
367
331
|
|
|
368
|
-
// Save updated config
|
|
369
332
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
370
333
|
await homebridge.savePluginConfig(pluginConfig);
|
|
371
|
-
|
|
372
|
-
// Update button
|
|
373
334
|
document.getElementById('logIn').setAttribute('class', 'btn btn-secondary');
|
|
374
335
|
homebridge.hideSpinner();
|
|
375
336
|
|
|
@@ -380,7 +341,6 @@
|
|
|
380
341
|
} finally {
|
|
381
342
|
homebridge.hideSpinner();
|
|
382
343
|
}
|
|
383
|
-
|
|
384
344
|
});
|
|
385
345
|
})();
|
|
386
346
|
</script>
|
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.7",
|
|
5
5
|
"description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "grzegorz914",
|