homebridge-melcloud-control 4.4.1-beta.5 → 4.4.1-beta.50

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.
@@ -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)}`);
@@ -109,9 +107,9 @@ class MelCloudHome extends EventEmitter {
109
107
 
110
108
  async checkDevicesList() {
111
109
  try {
112
- const devicesList = { State: false, Info: null, Devices: [], Scenes: [] }
110
+ const devicesList = { State: false, Info: null, Buildings: {}, 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 ?? [];
@@ -124,9 +122,6 @@ class MelCloudHome extends EventEmitter {
124
122
  return devicesList;
125
123
  }
126
124
 
127
- await this.functions.saveData(this.buildingsFile, userContext);
128
- if (this.logDebug) this.emit('debug', `Buildings list saved`);
129
-
130
125
  const devices = buildingsList.flatMap(building => {
131
126
  // Funkcja kapitalizująca klucze obiektu
132
127
  const capitalizeKeys = obj => Object.fromEntries(Object.entries(obj).map(([key, value]) => [key.charAt(0).toUpperCase() + key.slice(1), value]));
@@ -207,8 +202,13 @@ class MelCloudHome extends EventEmitter {
207
202
 
208
203
  devicesList.State = true;
209
204
  devicesList.Info = `Found ${devicesCount} devices ${scenes.length > 0 ? `and ${scenes.length} scenes` : ''}`;
205
+ devicesList.Buildings = userContext;
210
206
  devicesList.Devices = devices;
211
207
  devicesList.Scenes = scenes;
208
+
209
+ await this.functions.saveData(this.buildingsFile, devicesList);
210
+ if (this.logDebug) this.emit('debug', `Buildings list saved`);
211
+
212
212
  this.emit('devicesList', devicesList);
213
213
 
214
214
  return devicesList;
@@ -225,32 +225,36 @@ class MelCloudHome extends EventEmitter {
225
225
  try {
226
226
  const accountInfo = { State: false, Info: '', Account: {}, UseFahrenheit: false };
227
227
 
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`;
228
+ // Get Chromium path from resolver
229
+ const chromiumInfo = await this.functions.ensureChromiumInstalled();
230
+ let chromiumPath = chromiumInfo.path;
231
+ const arch = chromiumInfo.arch;
232
+ const system = chromiumInfo.system;
233
+
234
+ // If path is found, use it
235
+ if (chromiumPath) {
236
+ if (!this.logDebug) this.emit('debug', `Using Chromium for ${system} (${arch}) at ${chromiumPath}`);
237
+ } else {
238
+ if (arch === 'arm') {
239
+ accountInfo.Info = `No Chromium found for ${system} (${arch}). Please install it manually and try again.`;
240
+ return accountInfo;
241
+ } else {
242
+ try {
243
+ chromiumPath = puppeteer.executablePath();
244
+ if (!this.logDebug) this.emit('debug', `Using Puppeteer Chromium for ${system} (${arch}) at ${chromiumPath}`);
245
+ } catch (error) {
246
+ accountInfo.Info = `No Puppeteer Chromium for ${system} (${arch}), error: ${error.message}`;
240
247
  return accountInfo;
241
248
  }
242
- } catch (error) {
243
- accountInfo.Info = `Failed to get Puppeteer Chromium path: ${error.message}`;
244
- return accountInfo;
245
249
  }
246
250
  }
247
251
 
248
252
  // Verify Chromium executable
249
253
  try {
250
254
  const { stdout } = await execPromise(`"${chromiumPath}" --version`);
251
- if (this.logDebug) this.emit('debug', `Chromium detected: ${stdout.trim()}`);
255
+ if (!this.logDebug) this.emit('debug', `Chromium for ${system} (${arch}) detected: ${stdout.trim()}`);
252
256
  } catch (error) {
253
- accountInfo.Info = `Chromium found at ${chromiumPath}, but cannot be executed: ${error.message}`;
257
+ accountInfo.Info = `Chromium for ${system} (${arch}) found at ${chromiumPath}, but execute error: ${error.message}. Please install it manually and try again.`;
254
258
  return accountInfo;
255
259
  }
256
260
 
@@ -282,22 +286,22 @@ class MelCloudHome extends EventEmitter {
282
286
  await client.send('Network.enable')
283
287
  client.on('Network.webSocketCreated', ({ url }) => {
284
288
  try {
285
- if (url.startsWith(`${ApiUrlsHome.WebSocketURL}`)) {
289
+ if (url.startsWith(`${ApiUrls.Home.WebSocket}`)) {
286
290
  const params = new URL(url).searchParams;
287
291
  const hash = params.get('hash');
288
292
  if (this.logDebug) this.emit('debug', `Web socket hash detected: ${hash}`);
289
293
 
290
- //web socket connection
294
+ // Web socket connection
291
295
  if (!this.connecting && !this.socketConnected) {
292
296
  this.connecting = true;
293
297
 
294
298
  try {
295
299
  const headers = {
296
- 'Origin': ApiUrlsHome.BaseURL,
300
+ 'Origin': ApiUrls.Home.Base,
297
301
  'Pragma': 'no-cache',
298
302
  'Cache-Control': 'no-cache'
299
303
  };
300
- const webSocket = new WebSocket(`${ApiUrlsHome.WebSocketURL}${hash}`, { headers: headers })
304
+ const webSocket = new WebSocket(`${ApiUrls.Home.WebSocket}${hash}`, { headers: headers })
301
305
  .on('error', (error) => {
302
306
  if (this.logError) this.emit('error', `Web socket error: ${error}`);
303
307
  try {
@@ -326,7 +330,7 @@ class MelCloudHome extends EventEmitter {
326
330
  })
327
331
  .on('message', (message) => {
328
332
  const parsedMessage = JSON.parse(message);
329
- if (this.logDebug) this.emit('debug', `Incoming message: ${JSON.stringify(parsedMessage, null, 2)}`);
333
+ if (!this.logDebug) this.emit('debug', `Incoming message: ${JSON.stringify(parsedMessage, null, 2)}`);
330
334
  if (parsedMessage.message === 'Forbidden') return;
331
335
 
332
336
  this.emit('webSocket', parsedMessage);
@@ -343,9 +347,9 @@ class MelCloudHome extends EventEmitter {
343
347
  });
344
348
 
345
349
  try {
346
- await page.goto(ApiUrlsHome.BaseURL, { waitUntil: ['domcontentloaded', 'networkidle2'], timeout: GLOBAL_TIMEOUT });
350
+ await page.goto(ApiUrls.Home.Base, { waitUntil: ['domcontentloaded', 'networkidle2'], timeout: GLOBAL_TIMEOUT });
347
351
  } catch (error) {
348
- accountInfo.Info = `Navigation to ${ApiUrlsHome.BaseURL} failed: ${error.message}`;
352
+ accountInfo.Info = `Navigation to ${ApiUrls.Home.Base} failed: ${error.message}`;
349
353
  return accountInfo;
350
354
  }
351
355
 
@@ -407,7 +411,7 @@ class MelCloudHome extends EventEmitter {
407
411
  'Accept-Language': LanguageLocaleMap[this.language],
408
412
  'Cookie': cookies,
409
413
  'Priority': 'u=3, i',
410
- 'Referer': ApiUrlsHome.Dashboard,
414
+ 'Referer': ApiUrls.Home.Dashboard,
411
415
  'Sec-Fetch-Dest': 'empty',
412
416
  'Sec-Fetch-Mode': 'cors',
413
417
  'Sec-Fetch-Site': 'same-origin',
@@ -416,10 +420,10 @@ class MelCloudHome extends EventEmitter {
416
420
  };
417
421
 
418
422
  this.client = axios.create({
419
- baseURL: ApiUrlsHome.BaseURL,
423
+ baseURL: ApiUrls.Home.Base,
420
424
  timeout: 30000,
421
425
  headers: headers
422
- })
426
+ });
423
427
  this.emit('client', this.client);
424
428
 
425
429
  accountInfo.State = true;