homebridge-melcloud-control 4.0.0-beta.412 → 4.0.0-beta.413
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 +1 -1
- package/src/melcloud.js +63 -29
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.
|
|
4
|
+
"version": "4.0.0-beta.413",
|
|
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/melcloud.js
CHANGED
|
@@ -331,25 +331,29 @@ class MelCloud extends EventEmitter {
|
|
|
331
331
|
try {
|
|
332
332
|
browser = await puppeteer.launch({
|
|
333
333
|
headless: true,
|
|
334
|
-
args: [
|
|
334
|
+
args: [
|
|
335
|
+
'--no-sandbox',
|
|
336
|
+
'--disable-setuid-sandbox',
|
|
337
|
+
'--disable-dev-shm-usage',
|
|
338
|
+
'--single-process',
|
|
339
|
+
'--no-zygote'
|
|
340
|
+
]
|
|
335
341
|
});
|
|
336
342
|
|
|
337
343
|
const page = await browser.newPage();
|
|
338
344
|
|
|
339
|
-
// Emit page errors to logs
|
|
340
345
|
page.on('error', err => this.emit('warn', `Page crashed: ${err.message}`));
|
|
341
346
|
page.on('pageerror', err => this.emit('warn', `Browser error: ${err.message}`));
|
|
347
|
+
page.on('close', () => this.emit('warn', 'Page was closed unexpectedly'));
|
|
348
|
+
browser.on('disconnected', () => this.emit('warn', 'Browser disconnected unexpectedly'));
|
|
342
349
|
|
|
343
|
-
|
|
350
|
+
page.setDefaultTimeout(30000);
|
|
351
|
+
page.setDefaultNavigationTimeout(30000);
|
|
344
352
|
|
|
345
|
-
|
|
346
|
-
await page.waitForSelector('button.btn--blue', { timeout: 10000 }).catch(() => {
|
|
347
|
-
throw new Error('Login button not found on MELCloud Home');
|
|
348
|
-
});
|
|
353
|
+
await page.goto(ApiUrlsHome.BaseURL, { waitUntil: ['domcontentloaded', 'networkidle2'] });
|
|
349
354
|
|
|
350
355
|
const buttons = await page.$$('button.btn--blue');
|
|
351
356
|
let loginBtn = null;
|
|
352
|
-
|
|
353
357
|
for (const btn of buttons) {
|
|
354
358
|
const text = await page.evaluate(el => el.textContent.trim(), btn);
|
|
355
359
|
if (['Zaloguj', 'Sign In', 'Login'].includes(text)) {
|
|
@@ -357,44 +361,70 @@ class MelCloud extends EventEmitter {
|
|
|
357
361
|
break;
|
|
358
362
|
}
|
|
359
363
|
}
|
|
364
|
+
if (!loginBtn) {
|
|
365
|
+
this.emit('warn', 'Login button not found');
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
360
368
|
|
|
361
|
-
if (
|
|
362
|
-
|
|
363
|
-
|
|
369
|
+
if (page.isClosed()) {
|
|
370
|
+
this.emit('warn', 'Page closed before login click');
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
364
373
|
|
|
365
|
-
await Promise.
|
|
366
|
-
|
|
367
|
-
|
|
374
|
+
await Promise.race([
|
|
375
|
+
Promise.all([
|
|
376
|
+
loginBtn.click(),
|
|
377
|
+
page.waitForNavigation({ waitUntil: ['domcontentloaded', 'networkidle2'], timeout: 15000 })
|
|
378
|
+
]),
|
|
379
|
+
new Promise(r => setTimeout(r, 12000))
|
|
368
380
|
]);
|
|
369
381
|
|
|
370
|
-
await page
|
|
382
|
+
const usernameInput = await page.$('input[name="username"]');
|
|
383
|
+
const passwordInput = await page.$('input[name="password"]');
|
|
384
|
+
if (!usernameInput || !passwordInput) {
|
|
385
|
+
this.emit('warn', 'Username or password input not found');
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (page.isClosed()) {
|
|
390
|
+
this.emit('warn', 'Page closed before typing credentials');
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
|
|
371
394
|
await page.type('input[name="username"]', this.user, { delay: 50 });
|
|
372
395
|
await page.type('input[name="password"]', this.passwd, { delay: 50 });
|
|
373
396
|
|
|
374
|
-
// Handle possible "Show password" overlays
|
|
375
397
|
const submitButton = await page.$('input[type="submit"], button[type="submit"]');
|
|
376
|
-
if (!submitButton)
|
|
398
|
+
if (!submitButton) {
|
|
399
|
+
this.emit('warn', 'Submit button not found on login form');
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
377
402
|
|
|
378
|
-
if (
|
|
403
|
+
if (page.isClosed()) {
|
|
404
|
+
this.emit('warn', 'Page closed before submitting form');
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
379
407
|
|
|
380
|
-
await Promise.
|
|
381
|
-
|
|
382
|
-
|
|
408
|
+
await Promise.race([
|
|
409
|
+
Promise.all([
|
|
410
|
+
submitButton.click(),
|
|
411
|
+
page.waitForNavigation({ waitUntil: ['domcontentloaded', 'networkidle2'], timeout: 20000 })
|
|
412
|
+
]),
|
|
413
|
+
new Promise(r => setTimeout(r, 15000))
|
|
383
414
|
]);
|
|
384
415
|
|
|
385
|
-
// Check for login errors
|
|
386
416
|
const pageText = await page.content();
|
|
387
417
|
if (pageText.includes('incorrect') || pageText.includes('Invalid') || pageText.includes('nieprawidłowe')) {
|
|
388
|
-
|
|
418
|
+
this.emit('warn', 'Login failed: incorrect email or password');
|
|
419
|
+
return null;
|
|
389
420
|
}
|
|
390
421
|
|
|
391
|
-
// Check for CAPTCHA
|
|
392
422
|
const captchaPresent = await page.$('iframe[src*="captcha"], div[class*="captcha"]');
|
|
393
423
|
if (captchaPresent) {
|
|
394
|
-
|
|
424
|
+
this.emit('warn', 'Login blocked by CAPTCHA. Manual verification required.');
|
|
425
|
+
return null;
|
|
395
426
|
}
|
|
396
427
|
|
|
397
|
-
// Extract cookies with retry mechanism
|
|
398
428
|
let c1 = null, c2 = null;
|
|
399
429
|
const start = Date.now();
|
|
400
430
|
while ((!c1 || !c2) && Date.now() - start < 20000) {
|
|
@@ -404,7 +434,10 @@ class MelCloud extends EventEmitter {
|
|
|
404
434
|
if (!c1 || !c2) await new Promise(r => setTimeout(r, 500));
|
|
405
435
|
}
|
|
406
436
|
|
|
407
|
-
if (!c1 || !c2)
|
|
437
|
+
if (!c1 || !c2) {
|
|
438
|
+
this.emit('warn', 'Cookies C1/C2 missing after login');
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
408
441
|
|
|
409
442
|
const contextKey = [
|
|
410
443
|
'__Secure-monitorandcontrol=chunks-2',
|
|
@@ -420,7 +453,7 @@ class MelCloud extends EventEmitter {
|
|
|
420
453
|
|
|
421
454
|
return accountInfo;
|
|
422
455
|
} catch (error) {
|
|
423
|
-
//
|
|
456
|
+
// Puppeteer / system error handling
|
|
424
457
|
if (error.message.includes('libnspr4.so') || error.message.includes('Failed to launch the browser process')) {
|
|
425
458
|
const inDocker = await this.functions.isRunningInDocker();
|
|
426
459
|
this.emit('warn', `Missing system libraries detected.`);
|
|
@@ -434,6 +467,7 @@ class MelCloud extends EventEmitter {
|
|
|
434
467
|
if (inDocker) {
|
|
435
468
|
this.emit('warn', `Running in Docker — attempting automatic fix...`);
|
|
436
469
|
try {
|
|
470
|
+
const { execSync } = require('child_process');
|
|
437
471
|
execSync(installCmd, { stdio: 'inherit' });
|
|
438
472
|
this.emit('success', `System libraries installed. Retry the connection.`);
|
|
439
473
|
return true;
|
|
@@ -445,7 +479,7 @@ class MelCloud extends EventEmitter {
|
|
|
445
479
|
}
|
|
446
480
|
}
|
|
447
481
|
|
|
448
|
-
//
|
|
482
|
+
// Only throw for real technical errors
|
|
449
483
|
throw new Error(`Connect error: ${error.message}`);
|
|
450
484
|
} finally {
|
|
451
485
|
if (browser) {
|