homebridge-melcloud-control 4.4.1-beta.3 → 4.4.1-beta.31

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/src/melcloud.js CHANGED
@@ -56,7 +56,7 @@ class MelCloud extends EventEmitter {
56
56
  try {
57
57
  const devicesList = { State: false, Info: null, Devices: [], Scenes: [] }
58
58
  if (this.logDebug) this.emit('debug', `Scanning for devices...`);
59
- const listDevicesData = await this.client(ApiUrls.ListDevices, { method: 'GET', });
59
+ const listDevicesData = await this.client(ApiUrls.Get.ListDevices, { method: 'GET', });
60
60
 
61
61
  if (!listDevicesData || !listDevicesData.data) {
62
62
  devicesList.Info = 'Invalid or empty response from MELCloud API'
@@ -132,9 +132,9 @@ class MelCloud extends EventEmitter {
132
132
  CaptchaResponse: '',
133
133
  Persist: true
134
134
  };
135
- const accountData = await axios(ApiUrls.ClientLogin, {
135
+ const accountData = await axios(ApiUrls.Post.ClientLogin, {
136
136
  method: 'POST',
137
- baseURL: ApiUrls.BaseURL,
137
+ baseURL: ApiUrls.Base,
138
138
  timeout: 15000,
139
139
  data: payload
140
140
  });
@@ -164,7 +164,7 @@ class MelCloud extends EventEmitter {
164
164
  };
165
165
 
166
166
  this.client = axios.create({
167
- baseURL: ApiUrls.BaseURL,
167
+ baseURL: ApiUrls.Base,
168
168
  timeout: 30000,
169
169
  headers: headers
170
170
  });
@@ -1,6 +1,6 @@
1
1
  import EventEmitter from 'events';
2
2
  import Functions from './functions.js';
3
- import { ApiUrls, ApiUrlsHome, AirConditioner } from './constants.js';
3
+ import { ApiUrls, AirConditioner } from './constants.js';
4
4
 
5
5
  class MelCloudAta extends EventEmitter {
6
6
  constructor(account, device, defaultTempsFile, accountFile, melcloud) {
@@ -204,7 +204,7 @@ class MelCloudAta extends EventEmitter {
204
204
  case 'account':
205
205
  flagData.Account.LoginData.UseFahrenheit = flagData.UseFahrenheit;
206
206
  payload = { data: flagData.LoginData };
207
- path = ApiUrls.UpdateApplicationOptions;
207
+ path = ApiUrls.Post.UpdateApplicationOptions;
208
208
  await this.functions.saveData(this.accountFile, flagData);
209
209
  break;
210
210
  default:
@@ -230,7 +230,7 @@ class MelCloudAta extends EventEmitter {
230
230
  HideDryModeControl: deviceData.HideDryModeControl,
231
231
  HasPendingCommand: true
232
232
  };
233
- path = ApiUrls.SetAta;
233
+ path = ApiUrls.Post.Ata;
234
234
  update = true;
235
235
  break;
236
236
  }
@@ -254,7 +254,7 @@ class MelCloudAta extends EventEmitter {
254
254
  units: { ATA: [deviceData.DeviceID] }
255
255
  };
256
256
  method = 'POST';
257
- path = ApiUrlsHome.PostProtectionFrost;
257
+ path = ApiUrls.Home.Post.ProtectionFrost;
258
258
  update = true;
259
259
  break;
260
260
  case 'overheatprotection':
@@ -265,7 +265,7 @@ class MelCloudAta extends EventEmitter {
265
265
  units: { ATA: [deviceData.DeviceID] }
266
266
  };
267
267
  method = 'POST';
268
- path = ApiUrlsHome.PostProtectionOverheat;
268
+ path = ApiUrls.Home.Post.ProtectionOverheat;
269
269
  update = true;
270
270
  break;
271
271
  case 'holidaymode':
@@ -276,17 +276,17 @@ class MelCloudAta extends EventEmitter {
276
276
  units: { ATA: [deviceData.DeviceID] }
277
277
  };
278
278
  method = 'POST';
279
- path = ApiUrlsHome.PostHolidayMode;
279
+ path = ApiUrls.Home.Post.HolidayMode;
280
280
  break;
281
281
  case 'schedule':
282
282
  payload = { enabled: deviceData.ScheduleEnabled };
283
283
  method = 'PUT';
284
- path = ApiUrlsHome.PutScheduleEnabled.replace('deviceid', deviceData.DeviceID);
284
+ path = ApiUrls.Home.Put.ScheduleEnableDisable.Home.replace('deviceid', deviceData.DeviceID);
285
285
  update = true;
286
286
  break;
287
287
  case 'scene':
288
288
  method = 'PUT';
289
- path = ApiUrlsHome.PutScene[flagData.Enabled ? 'Enable' : 'Disable'].replace('sceneid', flagData.Id);
289
+ path = `${ApiUrls.Home.Put.SceneEnableDisable.replace('sceneid', flagData.Id)}${flagData.Enabled ? 'enable' : 'disable'}`;
290
290
  break;
291
291
  default:
292
292
  if (displayType === 1 && deviceData.Device.OperationMode === 8) {
@@ -312,7 +312,7 @@ class MelCloudAta extends EventEmitter {
312
312
  inStandbyMode: null
313
313
  };
314
314
  method = 'PUT';
315
- path = ApiUrlsHome.PutAta.replace('deviceid', deviceData.DeviceID);
315
+ path = ApiUrls.Home.Put.Ata.replace('deviceid', deviceData.DeviceID);
316
316
  break;
317
317
  }
318
318
 
@@ -1,6 +1,6 @@
1
1
  import EventEmitter from 'events';
2
2
  import Functions from './functions.js';
3
- import { ApiUrls, ApiUrlsHome, HeatPump } from './constants.js';
3
+ import { ApiUrls, HeatPump } from './constants.js';
4
4
 
5
5
  class MelCloudAtw extends EventEmitter {
6
6
  constructor(account, device, defaultTempsFile, accountFile, melcloud) {
@@ -204,7 +204,7 @@ class MelCloudAtw extends EventEmitter {
204
204
  case 'account':
205
205
  flagData.Account.LoginData.UseFahrenheit = flagData.UseFahrenheit;
206
206
  payload = { data: flagData.LoginData };
207
- path = ApiUrls.UpdateApplicationOptions;
207
+ path = ApiUrls.Post.UpdateApplicationOptions;
208
208
  await this.functions.saveData(this.accountFile, flagData);
209
209
  break;
210
210
  default:
@@ -231,7 +231,7 @@ class MelCloudAtw extends EventEmitter {
231
231
  ProhibitHotWater: deviceData.Device.ProhibitHotWater,
232
232
  HasPendingCommand: true
233
233
  }
234
- path = ApiUrls.SetAtw;
234
+ path = ApiUrls.Post.Atw;
235
235
  update = true;
236
236
  break;
237
237
  }
@@ -255,7 +255,7 @@ class MelCloudAtw extends EventEmitter {
255
255
  units: { ATA: [deviceData.DeviceID] }
256
256
  };
257
257
  method = 'POST';
258
- path = ApiUrlsHome.PostProtectionFrost;
258
+ path = ApiUrls.Home.Post.ProtectionFrost;
259
259
  update = true;
260
260
  break;
261
261
  case 'holidaymode':
@@ -266,17 +266,17 @@ class MelCloudAtw extends EventEmitter {
266
266
  units: { ATW: [deviceData.DeviceID] }
267
267
  };
268
268
  method = 'POST';
269
- path = ApiUrlsHome.PostHolidayMode;
269
+ path = ApiUrls.Home.Post.HolidayMode;
270
270
  break;
271
271
  case 'schedule':
272
272
  payload = { enabled: deviceData.ScheduleEnabled };
273
273
  method = 'PUT';
274
- path = ApiUrlsHome.PutScheduleEnabled.replace('deviceid', deviceData.DeviceID);
274
+ path = ApiUrls.Home.Put.ScheduleEnableDisable.Home.replace('deviceid', deviceData.DeviceID);
275
275
  update = true;
276
276
  break;
277
277
  case 'scene':
278
278
  method = 'PUT';
279
- path = ApiUrlsHome.PutScene[flagData.Enabled ? 'Enable' : 'Disable'].replace('sceneid', flagData.Id);
279
+ path = `${ApiUrls.Home.Put.SceneEnableDisable.replace('sceneid', flagData.Id)}${flagData.Enabled ? 'enable' : 'disable'}`;
280
280
  break;
281
281
  default:
282
282
  payload = {
@@ -295,7 +295,7 @@ class MelCloudAtw extends EventEmitter {
295
295
  ecoHotWater: deviceData.Device.EcoHotWater,
296
296
  };
297
297
  method = 'PUT';
298
- path = ApiUrlsHome.PutAtw.replace('deviceid', deviceData.DeviceID);
298
+ path = ApiUrls.Home.Put.Atw.replace('deviceid', deviceData.DeviceID);
299
299
  break
300
300
  }
301
301
 
@@ -1,6 +1,6 @@
1
1
  import EventEmitter from 'events';
2
2
  import Functions from './functions.js';
3
- import { ApiUrls, ApiUrlsHome, Ventilation } from './constants.js';
3
+ import { ApiUrls, Ventilation } from './constants.js';
4
4
 
5
5
  class MelCloudErv extends EventEmitter {
6
6
  constructor(account, device, defaultTempsFile, accountFile, melcloud) {
@@ -189,7 +189,7 @@ class MelCloudErv extends EventEmitter {
189
189
  case 'account':
190
190
  flagData.Account.LoginData.UseFahrenheit = flagData.UseFahrenheit;
191
191
  payload = { data: flagData.LoginData };
192
- path = ApiUrls.UpdateApplicationOptions;
192
+ path = ApiUrls.Post.UpdateApplicationOptions;
193
193
  await this.functions.saveData(this.accountFile, flagData);
194
194
  break;
195
195
  default:
@@ -231,7 +231,7 @@ class MelCloudErv extends EventEmitter {
231
231
  NightPurgeMode: deviceData.Device.NightPurgeMode,
232
232
  HasPendingCommand: true
233
233
  }
234
- path = ApiUrls.SetErv;
234
+ path = ApiUrls.Post.Erv;
235
235
  update = true;
236
236
  break;
237
237
  }
@@ -255,17 +255,17 @@ class MelCloudErv extends EventEmitter {
255
255
  units: { ERV: [deviceData.DeviceID] }
256
256
  };
257
257
  method = 'POST';
258
- path = ApiUrlsHome.PostHolidayMode;
258
+ path = ApiUrls.Home.Post.HolidayMode;
259
259
  break;
260
260
  case 'schedule':
261
261
  payload = { enabled: deviceData.ScheduleEnabled };
262
262
  method = 'PUT';
263
- path = ApiUrlsHome.PutScheduleEnabled.replace('deviceid', deviceData.DeviceID);
263
+ path = ApiUrls.Home.Put.ScheduleEnableDisable.Home.replace('deviceid', deviceData.DeviceID);
264
264
  update = true;
265
265
  break;
266
266
  case 'scene':
267
267
  method = 'PUT';
268
- path = ApiUrlsHome.PutScene[flagData.Enabled ? 'Enable' : 'Disable'].replace('sceneid', flagData.Id);
268
+ path = `${ApiUrls.Home.Put.SceneEnableDisable.replace('sceneid', flagData.Id)}${flagData.Enabled ? 'enable' : 'disable'}`;
269
269
  break;
270
270
  default:
271
271
  if (displayType === 1 && deviceData.Device.VentilationMode === 2) {
@@ -288,7 +288,7 @@ class MelCloudErv extends EventEmitter {
288
288
  ventilationMode: Ventilation.VentilationModeMapEnumToString[deviceData.Device.VentilationMode],
289
289
  };
290
290
  method = 'PUT';
291
- path = ApiUrlsHome.PutErv.replace('deviceid', deviceData.DeviceID);
291
+ path = ApiUrls.Home.Put.Erv.replace('deviceid', deviceData.DeviceID);
292
292
  break
293
293
  }
294
294
 
@@ -1,4 +1,3 @@
1
- import fs from 'fs';
2
1
  import axios from 'axios';
3
2
  import WebSocket from 'ws';
4
3
  import { exec } from 'child_process';
@@ -7,7 +6,7 @@ import EventEmitter from 'events';
7
6
  import puppeteer from 'puppeteer';
8
7
  import ImpulseGenerator from './impulsegenerator.js';
9
8
  import Functions from './functions.js';
10
- import { ApiUrlsHome, LanguageLocaleMap } from './constants.js';
9
+ import { ApiUrls, LanguageLocaleMap } from './constants.js';
11
10
  const execPromise = promisify(exec);
12
11
 
13
12
  class MelCloudHome extends EventEmitter {
@@ -17,7 +16,6 @@ class MelCloudHome extends EventEmitter {
17
16
  this.user = account.user;
18
17
  this.passwd = account.passwd;
19
18
  this.language = account.language;
20
- this.logSuccess = account.log?.success;
21
19
  this.logWarn = account.log?.warn;
22
20
  this.logError = account.log?.error;
23
21
  this.logDebug = account.log?.debug;
@@ -79,7 +77,7 @@ class MelCloudHome extends EventEmitter {
79
77
  async checkScenesList() {
80
78
  try {
81
79
  if (this.logDebug) this.emit('debug', `Scanning for scenes`);
82
- const listScenesData = await this.client(ApiUrlsHome.GetUserScenes, { method: 'GET', });
80
+ const listScenesData = await this.client(ApiUrls.Home.Get.Scenes, { method: 'GET', });
83
81
 
84
82
  const scenesList = listScenesData.data;
85
83
  if (this.logDebug) this.emit('debug', `Scenes: ${JSON.stringify(scenesList, null, 2)}`);
@@ -111,7 +109,7 @@ class MelCloudHome extends EventEmitter {
111
109
  try {
112
110
  const devicesList = { State: false, Info: null, Devices: [], Scenes: [] }
113
111
  if (this.logDebug) this.emit('debug', `Scanning for devices`);
114
- const listDevicesData = await this.client(ApiUrlsHome.GetUserContext, { method: 'GET' });
112
+ const listDevicesData = await this.client(ApiUrls.Home.Get.ListDevices, { method: 'GET' });
115
113
 
116
114
  const userContext = listDevicesData.data;
117
115
  const buildings = userContext.buildings ?? [];
@@ -225,32 +223,36 @@ class MelCloudHome extends EventEmitter {
225
223
  try {
226
224
  const accountInfo = { State: false, Info: '', Account: {}, UseFahrenheit: false };
227
225
 
228
- // Get Chromium path
229
- let chromiumPath = await this.functions.ensureChromiumInstalled();
230
-
231
- // Fallback to Puppeteer's bundled Chromium
232
- if (!chromiumPath) {
233
- try {
234
- const puppeteerPath = puppeteer.executablePath();
235
- if (puppeteerPath && puppeteerPath.length > 0) {
236
- chromiumPath = puppeteerPath;
237
- if (this.logDebug) this.emit('debug', `Using Puppeteer bundled Chromium at ${chromiumPath}`);
238
- } else {
239
- accountInfo.Info = `Puppeteer returned empty Chromium path`;
226
+ // Get Chromium path from resolver
227
+ const chromiumInfo = await this.functions.ensureChromiumInstalled();
228
+ let chromiumPath = chromiumInfo.path;
229
+ const arch = chromiumInfo.arch;
230
+ const system = chromiumInfo.system;
231
+
232
+ // If path is found, use it
233
+ if (chromiumPath) {
234
+ if (!this.logDebug) this.emit('debug', `Using Chromium for ${system} (${arch}) at ${chromiumPath}`);
235
+ } else {
236
+ if (arch === 'arm') {
237
+ accountInfo.Info = `No Chromium found for ${system} (${arch}). Please install it manually and try again.`;
238
+ return accountInfo;
239
+ } else {
240
+ try {
241
+ chromiumPath = puppeteer.executablePath();
242
+ if (!this.logDebug) this.emit('debug', `Using Puppeteer Chromium for ${system} (${arch}) at ${chromiumPath}`);
243
+ } catch (error) {
244
+ accountInfo.Info = `No Puppeteer Chromium for ${system} (${arch}), error: ${error.message}`;
240
245
  return accountInfo;
241
246
  }
242
- } catch (error) {
243
- accountInfo.Info = `Failed to get Puppeteer Chromium path: ${error.message}`;
244
- return accountInfo;
245
247
  }
246
248
  }
247
249
 
248
250
  // Verify Chromium executable
249
251
  try {
250
252
  const { stdout } = await execPromise(`"${chromiumPath}" --version`);
251
- if (this.logDebug) this.emit('debug', `Chromium detected: ${stdout.trim()}`);
253
+ if (!this.logDebug) this.emit('debug', `Chromium for ${system} (${arch}) detected: ${stdout.trim()}`);
252
254
  } catch (error) {
253
- accountInfo.Info = `Chromium found at ${chromiumPath}, but cannot be executed: ${error.message}`;
255
+ accountInfo.Info = `Chromium for ${system} (${arch}) found at ${chromiumPath}, but execute error: ${error.message}. Please install it manually and try again.`;
254
256
  return accountInfo;
255
257
  }
256
258
 
@@ -282,22 +284,22 @@ class MelCloudHome extends EventEmitter {
282
284
  await client.send('Network.enable')
283
285
  client.on('Network.webSocketCreated', ({ url }) => {
284
286
  try {
285
- if (url.startsWith(`${ApiUrlsHome.WebSocketURL}`)) {
287
+ if (url.startsWith(`${ApiUrls.Home.WebSocket}`)) {
286
288
  const params = new URL(url).searchParams;
287
289
  const hash = params.get('hash');
288
290
  if (this.logDebug) this.emit('debug', `Web socket hash detected: ${hash}`);
289
291
 
290
- //web socket connection
292
+ // Web socket connection
291
293
  if (!this.connecting && !this.socketConnected) {
292
294
  this.connecting = true;
293
295
 
294
296
  try {
295
297
  const headers = {
296
- 'Origin': ApiUrlsHome.BaseURL,
298
+ 'Origin': ApiUrls.Home.Base,
297
299
  'Pragma': 'no-cache',
298
300
  'Cache-Control': 'no-cache'
299
301
  };
300
- const webSocket = new WebSocket(`${ApiUrlsHome.WebSocketURL}${hash}`, { headers: headers })
302
+ const webSocket = new WebSocket(`${ApiUrls.Home.WebSocket}${hash}`, { headers: headers })
301
303
  .on('error', (error) => {
302
304
  if (this.logError) this.emit('error', `Web socket error: ${error}`);
303
305
  try {
@@ -326,7 +328,7 @@ class MelCloudHome extends EventEmitter {
326
328
  })
327
329
  .on('message', (message) => {
328
330
  const parsedMessage = JSON.parse(message);
329
- if (this.logDebug) this.emit('debug', `Incoming message: ${JSON.stringify(parsedMessage, null, 2)}`);
331
+ if (!this.logDebug) this.emit('debug', `Incoming message: ${JSON.stringify(parsedMessage, null, 2)}`);
330
332
  if (parsedMessage.message === 'Forbidden') return;
331
333
 
332
334
  this.emit('webSocket', parsedMessage);
@@ -343,9 +345,9 @@ class MelCloudHome extends EventEmitter {
343
345
  });
344
346
 
345
347
  try {
346
- await page.goto(ApiUrlsHome.BaseURL, { waitUntil: ['domcontentloaded', 'networkidle2'], timeout: GLOBAL_TIMEOUT });
348
+ await page.goto(ApiUrls.Home.Base, { waitUntil: ['domcontentloaded', 'networkidle2'], timeout: GLOBAL_TIMEOUT });
347
349
  } catch (error) {
348
- accountInfo.Info = `Navigation to ${ApiUrlsHome.BaseURL} failed: ${error.message}`;
350
+ accountInfo.Info = `Navigation to ${ApiUrls.Home.Base} failed: ${error.message}`;
349
351
  return accountInfo;
350
352
  }
351
353
 
@@ -407,7 +409,7 @@ class MelCloudHome extends EventEmitter {
407
409
  'Accept-Language': LanguageLocaleMap[this.language],
408
410
  'Cookie': cookies,
409
411
  'Priority': 'u=3, i',
410
- 'Referer': ApiUrlsHome.Dashboard,
412
+ 'Referer': ApiUrls.Home.Dashboard,
411
413
  'Sec-Fetch-Dest': 'empty',
412
414
  'Sec-Fetch-Mode': 'cors',
413
415
  'Sec-Fetch-Site': 'same-origin',
@@ -416,10 +418,10 @@ class MelCloudHome extends EventEmitter {
416
418
  };
417
419
 
418
420
  this.client = axios.create({
419
- baseURL: ApiUrlsHome.BaseURL,
421
+ baseURL: ApiUrls.Home.Base,
420
422
  timeout: 30000,
421
423
  headers: headers
422
- })
424
+ });
423
425
  this.emit('client', this.client);
424
426
 
425
427
  accountInfo.State = true;