homebridge-melcloud-control 3.9.0-beta.13 → 3.9.0-beta.15

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.
@@ -1813,7 +1813,7 @@
1813
1813
  {
1814
1814
  "key": "accounts",
1815
1815
  "type": "tabarray",
1816
- "title": "{{ value.name || 'account' }}",
1816
+ "title": "{{ value.name }}",
1817
1817
  "items": [
1818
1818
  "accounts[].name",
1819
1819
  "accounts[].user",
@@ -6,235 +6,342 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
7
  <title>MELCloud Account Configuration</title>
8
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css">
9
- <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
9
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/js/all.min.js"></script>
10
10
  </head>
11
11
 
12
12
  <body>
13
+
13
14
  <div class="container mt-4">
14
15
  <div class="text-center">
15
- <img src="homebridge-melcloud-control.png" alt="Image" height="100" />
16
+ <img src="homebridge-melcloud-control.png" alt="Image" height="120" />
16
17
  </div>
17
18
 
18
- <!-- Tabs -->
19
- <ul class="nav nav-tabs mt-3" id="accountTabs" role="tablist"></ul>
19
+ <div id="melCloudAccount" class="card card-body mt-3">
20
+ <form id="configForm">
21
+ <div class="text-center">
22
+ <label id="accountName" class="fw-bold" style="font-size: 23px;">Account</label><br>
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
+ </div>
27
+
28
+ <div class="mb-3">
29
+ <label for="name" class="form-label">Name</label>
30
+ <input id="name" type="text" class="form-control" required>
31
+ </div>
32
+
33
+ <div class="mb-3">
34
+ <label for="user" class="form-label">User Name</label>
35
+ <input id="user" type="text" class="form-control" required>
36
+ </div>
37
+
38
+ <div class="mb-3">
39
+ <label for="passwd" class="form-label">Password</label>
40
+ <input id="passwd" type="password" class="form-control" autocomplete="off" required>
41
+ </div>
20
42
 
21
- <!-- Tab contents -->
22
- <div class="tab-content mt-3" id="accountTabsContent"></div>
43
+ <div class="mb-3">
44
+ <label for="language" class="form-label">Language</label>
45
+ <select id="language" name="language" class="form-control">
46
+ <option value="0">English</option>
47
+ <option value="1">Български</option>
48
+ <option value="2">Čeština</option>
49
+ <option value="3">Dansk</option>
50
+ <option value="4">Deutsch</option>
51
+ <option value="5">Eesti</option>
52
+ <option value="6">Español</option>
53
+ <option value="7">Français</option>
54
+ <option value="8">Հայերեն</option>
55
+ <option value="9">Latviešu</option>
56
+ <option value="10">Lietuvių</option>
57
+ <option value="11">Magyar</option>
58
+ <option value="12">Nederlands</option>
59
+ <option value="13">Norwegian</option>
60
+ <option value="14">Polski</option>
61
+ <option value="15">Português</option>
62
+ <option value="16">Русский</option>
63
+ <option value="17">Suomi</option>
64
+ <option value="18">Svenska</option>
65
+ <option value="19">Українська</option>
66
+ <option value="20">Türkçe</option>
67
+ <option value="21">Ελληνικά</option>
68
+ <option value="22">Hrvatski</option>
69
+ <option value="23">Română</option>
70
+ <option value="24">Slovenščina</option>
71
+ </select>
72
+ </div>
23
73
 
24
- <!-- Info Section -->
25
- <div class="mt-3">
26
- <div id="info"></div>
27
- <div id="info1"></div>
28
- <div id="info2"></div>
74
+ <div class="text-center">
75
+ <button id="logIn" type="button" class="btn btn-secondary">Connect to MELCloud</button>
76
+ <button id="configButton" type="button" class="btn btn-secondary"><i class="fas fa-gear"></i></button>
77
+ </div>
78
+ </form>
29
79
  </div>
80
+
81
+ <div id="accountButton" class="mt-3"></div>
30
82
  </div>
31
83
 
32
84
  <script>
33
85
  (async () => {
34
86
  const pluginConfig = await homebridge.getPluginConfig();
35
87
  if (!pluginConfig.length) {
36
- pluginConfig.push({ accounts: [] });
88
+ pluginConfig.push({});
37
89
  await homebridge.updatePluginConfig(pluginConfig);
38
90
  homebridge.showSchemaForm();
39
91
  return;
40
92
  }
93
+ this.configButtonState = false;
41
94
 
42
- const accounts = pluginConfig[0].accounts;
43
- const tabs = document.getElementById("accountTabs");
44
- const content = document.getElementById("accountTabsContent");
95
+ const accountsCount = pluginConfig[0].accounts.length;
96
+ this.deviceIndex = 0;
97
+ for (let i = 0; i < accountsCount; i++) {
98
+ const button = document.createElement("button");
99
+ button.setAttribute("type", "button");
100
+ button.setAttribute("id", `button${i}`);
101
+ button.setAttribute("class", "btn btn-primary");
102
+ button.style.textTransform = 'none';
103
+ button.innerText = pluginConfig[0].accounts[i].name;
104
+ document.getElementById("accountButton").appendChild(button);
45
105
 
46
- function updateConfigButtonState(account, configButton) {
47
- const hasMultipleDevices =
48
- (account.ataDevices?.length || 0) > 1 ||
49
- (account.atwDevices?.length || 0) > 1 ||
50
- (account.ervDevices?.length || 0) > 1;
51
- configButton.disabled = !hasMultipleDevices;
52
- }
106
+ document.getElementById(`button${i}`).addEventListener('click', async () => {
107
+ for (let j = 0; j < accountsCount; j++) {
108
+ j === i
109
+ ? document.getElementById(`button${j}`).setAttribute("class", "btn btn-secondary")
110
+ : document.getElementById(`button${j}`).setAttribute("class", "btn btn-primary");
111
+ }
53
112
 
54
- function createAccountForm(account, i) {
55
- // Tab header
56
- const li = document.createElement("li");
57
- li.classList.add("nav-item");
58
- li.id = `tab-li-${i}`;
59
- li.innerHTML = `
60
- <button class="nav-link ${i === 0 ? 'active' : ''}"
61
- id="tab-${i}" data-bs-toggle="tab"
62
- data-bs-target="#pane-${i}"
63
- type="button" role="tab">
64
- ${account.name || 'Account ' + (i + 1)}
65
- </button>`;
66
- tabs.insertBefore(li, document.getElementById("addTab"));
67
-
68
- // Tab content pane
69
- const pane = document.createElement("div");
70
- pane.classList.add("tab-pane", "fade", i === 0 ? "show" : "", i === 0 ? "active" : "");
71
- pane.id = `pane-${i}`;
72
- pane.role = "tabpanel";
73
- pane.innerHTML = `
74
- <form id="configForm-${i}">
75
- <div class="mb-3">
76
- <label class="form-label">Name</label>
77
- <input type="text" class="form-control" id="name-${i}" value="${account.name || ''}">
78
- </div>
79
- <div class="mb-3">
80
- <label class="form-label">User Name</label>
81
- <input type="text" class="form-control" id="user-${i}" value="${account.user || ''}">
82
- </div>
83
- <div class="mb-3">
84
- <label class="form-label">Password</label>
85
- <input type="password" class="form-control" id="passwd-${i}" value="${account.passwd || ''}">
86
- </div>
87
- <div class="mb-3">
88
- <label class="form-label">Language</label>
89
- <select class="form-control" id="language-${i}">
90
- <option value="0" ${account.language == 0 ? 'selected' : ''}>English</option>
91
- <option value="1" ${account.language == 1 ? 'selected' : ''}>Български</option>
92
- <option value="2" ${account.language == 2 ? 'selected' : ''}>Česky</option>
93
- <option value="3" ${account.language == 3 ? 'selected' : ''}>Dansk</option>
94
- <option value="4" ${account.language == 4 ? 'selected' : ''}>Deutsch</option>
95
- <option value="5" ${account.language == 5 ? 'selected' : ''}>Eesti</option>
96
- <option value="6" ${account.language == 6 ? 'selected' : ''}>Español</option>
97
- <option value="7" ${account.language == 7 ? 'selected' : ''}>Français</option>
98
- <option value="8" ${account.language == 8 ? 'selected' : ''}>Italiano</option>
99
- <option value="9" ${account.language == 9 ? 'selected' : ''}>Latviešu</option>
100
- <option value="10" ${account.language == 10 ? 'selected' : ''}>Lietuvių</option>
101
- <option value="11" ${account.language == 11 ? 'selected' : ''}>Magyar</option>
102
- <option value="12" ${account.language == 12 ? 'selected' : ''}>Nederlands</option>
103
- <option value="13" ${account.language == 13 ? 'selected' : ''}>Norsk</option>
104
- <option value="14" ${account.language == 14 ? 'selected' : ''}>Polski</option>
105
- <option value="15" ${account.language == 15 ? 'selected' : ''}>Português</option>
106
- <option value="16" ${account.language == 16 ? 'selected' : ''}>Русский</option>
107
- <option value="17" ${account.language == 17 ? 'selected' : ''}>Suomi</option>
108
- <option value="18" ${account.language == 18 ? 'selected' : ''}>Svenska</option>
109
- <option value="19" ${account.language == 19 ? 'selected' : ''}>Türkçe</option>
110
- </select>
111
- </div>
112
- <div class="mb-3">
113
- <button type="button" class="btn btn-secondary" id="logIn-${i}">Connect</button>
114
- <button type="button" class="btn btn-danger ms-2" id="remove-${i}">❌ Remove Account</button>
115
- <button type="button" class="btn btn-primary ms-2" id="config-${i}" disabled>⚙️ Config</button>
116
- </div>
117
- </form>`;
118
- content.appendChild(pane);
119
-
120
- const configButton = document.getElementById(`config-${i}`);
121
-
122
- // Enable config button if devices > 1
123
- updateConfigButtonState(account, configButton);
124
-
125
- // Handle input updates
126
- pane.querySelector("form").addEventListener("input", async () => {
127
- account.name = document.getElementById(`name-${i}`).value;
128
- account.user = document.getElementById(`user-${i}`).value;
129
- account.passwd = document.getElementById(`passwd-${i}`).value;
130
- account.language = document.getElementById(`language-${i}`).value;
113
+ document.getElementById('accountName').innerHTML = pluginConfig[0].accounts[i].name || '';
114
+ document.getElementById('name').value = pluginConfig[0].accounts[i].name || '';
115
+ document.getElementById('user').value = pluginConfig[0].accounts[i].user || '';
116
+ document.getElementById('passwd').value = pluginConfig[0].accounts[i].passwd || '';
117
+ document.getElementById('language').value = pluginConfig[0].accounts[i].language || '';
131
118
 
132
- await homebridge.updatePluginConfig(pluginConfig);
133
- await homebridge.savePluginConfig(pluginConfig);
134
- document.querySelector(`#tab-${i}`).innerText = account.name || `Account ${i + 1}`;
135
- });
119
+ const accountConfigured = pluginConfig[0].accounts[i].name && pluginConfig[0].accounts[i].user && pluginConfig[0].accounts[i].passwd && pluginConfig[0].accounts[i].language;
120
+ document.getElementById('logIn').disabled = !accountConfigured;
136
121
 
137
- // Remove account
138
- document.getElementById(`remove-${i}`).addEventListener("click", async () => {
139
- accounts.splice(i, 1);
140
- document.getElementById(`tab-li-${i}`).remove();
141
- document.getElementById(`pane-${i}`).remove();
142
122
  await homebridge.updatePluginConfig(pluginConfig);
143
- await homebridge.savePluginConfig(pluginConfig);
144
- if (accounts.length > 0) new bootstrap.Tab(document.getElementById("tab-0")).show();
123
+ this.deviceIndex = i;
145
124
  });
125
+ if (i === accountsCount - 1) {
126
+ document.getElementById(`button0`).click();
127
+ await homebridge.updatePluginConfig(pluginConfig);
128
+ }
129
+ }
146
130
 
147
- // Login button
148
- document.getElementById(`logIn-${i}`).addEventListener("click", async () => {
149
- homebridge.showSpinner();
150
- try {
151
- const account = accounts[i];
152
- const devicesInMelCloud = await homebridge.request('/connect', {
153
- accountName: account.name,
154
- user: account.user,
155
- passwd: account.passwd,
156
- language: account.language
157
- });
131
+ document.getElementById('melCloudAccount').style.display = 'block';
132
+
133
+ document.getElementById('configForm').addEventListener('input', async () => {
134
+ pluginConfig[0].accounts[this.deviceIndex].name = document.querySelector('#name').value;
135
+ pluginConfig[0].accounts[this.deviceIndex].user = document.querySelector('#user').value;
136
+ pluginConfig[0].accounts[this.deviceIndex].passwd = document.querySelector('#passwd').value;
137
+ pluginConfig[0].accounts[this.deviceIndex].language = document.querySelector('#language').value;
138
+
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;
140
+ document.getElementById('logIn').disabled = !accountConfigured;
141
+
142
+ await homebridge.updatePluginConfig(pluginConfig);
143
+ await homebridge.savePluginConfig(pluginConfig);
144
+ });
145
+
146
+ document.getElementById('configButton').addEventListener('click', async () => {
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");
151
+ this.configButtonState = !this.configButtonState;
152
+ });
153
+
154
+ function removeStaleDevices(configDevices, melcloudDevices) {
155
+ const melcloudIds = melcloudDevices.map(d => d.DeviceID);
156
+ const removedDevices = [];
157
+ for (let i = configDevices.length - 1; i >= 0; i--) {
158
+ const device = configDevices[i];
159
+ if (device.id !== 0 && !melcloudIds.includes(device.id)) {
160
+ removedDevices.push(device);
161
+ configDevices.splice(i, 1);
162
+ }
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
+ }
173
+ }
158
174
 
159
- const devicesByType = { ata: [], atw: [], erv: [] };
160
- for (const d of devicesInMelCloud) {
161
- if (d.Type === 0) devicesByType.ata.push(d);
162
- if (d.Type === 1) devicesByType.atw.push(d);
163
- if (d.Type === 3) devicesByType.erv.push(d);
175
+ document.getElementById('logIn').addEventListener('click', async () => {
176
+ homebridge.showSpinner();
177
+ document.getElementById(`logIn`).setAttribute("class", "btn btn-primary");
178
+ updateInfo('info', 'Connecting...', 'yellow');
179
+
180
+ try {
181
+ const account = pluginConfig[0].accounts[this.deviceIndex];
182
+ const { name: accountName, user, passwd, language } = account;
183
+ const payload = { accountName, user, passwd, language };
184
+ const devicesInMelCloud = await homebridge.request('/connect', payload);
185
+
186
+ const newDevices = { ata: [], ataPresets: [], atw: [], atwPresets: [], erv: [], ervPresets: [] };
187
+ const devicesByTypeInMelCloud = { ata: [], atw: [], erv: [] };
188
+
189
+ for (const deviceInMelcloud of devicesInMelCloud) {
190
+ switch (deviceInMelcloud.Type) {
191
+ case 0: devicesByTypeInMelCloud.ata.push(deviceInMelcloud); break;
192
+ case 1: devicesByTypeInMelCloud.atw.push(deviceInMelcloud); break;
193
+ case 3: devicesByTypeInMelCloud.erv.push(deviceInMelcloud); break;
164
194
  }
195
+ }
165
196
 
166
- // Initialize device arrays if missing
167
- account.ataDevices = account.ataDevices ?? [{}];
168
- account.atwDevices = account.atwDevices ?? [{}];
169
- account.ervDevices = account.ervDevices ?? [{}];
170
-
171
- // Remove stale devices
172
- function removeStaleDevices(configDevices, melcloudDevices) {
173
- const melcloudIds = melcloudDevices.map(d => d.DeviceID);
174
- for (let j = configDevices.length - 1; j >= 0; j--) {
175
- const dev = configDevices[j];
176
- if (dev.id !== 0 && !melcloudIds.includes(dev.id)) configDevices.splice(j, 1);
197
+ const ataDevicesInConfig = account.ataDevices ?? (account.ataDevices = []);
198
+ const atwDevicesInConfig = account.atwDevices ?? (account.atwDevices = []);
199
+ const ervDevicesInConfig = account.ervDevices ?? (account.ervDevices = []);
200
+
201
+ const removedAta = removeStaleDevices(ataDevicesInConfig, devicesByTypeInMelCloud.ata);
202
+ const removedAtw = removeStaleDevices(atwDevicesInConfig, devicesByTypeInMelCloud.atw);
203
+ const removedErv = removeStaleDevices(ervDevicesInConfig, devicesByTypeInMelCloud.erv);
204
+
205
+ // === Handle ATA devices ===
206
+ devicesByTypeInMelCloud.ata.forEach(device => {
207
+ const { DeviceID: deviceId, Type: deviceType, DeviceName: deviceName, Presets: devicePresets = [] } = device;
208
+ const deviceAta = {
209
+ id: deviceId,
210
+ type: deviceType,
211
+ typeString: "Air Conditioner",
212
+ name: deviceName,
213
+ displayMode: 1,
214
+ heatDryFanMode: 1,
215
+ coolDryFanMode: 1,
216
+ autoDryFanMode: 1,
217
+ temperatureSensor: false,
218
+ temperatureSensorOutdoor: false,
219
+ presets: [],
220
+ buttonsSensors: []
221
+ };
222
+ if (!ataDevicesInConfig.some(d => d.id === deviceId)) {
223
+ ataDevicesInConfig.push(deviceAta);
224
+ newDevices.ata.push(deviceAta);
225
+ }
226
+ devicePresets.forEach(preset => {
227
+ const { ID: presetId, NumberDescription: presetName } = preset;
228
+ preset.id = presetId;
229
+ preset.name = presetName;
230
+ preset.displayType = 0;
231
+ preset.namePrefix = false;
232
+ const ataDevice = ataDevicesInConfig.find(d => d.id === deviceId);
233
+ if (ataDevice && !ataDevice.presets.some(p => p.id === presetId)) {
234
+ ataDevice.presets.push(preset);
235
+ newDevices.ataPresets.push(preset);
177
236
  }
237
+ });
238
+ });
239
+
240
+ // === Handle ATW devices ===
241
+ devicesByTypeInMelCloud.atw.forEach(device => {
242
+ const { DeviceID: deviceId, Type: deviceType, DeviceName: deviceName, Presets: devicePresets = [] } = device;
243
+ const deviceAtw = {
244
+ id: deviceId,
245
+ type: deviceType,
246
+ typeString: "Heat Pump",
247
+ name: deviceName,
248
+ displayMode: 1,
249
+ hideZone: 0,
250
+ temperatureSensor: false,
251
+ presets: [],
252
+ buttonsSensors: []
253
+ };
254
+ if (!atwDevicesInConfig.some(d => d.id === deviceId)) {
255
+ atwDevicesInConfig.push(deviceAtw);
256
+ newDevices.atw.push(deviceAtw);
178
257
  }
258
+ devicePresets.forEach(preset => {
259
+ const { ID: presetId, NumberDescription: presetName } = preset;
260
+ preset.id = presetId;
261
+ preset.name = presetName;
262
+ preset.displayType = 0;
263
+ preset.namePrefix = false;
264
+ const atwDevice = atwDevicesInConfig.find(d => d.id === deviceId);
265
+ if (atwDevice && !atwDevice.presets.some(p => p.id === presetId)) {
266
+ atwDevice.presets.push(preset);
267
+ newDevices.atwPresets.push(preset);
268
+ }
269
+ });
270
+ });
179
271
 
180
- removeStaleDevices(account.ataDevices, devicesByType.ata);
181
- removeStaleDevices(account.atwDevices, devicesByType.atw);
182
- removeStaleDevices(account.ervDevices, devicesByType.erv);
183
-
184
- // Add new devices
185
- function addDevices(configArray, devicesArray) {
186
- devicesArray.forEach(d => {
187
- if (!configArray.find(x => x.id === d.DeviceID)) {
188
- configArray.push({ id: d.DeviceID, type: d.Type, name: d.DeviceName });
189
- }
190
- });
272
+ // === Handle ERV devices ===
273
+ devicesByTypeInMelCloud.erv.forEach(device => {
274
+ const { DeviceID: deviceId, Type: deviceType, DeviceName: deviceName, Presets: devicePresets = [] } = device;
275
+ const deviceErv = {
276
+ id: deviceId,
277
+ type: deviceType,
278
+ typeString: "ERV",
279
+ name: deviceName,
280
+ displayMode: 1,
281
+ temperatureSensor: false,
282
+ presets: [],
283
+ buttonsSensors: []
284
+ };
285
+ if (!ervDevicesInConfig.some(d => d.id === deviceId)) {
286
+ ervDevicesInConfig.push(deviceErv);
287
+ newDevices.erv.push(deviceErv);
191
288
  }
289
+ devicePresets.forEach(preset => {
290
+ const { ID: presetId, NumberDescription: presetName } = preset;
291
+ preset.id = presetId;
292
+ preset.name = presetName;
293
+ preset.displayType = 0;
294
+ preset.namePrefix = false;
295
+ const ervDevice = ervDevicesInConfig.find(d => d.id === deviceId);
296
+ if (ervDevice && !ervDevice.presets.some(p => p.id === presetId)) {
297
+ ervDevice.presets.push(preset);
298
+ newDevices.ervPresets.push(preset);
299
+ }
300
+ });
301
+ });
192
302
 
193
- addDevices(account.ataDevices, devicesByType.ata);
194
- addDevices(account.atwDevices, devicesByType.atw);
195
- addDevices(account.ervDevices, devicesByType.erv);
303
+ // --- Display Info Section ---
304
+ const textAta = `ATA: ${newDevices.ata.length}`;
305
+ const textAtw = `ATW: ${newDevices.atw.length}`;
306
+ const textErv = `ERV: ${newDevices.erv.length}`;
307
+ const textAtaPresets = `ATA Presets: ${newDevices.ataPresets.length}`;
308
+ const textAtwPresets = `ATW Presets: ${newDevices.atwPresets.length}`;
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}`;
196
313
 
197
- // Update Config button state
198
- updateConfigButtonState(account, configButton);
314
+ const newDevicesCount = newDevices.ata.length + newDevices.atw.length + newDevices.erv.length;
315
+ const newPresetsCount = newDevices.ataPresets.length + newDevices.atwPresets.length + newDevices.ervPresets.length;
316
+ const removedCount = removedAta.length + removedAtw.length + removedErv.length;
199
317
 
200
- await homebridge.updatePluginConfig(pluginConfig);
201
- await homebridge.savePluginConfig(pluginConfig);
202
- } catch (err) {
203
- document.getElementById('info').innerHTML = `Error: ${err.message || err}`;
204
- } finally {
205
- homebridge.hideSpinner();
206
- }
207
- });
208
-
209
- // Config button click
210
- configButton.addEventListener('click', () => {
211
- if (configButton.classList.contains('btn-primary')) {
212
- homebridge.showSchemaForm();
318
+ if (newDevicesCount === 0 && newPresetsCount === 0 && removedCount === 0) {
319
+ updateInfo('info', 'No changes detected.', 'white');
213
320
  } else {
214
- homebridge.hideSchemaForm();
321
+ if (newDevicesCount > 0) {
322
+ updateInfo('info', `Found new devices: ${textAta}, ${textAtw}, ${textErv}.`, 'green');
323
+ }
324
+ if (newPresetsCount > 0) {
325
+ updateInfo('info1', `Found new presets: ${textAtaPresets}, ${textAtwPresets}, ${textErvPresets}.`, 'green');
326
+ }
327
+ if (removedCount > 0) {
328
+ updateInfo('info2', `Removed devices: ${textRemovedAta}, ${textRemovedAtw}, ${textRemovedErv}.`, 'orange');
329
+ }
215
330
  }
216
- });
217
- }
218
331
 
219
- // Render accounts
220
- accounts.forEach((acc, i) => createAccountForm(acc, i));
221
-
222
- // Add "Add Account" tab
223
- const addLi = document.createElement("li");
224
- addLi.classList.add("nav-item");
225
- addLi.innerHTML = `<button class="nav-link" id="addTab" type="button" role="tab">➕ Add Account</button>`;
226
- tabs.appendChild(addLi);
332
+ await homebridge.updatePluginConfig(pluginConfig);
333
+ await homebridge.savePluginConfig(pluginConfig);
334
+ document.getElementById('logIn').setAttribute('class', 'btn btn-secondary');
335
+ homebridge.hideSpinner();
227
336
 
228
- document.getElementById("addTab").addEventListener("click", async () => {
229
- const newAccount = { name: "", user: "", passwd: "", language: 0, ataDevices: [{}], atwDevices: [{}], ervDevices: [{}] };
230
- accounts.push(newAccount);
231
- const i = accounts.length - 1;
232
- createAccountForm(newAccount, i);
233
- await homebridge.updatePluginConfig(pluginConfig);
234
- await homebridge.savePluginConfig(pluginConfig);
235
- new bootstrap.Tab(document.getElementById(`tab-${i}`)).show();
337
+ } catch (error) {
338
+ updateInfo('info', 'Check Your credentials data and try again.', 'yellow');
339
+ updateInfo('info1', `Error: ${error}`, 'red');
340
+ document.getElementById('logIn').setAttribute('class', 'btn btn-secondary');
341
+ } finally {
342
+ homebridge.hideSpinner();
343
+ }
236
344
  });
237
-
238
345
  })();
239
346
  </script>
240
347
  </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.13",
4
+ "version": "3.9.0-beta.15",
5
5
  "description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",