homebridge-melcloud-control 3.9.0-beta.5 → 3.9.0-beta.6

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