homebridge-melcloud-control 3.8.16 → 3.9.0-beta.0

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