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

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.431",
4
+ "version": "4.0.0-beta.433",
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
@@ -1,9 +1,5 @@
1
1
  import fs from 'fs';
2
- import { exec } from 'child_process';
3
2
  import { promises as fsPromises } from 'fs';
4
- import { promisify } from 'util';
5
- import puppeteer from 'puppeteer-core';
6
- const execAsync = promisify(exec);
7
3
 
8
4
  class Functions {
9
5
  constructor() {
@@ -49,85 +45,111 @@ class Functions {
49
45
  }
50
46
  }
51
47
 
48
+ async ensureChromiumInstalled() {
49
+ let chromiumPath = '/usr/bin/chromium-browser';
52
50
 
53
- async ensureChromiumInstalled(logInfo, logWarn, logError) {
54
- let chromiumPath = '/usr/bin/chromium-browser';
55
-
51
+ try {
52
+ // --- Detect architecture ---
53
+ let arch = '';
56
54
  try {
57
- // --- Detect platform ---
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}`);
60
-
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}`);
63
-
64
- // --- macOS handling ---
65
- if (osName === 'Darwin') {
66
- logInfo && logInfo('Running on macOS — using Puppeteer bundled Chromium');
67
- chromiumPath = require('puppeteer-core').executablePath();
68
- logInfo && logInfo(`Chromium path: ${chromiumPath}`);
69
- return chromiumPath;
70
- }
55
+ arch = (await new Promise((res, rej) =>
56
+ require('child_process').exec('uname -m', (e, stdout) => e ? rej(e) : res(stdout))
57
+ )).trim();
58
+ if (this.logDebug) this.emit('debug', `Detected architecture: ${arch}`);
59
+ } catch (err) {
60
+ if (this.logWarn) this.emit('warn', `Failed to detect architecture: ${err.message}`);
61
+ }
71
62
 
72
- // --- Linux handling ---
73
- let linuxDistro = 'unknown';
74
- try {
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';
76
- } catch {
77
- logWarn && logWarn('/etc/os-release not found, skipping OS detection.');
78
- }
79
- logInfo && logInfo(`Linux distro: ${linuxDistro}`);
80
-
81
- // --- Check existing Chromium ---
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}`);
86
- return chromiumPath;
87
- }
63
+ // --- Detect OS ---
64
+ let osName = '';
65
+ try {
66
+ osName = (await new Promise((res, rej) =>
67
+ require('child_process').exec('uname -s', (e, stdout) => e ? rej(e) : res(stdout))
68
+ )).trim();
69
+ if (this.logDebug) this.emit('debug', `Detected OS: ${osName}`);
70
+ } catch (err) {
71
+ if (this.logWarn) this.emit('warn', `Failed to detect OS: ${err.message}`);
72
+ }
88
73
 
89
- logWarn && logWarn('Chromium not found. Attempting installation...');
74
+ // --- macOS fallback ---
75
+ if (osName === 'Darwin') {
76
+ if (this.logDebug) this.emit('debug', 'Running on macOS — using Puppeteer bundled Chromium');
77
+ chromiumPath = require('puppeteer-core').executablePath();
78
+ if (this.logDebug) this.emit('debug', `Chromium path: ${chromiumPath}`);
79
+ return chromiumPath;
80
+ }
90
81
 
91
- // --- Try apt-get ---
92
- try {
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()));
94
- chromiumPath = '/usr/bin/chromium-browser';
95
- logInfo && logInfo('Chromium installed successfully via apt-get.');
96
- return chromiumPath;
97
- } catch {
98
- logWarn && logWarn('apt-get install failed. Trying apk or yum...');
99
- }
82
+ // --- Linux distro detection ---
83
+ let linuxDistro = 'unknown';
84
+ try {
85
+ linuxDistro = (await new Promise((res, rej) =>
86
+ require('child_process').exec('cat /etc/os-release', (e, stdout) => e ? rej(e) : res(stdout))
87
+ )).split('\n')[0] || 'unknown';
88
+ } catch {
89
+ if (this.logWarn) this.emit('warn', '/etc/os-release not found, skipping OS detection.');
90
+ }
91
+ if (this.logDebug) this.emit('debug', `Linux distro: ${linuxDistro}`);
92
+
93
+ // --- Check if Chromium exists ---
94
+ const chromiumCheck = (await new Promise((res) =>
95
+ require('child_process').exec('which chromium || which chromium-browser || true', (e, stdout) => res(stdout))
96
+ )).trim();
97
+ if (chromiumCheck) {
98
+ chromiumPath = chromiumCheck;
99
+ if (this.logDebug) this.emit('debug', `Found system Chromium: ${chromiumPath}`);
100
+ return chromiumPath;
101
+ }
100
102
 
101
- // --- Try Alpine APK ---
102
- try {
103
- await new Promise((res, rej) => require('child_process').exec('sudo apk add --no-cache chromium ffmpeg', (e) => e ? rej(e) : res()));
104
- chromiumPath = '/usr/bin/chromium-browser';
105
- logInfo && logInfo('Chromium installed successfully via apk.');
106
- return chromiumPath;
107
- } catch {
108
- logWarn && logWarn('apk install failed. Trying yum...');
109
- }
103
+ if (this.logWarn) this.emit('warn', 'Chromium not found. Attempting installation...');
110
104
 
111
- // --- Try YUM ---
112
- try {
113
- await new Promise((res, rej) => require('child_process').exec('sudo yum install -y chromium chromium-codecs-ffmpeg', (e) => e ? rej(e) : res()));
114
- chromiumPath = '/usr/bin/chromium-browser';
115
- logInfo && logInfo('Chromium installed successfully via yum.');
116
- return chromiumPath;
117
- } catch {
118
- logWarn && logWarn('yum install failed. Falling back to Puppeteer bundled Chromium.');
119
- }
105
+ // --- apt-get ---
106
+ try {
107
+ await new Promise((res, rej) =>
108
+ require('child_process').exec('sudo apt-get update -y && sudo apt-get install -y chromium-browser chromium-codecs-ffmpeg', (e) => e ? rej(e) : res())
109
+ );
110
+ chromiumPath = '/usr/bin/chromium-browser';
111
+ if (this.logDebug) this.emit('debug', 'Chromium installed successfully via apt-get.');
112
+ return chromiumPath;
113
+ } catch {
114
+ if (this.logWarn) this.emit('warn', 'apt-get install failed. Trying apk or yum...');
115
+ }
120
116
 
121
- // --- Fallback: Puppeteer Chromium ---
122
- chromiumPath = require('puppeteer-core').executablePath();
123
- logWarn && logWarn(`Using bundled Puppeteer Chromium at ${chromiumPath}`);
117
+ // --- apk (Alpine) ---
118
+ try {
119
+ await new Promise((res, rej) =>
120
+ require('child_process').exec('sudo apk add --no-cache chromium ffmpeg', (e) => e ? rej(e) : res())
121
+ );
122
+ chromiumPath = '/usr/bin/chromium-browser';
123
+ if (this.logDebug) this.emit('debug', 'Chromium installed successfully via apk.');
124
124
  return chromiumPath;
125
+ } catch {
126
+ if (this.logWarn) this.emit('warn', 'apk install failed. Trying yum...');
127
+ }
125
128
 
126
- } catch (err) {
127
- logError && logError(`Chromium detection/install error: ${err.message}`);
128
- throw err;
129
+ // --- yum (RHEL/CentOS) ---
130
+ try {
131
+ await new Promise((res, rej) =>
132
+ require('child_process').exec('sudo yum install -y chromium chromium-codecs-ffmpeg', (e) => e ? rej(e) : res())
133
+ );
134
+ chromiumPath = '/usr/bin/chromium-browser';
135
+ if (this.logDebug) this.emit('debug', 'Chromium installed successfully via yum.');
136
+ return chromiumPath;
137
+ } catch {
138
+ if (this.logWarn) this.emit('warn', 'yum install failed. Falling back to Puppeteer bundled Chromium.');
129
139
  }
140
+
141
+ // --- Fallback ---
142
+ chromiumPath = require('puppeteer-core').executablePath();
143
+ if (this.logWarn) this.emit('warn', `Using bundled Puppeteer Chromium at ${chromiumPath}`);
144
+ return chromiumPath;
145
+
146
+ } catch (err) {
147
+ if (this.logError) this.emit('error', `Chromium detection/install error: ${err.message}`);
148
+ throw err;
130
149
  }
150
+ }
151
+
152
+
131
153
 
132
154
  async isRunningInDocker() {
133
155
  try {
package/src/melcloud.js CHANGED
@@ -322,18 +322,18 @@ class MelCloud extends EventEmitter {
322
322
  }
323
323
  }
324
324
 
325
- async connectToMelCloudHome(user, passwd, functions, ApiUrlsHome, accountFile, logDebug, logWarn, logError, logSuccess, refresh = false) {
326
- if (logDebug) logDebug('Connecting to MELCloud Home');
325
+ async connectToMelCloudHome(refresh = false) {
326
+ if (this.logDebug) this.emit('debug', 'Connecting to MELCloud Home');
327
+
327
328
  let browser;
328
329
 
329
330
  try {
330
- const chromiumPath = await ensureChromiumInstalled(
331
- msg => logDebug && logDebug(msg),
332
- msg => logWarn && logWarn(msg),
333
- msg => logError && logError(msg)
334
- );
331
+ const chromiumPath = await this.ensureChromiumInstalled();
332
+
333
+ // dynamiczny require dopiero przy uruchomieniu
334
+ const puppeteer = require('puppeteer-core');
335
335
 
336
- browser = await require('puppeteer-core').launch({
336
+ browser = await puppeteer.launch({
337
337
  headless: true,
338
338
  executablePath: chromiumPath,
339
339
  args: [
@@ -347,15 +347,15 @@ class MelCloud extends EventEmitter {
347
347
 
348
348
  const page = await browser.newPage();
349
349
 
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'));
350
+ page.on('error', err => { if (this.logError) this.emit('error', `Page crashed: ${err.message}`); });
351
+ page.on('pageerror', err => { if (this.logError) this.emit('error', `Browser error: ${err.message}`); });
352
+ page.on('close', () => { if (this.logDebug) this.emit('debug', 'Page was closed unexpectedly'); });
353
+ browser.on('disconnected', () => { if (this.logDebug) this.emit('debug', 'Browser disconnected unexpectedly'); });
354
354
 
355
355
  page.setDefaultTimeout(30000);
356
356
  page.setDefaultNavigationTimeout(30000);
357
357
 
358
- await page.goto(ApiUrlsHome.BaseURL, { waitUntil: ['domcontentloaded', 'networkidle2'] });
358
+ await page.goto(this.ApiUrlsHome.BaseURL, { waitUntil: ['domcontentloaded', 'networkidle2'] });
359
359
 
360
360
  const buttons = await page.$$('button.btn--blue');
361
361
  let loginBtn = null;
@@ -367,7 +367,7 @@ class MelCloud extends EventEmitter {
367
367
  }
368
368
  }
369
369
  if (!loginBtn) {
370
- logWarn && logWarn('Login button not found');
370
+ this.emit('warn', 'Login button not found');
371
371
  return null;
372
372
  }
373
373
 
@@ -382,16 +382,16 @@ class MelCloud extends EventEmitter {
382
382
  const usernameInput = await page.$('input[name="username"]');
383
383
  const passwordInput = await page.$('input[name="password"]');
384
384
  if (!usernameInput || !passwordInput) {
385
- logWarn && logWarn('Username or password input not found');
385
+ this.emit('warn', 'Username or password input not found');
386
386
  return null;
387
387
  }
388
388
 
389
- await page.type('input[name="username"]', user, { delay: 50 });
390
- await page.type('input[name="password"]', passwd, { delay: 50 });
389
+ await page.type('input[name="username"]', this.user, { delay: 50 });
390
+ await page.type('input[name="password"]', this.passwd, { delay: 50 });
391
391
 
392
392
  const submitButton = await page.$('input[type="submit"], button[type="submit"]');
393
393
  if (!submitButton) {
394
- logWarn && logWarn('Submit button not found on login form');
394
+ this.emit('warn', 'Submit button not found on login form');
395
395
  return null;
396
396
  }
397
397
 
@@ -413,7 +413,7 @@ class MelCloud extends EventEmitter {
413
413
  }
414
414
 
415
415
  if (!c1 || !c2) {
416
- logWarn && logWarn('Cookies C1/C2 missing after login');
416
+ this.emit('warn', 'Cookies C1/C2 missing after login');
417
417
  return null;
418
418
  }
419
419
 
@@ -424,9 +424,11 @@ class MelCloud extends EventEmitter {
424
424
  ].join('; ');
425
425
 
426
426
  const accountInfo = { ContextKey: contextKey, UseFahrenheit: false };
427
- await functions.saveData(accountFile, accountInfo);
427
+ this.contextKey = contextKey;
428
428
 
429
- if (!refresh && logSuccess) logSuccess('Connect to MELCloud Home Success');
429
+ await this.functions.saveData(this.accountFile, accountInfo);
430
+
431
+ if (!refresh) this.emit('success', 'Connect to MELCloud Home Success');
430
432
  return accountInfo;
431
433
 
432
434
  } catch (error) {
@@ -434,11 +436,12 @@ class MelCloud extends EventEmitter {
434
436
  } finally {
435
437
  if (browser) {
436
438
  try { await browser.close(); }
437
- catch (closeErr) { logError && logError(`Failed to close Puppeteer browser: ${closeErr.message}`); }
439
+ catch (closeErr) { if (this.logError) this.emit('error', `Failed to close Puppeteer browser: ${closeErr.message}`); }
438
440
  }
439
441
  }
440
442
  }
441
443
 
444
+
442
445
  async checkDevicesList() {
443
446
  let devices = [];
444
447
  switch (this.accountType) {