homebridge-melcloud-control 4.0.0-beta.430 → 4.0.0-beta.431

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "MELCloud Control",
3
3
  "name": "homebridge-melcloud-control",
4
- "version": "4.0.0-beta.430",
4
+ "version": "4.0.0-beta.431",
5
5
  "description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
package/src/functions.js CHANGED
@@ -51,89 +51,84 @@ class Functions {
51
51
 
52
52
 
53
53
  async ensureChromiumInstalled(logInfo, logWarn, logError) {
54
- let chromiumPath = '/usr/bin/chromium-browser'; // default fallback Linux
54
+ let chromiumPath = '/usr/bin/chromium-browser';
55
55
 
56
56
  try {
57
57
  // --- Detect platform ---
58
- const { stdout: archStdout } = await execAsync('uname -m');
59
- const arch = archStdout.trim();
60
- logInfo(`Detected architecture: ${arch}`);
58
+ const arch = (await new Promise((res, rej) => require('child_process').exec('uname -m', (e, stdout) => e ? rej(e) : res(stdout)))).trim();
59
+ logInfo && logInfo(`Detected architecture: ${arch}`);
61
60
 
62
- const { stdout: osNameStdout } = await execAsync('uname -s');
63
- const osName = osNameStdout.trim();
64
- logInfo(`Detected OS: ${osName}`);
61
+ const osName = (await new Promise((res, rej) => require('child_process').exec('uname -s', (e, stdout) => e ? rej(e) : res(stdout)))).trim();
62
+ logInfo && logInfo(`Detected OS: ${osName}`);
65
63
 
66
64
  // --- macOS handling ---
67
65
  if (osName === 'Darwin') {
68
- logInfo('Running on macOS — using Puppeteer bundled Chromium');
69
- chromiumPath = puppeteer.executablePath();
70
- logInfo(`Chromium path: ${chromiumPath}`);
66
+ logInfo && logInfo('Running on macOS — using Puppeteer bundled Chromium');
67
+ chromiumPath = require('puppeteer-core').executablePath();
68
+ logInfo && logInfo(`Chromium path: ${chromiumPath}`);
71
69
  return chromiumPath;
72
70
  }
73
71
 
74
72
  // --- Linux handling ---
75
- // Detect OS release if available
76
73
  let linuxDistro = 'unknown';
77
74
  try {
78
- const { stdout: osRelease } = await execAsync('cat /etc/os-release');
79
- linuxDistro = osRelease.split('\n')[0] || 'unknown';
75
+ linuxDistro = (await new Promise((res, rej) => require('child_process').exec('cat /etc/os-release', (e, stdout) => e ? rej(e) : res(stdout)))).split('\n')[0] || 'unknown';
80
76
  } catch {
81
- logWarn('/etc/os-release not found, skipping OS detection.');
77
+ logWarn && logWarn('/etc/os-release not found, skipping OS detection.');
82
78
  }
83
- logInfo(`Linux distro: ${linuxDistro}`);
79
+ logInfo && logInfo(`Linux distro: ${linuxDistro}`);
84
80
 
85
81
  // --- Check existing Chromium ---
86
- const { stdout: chromiumCheck } = await execAsync('which chromium || which chromium-browser || true');
87
- if (chromiumCheck.trim()) {
88
- chromiumPath = chromiumCheck.trim();
89
- logInfo(`Found system Chromium: ${chromiumPath}`);
82
+ const chromiumCheck = (await new Promise((res) => require('child_process').exec('which chromium || which chromium-browser || true', (e, stdout) => res(stdout)))).trim();
83
+ if (chromiumCheck) {
84
+ chromiumPath = chromiumCheck;
85
+ logInfo && logInfo(`Found system Chromium: ${chromiumPath}`);
90
86
  return chromiumPath;
91
87
  }
92
88
 
93
- logWarn('Chromium not found. Attempting installation...');
89
+ logWarn && logWarn('Chromium not found. Attempting installation...');
94
90
 
95
- // --- Try apt-get first ---
91
+ // --- Try apt-get ---
96
92
  try {
97
- await execAsync('sudo apt-get update -y && sudo apt-get install -y chromium-browser chromium-codecs-ffmpeg');
93
+ await new Promise((res, rej) => require('child_process').exec('sudo apt-get update -y && sudo apt-get install -y chromium-browser chromium-codecs-ffmpeg', (e) => e ? rej(e) : res()));
98
94
  chromiumPath = '/usr/bin/chromium-browser';
99
- logInfo('Chromium installed successfully via apt-get.');
95
+ logInfo && logInfo('Chromium installed successfully via apt-get.');
100
96
  return chromiumPath;
101
- } catch (aptErr) {
102
- logWarn('apt-get install failed. Trying apk (Alpine) or yum (RHEL/CentOS)...');
97
+ } catch {
98
+ logWarn && logWarn('apt-get install failed. Trying apk or yum...');
103
99
  }
104
100
 
105
101
  // --- Try Alpine APK ---
106
102
  try {
107
- await execAsync('sudo apk add --no-cache chromium ffmpeg');
103
+ await new Promise((res, rej) => require('child_process').exec('sudo apk add --no-cache chromium ffmpeg', (e) => e ? rej(e) : res()));
108
104
  chromiumPath = '/usr/bin/chromium-browser';
109
- logInfo('Chromium installed successfully via apk.');
105
+ logInfo && logInfo('Chromium installed successfully via apk.');
110
106
  return chromiumPath;
111
- } catch (apkErr) {
112
- logWarn('apk install failed. Trying yum (RHEL/CentOS)...');
107
+ } catch {
108
+ logWarn && logWarn('apk install failed. Trying yum...');
113
109
  }
114
110
 
115
111
  // --- Try YUM ---
116
112
  try {
117
- await execAsync('sudo yum install -y chromium chromium-codecs-ffmpeg');
113
+ await new Promise((res, rej) => require('child_process').exec('sudo yum install -y chromium chromium-codecs-ffmpeg', (e) => e ? rej(e) : res()));
118
114
  chromiumPath = '/usr/bin/chromium-browser';
119
- logInfo('Chromium installed successfully via yum.');
115
+ logInfo && logInfo('Chromium installed successfully via yum.');
120
116
  return chromiumPath;
121
- } catch (yumErr) {
122
- logWarn('yum install failed. Falling back to Puppeteer bundled Chromium.');
117
+ } catch {
118
+ logWarn && logWarn('yum install failed. Falling back to Puppeteer bundled Chromium.');
123
119
  }
124
120
 
125
121
  // --- Fallback: Puppeteer Chromium ---
126
- chromiumPath = puppeteer.executablePath();
127
- logWarn(`Using bundled Puppeteer Chromium at ${chromiumPath}`);
122
+ chromiumPath = require('puppeteer-core').executablePath();
123
+ logWarn && logWarn(`Using bundled Puppeteer Chromium at ${chromiumPath}`);
128
124
  return chromiumPath;
129
125
 
130
126
  } catch (err) {
131
- logError(`Chromium detection/install error: ${err.message}`);
127
+ logError && logError(`Chromium detection/install error: ${err.message}`);
132
128
  throw err;
133
129
  }
134
130
  }
135
131
 
136
-
137
132
  async isRunningInDocker() {
138
133
  try {
139
134
  if (fs.existsSync('/.dockerenv')) return true;
package/src/melcloud.js CHANGED
@@ -322,19 +322,18 @@ class MelCloud extends EventEmitter {
322
322
  }
323
323
  }
324
324
 
325
- async connectToMelCloudHome(refresh = false) {
326
- if (this.logDebug) this.emit('debug', `Connecting to MELCloud Home`);
325
+ async connectToMelCloudHome(user, passwd, functions, ApiUrlsHome, accountFile, logDebug, logWarn, logError, logSuccess, refresh = false) {
326
+ if (logDebug) logDebug('Connecting to MELCloud Home');
327
327
  let browser;
328
328
 
329
329
  try {
330
- // --- System Detection & Chromium install ---
331
- const chromiumPath = await this.functions.ensureChromiumInstalled(
332
- msg => this.emit('debug', msg),
333
- msg => this.emit('warn', msg),
334
- msg => this.emit('error', msg)
330
+ const chromiumPath = await ensureChromiumInstalled(
331
+ msg => logDebug && logDebug(msg),
332
+ msg => logWarn && logWarn(msg),
333
+ msg => logError && logError(msg)
335
334
  );
336
335
 
337
- const launchOptions = {
336
+ browser = await require('puppeteer-core').launch({
338
337
  headless: true,
339
338
  executablePath: chromiumPath,
340
339
  args: [
@@ -344,24 +343,20 @@ class MelCloud extends EventEmitter {
344
343
  '--single-process',
345
344
  '--no-zygote'
346
345
  ]
347
- };
346
+ });
348
347
 
349
- browser = await puppeteer.launch(launchOptions);
350
348
  const page = await browser.newPage();
351
349
 
352
- // --- Event handlers ---
353
- page.on('error', err => this.emit('error', `Page crashed: ${err.message}`));
354
- page.on('pageerror', err => this.emit('error', `Browser error: ${err.message}`));
355
- page.on('close', () => this.emit('debug', 'Page was closed unexpectedly'));
356
- browser.on('disconnected', () => this.emit('debug', 'Browser disconnected unexpectedly'));
350
+ page.on('error', err => logError && logError(`Page crashed: ${err.message}`));
351
+ page.on('pageerror', err => logError && logError(`Browser error: ${err.message}`));
352
+ page.on('close', () => logDebug && logDebug('Page was closed unexpectedly'));
353
+ browser.on('disconnected', () => logDebug && logDebug('Browser disconnected unexpectedly'));
357
354
 
358
355
  page.setDefaultTimeout(30000);
359
356
  page.setDefaultNavigationTimeout(30000);
360
357
 
361
- // --- Go to login page ---
362
358
  await page.goto(ApiUrlsHome.BaseURL, { waitUntil: ['domcontentloaded', 'networkidle2'] });
363
359
 
364
- // --- Login flow ---
365
360
  const buttons = await page.$$('button.btn--blue');
366
361
  let loginBtn = null;
367
362
  for (const btn of buttons) {
@@ -372,7 +367,7 @@ class MelCloud extends EventEmitter {
372
367
  }
373
368
  }
374
369
  if (!loginBtn) {
375
- this.emit('warn', 'Login button not found');
370
+ logWarn && logWarn('Login button not found');
376
371
  return null;
377
372
  }
378
373
 
@@ -384,20 +379,19 @@ class MelCloud extends EventEmitter {
384
379
  new Promise(r => setTimeout(r, 12000))
385
380
  ]);
386
381
 
387
- // --- Credentials ---
388
382
  const usernameInput = await page.$('input[name="username"]');
389
383
  const passwordInput = await page.$('input[name="password"]');
390
384
  if (!usernameInput || !passwordInput) {
391
- this.emit('warn', 'Username or password input not found');
385
+ logWarn && logWarn('Username or password input not found');
392
386
  return null;
393
387
  }
394
388
 
395
- await page.type('input[name="username"]', this.user, { delay: 50 });
396
- await page.type('input[name="password"]', this.passwd, { delay: 50 });
389
+ await page.type('input[name="username"]', user, { delay: 50 });
390
+ await page.type('input[name="password"]', passwd, { delay: 50 });
397
391
 
398
392
  const submitButton = await page.$('input[type="submit"], button[type="submit"]');
399
393
  if (!submitButton) {
400
- this.emit('warn', 'Submit button not found on login form');
394
+ logWarn && logWarn('Submit button not found on login form');
401
395
  return null;
402
396
  }
403
397
 
@@ -409,7 +403,6 @@ class MelCloud extends EventEmitter {
409
403
  new Promise(r => setTimeout(r, 15000))
410
404
  ]);
411
405
 
412
- // --- Cookie extraction ---
413
406
  let c1 = null, c2 = null;
414
407
  const start = Date.now();
415
408
  while ((!c1 || !c2) && Date.now() - start < 20000) {
@@ -420,7 +413,7 @@ class MelCloud extends EventEmitter {
420
413
  }
421
414
 
422
415
  if (!c1 || !c2) {
423
- this.emit('warn', 'Cookies C1/C2 missing after login');
416
+ logWarn && logWarn('Cookies C1/C2 missing after login');
424
417
  return null;
425
418
  }
426
419
 
@@ -431,21 +424,17 @@ class MelCloud extends EventEmitter {
431
424
  ].join('; ');
432
425
 
433
426
  const accountInfo = { ContextKey: contextKey, UseFahrenheit: false };
434
- this.contextKey = contextKey;
435
- await this.functions.saveData(this.accountFile, accountInfo);
427
+ await functions.saveData(accountFile, accountInfo);
436
428
 
437
- if (!refresh) this.emit('success', `Connect to MELCloud Home Success`);
429
+ if (!refresh && logSuccess) logSuccess('Connect to MELCloud Home Success');
438
430
  return accountInfo;
439
431
 
440
432
  } catch (error) {
441
433
  throw new Error(`Connect error: ${error.message}`);
442
434
  } finally {
443
435
  if (browser) {
444
- try {
445
- await browser.close();
446
- } catch (closeErr) {
447
- this.emit('error', `Failed to close Puppeteer browser: ${closeErr.message}`);
448
- }
436
+ try { await browser.close(); }
437
+ catch (closeErr) { logError && logError(`Failed to close Puppeteer browser: ${closeErr.message}`); }
449
438
  }
450
439
  }
451
440
  }