homebridge-melcloud-control 4.0.0-beta.0 → 4.0.0-beta.10
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/index.js +3 -3
- package/package.json +1 -1
- package/src/melcloud.js +63 -31
package/index.js
CHANGED
|
@@ -76,7 +76,7 @@ class MelCloudPlatform {
|
|
|
76
76
|
const accountFile = `${prefDir}/${accountName}_Account`;
|
|
77
77
|
const buildingsFile = `${prefDir}/${accountName}_Buildings`;
|
|
78
78
|
const devicesFile = `${prefDir}/${accountName}_Devices`;
|
|
79
|
-
const
|
|
79
|
+
const cookiesFile = `${prefDir}/${accountName}_Cookies`;
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
//set account refresh interval
|
|
@@ -88,14 +88,14 @@ class MelCloudPlatform {
|
|
|
88
88
|
.on('start', async () => {
|
|
89
89
|
try {
|
|
90
90
|
//melcloud account
|
|
91
|
-
const melCloud = new MelCloud(user, passwd, language, accountFile, buildingsFile, devicesFile,
|
|
91
|
+
const melCloud = new MelCloud(user, passwd, language, accountFile, buildingsFile, devicesFile, cookiesFile, logLevel.warn, logLevel.debug, false)
|
|
92
92
|
.on('success', (msg) => logLevel.success && log.success(`${accountName}, ${msg}`))
|
|
93
93
|
.on('info', (msg) => logLevel.info && log.info(`${accountName}, ${msg}`))
|
|
94
94
|
.on('debug', (msg) => logLevel.debug && log.info(`${accountName}, debug: ${msg}`))
|
|
95
95
|
.on('warn', (msg) => logLevel.warn && log.warn(`${accountName}, ${msg}`))
|
|
96
96
|
.on('error', (msg) => logLevel.error && log.error(`${accountName}, ${msg}`));
|
|
97
97
|
|
|
98
|
-
await melCloud.
|
|
98
|
+
await melCloud.connectHomeCookies();
|
|
99
99
|
return;
|
|
100
100
|
|
|
101
101
|
|
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.10",
|
|
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
|
@@ -7,7 +7,7 @@ import Functions from './functions.js';
|
|
|
7
7
|
import { ApiUrls, ApiUrlsHome } from './constants.js';
|
|
8
8
|
|
|
9
9
|
class MelCloud extends EventEmitter {
|
|
10
|
-
constructor(user, passwd, language, accountFile, buildingsFile, devicesFile,
|
|
10
|
+
constructor(user, passwd, language, accountFile, buildingsFile, devicesFile, cookiesFile, logWarn, logDebug, requestConfig) {
|
|
11
11
|
super();
|
|
12
12
|
this.user = user;
|
|
13
13
|
this.passwd = passwd;
|
|
@@ -15,7 +15,7 @@ class MelCloud extends EventEmitter {
|
|
|
15
15
|
this.accountFile = accountFile;
|
|
16
16
|
this.buildingsFile = buildingsFile;
|
|
17
17
|
this.devicesFile = devicesFile;
|
|
18
|
-
this.
|
|
18
|
+
this.cookiesFile = cookiesFile;
|
|
19
19
|
this.logWarn = logWarn;
|
|
20
20
|
this.logDebug = logDebug;
|
|
21
21
|
this.requestConfig = requestConfig;
|
|
@@ -213,7 +213,14 @@ class MelCloud extends EventEmitter {
|
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
async
|
|
216
|
+
async connectHomeCookies() {
|
|
217
|
+
const loginUrl = new URL('https://live-melcloudhome.auth.eu-west-1.amazoncognito.com/login');
|
|
218
|
+
loginUrl.searchParams.set('client_id', '3g4d5l5kivuqi7oia68gib7uso');
|
|
219
|
+
loginUrl.searchParams.set('redirect_uri', 'https://auth.melcloudhome.com/signin-oidc-meu');
|
|
220
|
+
loginUrl.searchParams.set('response_type', 'code');
|
|
221
|
+
loginUrl.searchParams.set('scope', 'openid profile');
|
|
222
|
+
loginUrl.searchParams.set('response_mode', 'form_post');
|
|
223
|
+
|
|
217
224
|
const browser = await puppeteer.launch({
|
|
218
225
|
headless: true,
|
|
219
226
|
args: ['--no-sandbox', '--disable-setuid-sandbox']
|
|
@@ -221,43 +228,68 @@ class MelCloud extends EventEmitter {
|
|
|
221
228
|
|
|
222
229
|
const page = await browser.newPage();
|
|
223
230
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
231
|
+
try {
|
|
232
|
+
this.emit('warn', 'Opening login page...');
|
|
233
|
+
await page.goto(loginUrl.toString(), { waitUntil: 'networkidle2' });
|
|
234
|
+
|
|
235
|
+
// Wpisz login i hasło
|
|
236
|
+
await page.type('input[name="username"]', this.user);
|
|
237
|
+
await page.type('input[name="password"]', thispasswd);
|
|
238
|
+
|
|
239
|
+
// Kliknij przycisk logowania
|
|
240
|
+
const button = await page.$('button[type="submit"]');
|
|
241
|
+
await Promise.all([
|
|
242
|
+
button.click(),
|
|
243
|
+
page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 20000 })
|
|
244
|
+
]);
|
|
245
|
+
|
|
246
|
+
// Opcjonalnie obsłuż "Stay signed in?" jeśli występuje
|
|
247
|
+
const staySignedInBtn = await page.$('input[type="submit"]');
|
|
248
|
+
if (staySignedInBtn) {
|
|
249
|
+
await Promise.all([
|
|
250
|
+
staySignedInBtn.click(),
|
|
251
|
+
page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 20000 })
|
|
252
|
+
]);
|
|
253
|
+
}
|
|
227
254
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
255
|
+
// Opcjonalnie obsługa "Stay signed in?"
|
|
256
|
+
const staySignedInSelector = 'input[name="rememberDevice"], button[type="submit"]';
|
|
257
|
+
if (await page.$(staySignedInSelector)) {
|
|
258
|
+
console.log('Handling "Stay signed in?" screen...');
|
|
259
|
+
await Promise.all([
|
|
260
|
+
page.click(staySignedInSelector),
|
|
261
|
+
page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 20000 })
|
|
262
|
+
]);
|
|
263
|
+
}
|
|
232
264
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
page.click('button[type="submit"]'),
|
|
237
|
-
page.waitForNavigation({ waitUntil: 'networkidle2' })
|
|
238
|
-
]);
|
|
265
|
+
// Monitorowanie requestów i oczekiwanie na cookies C1 i C2
|
|
266
|
+
let c1 = null, c2 = null;
|
|
267
|
+
const start = Date.now();
|
|
239
268
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
269
|
+
while ((!c1 || !c2) && Date.now() - start < 20000) { // max 20s
|
|
270
|
+
const cookies = await page.cookies();
|
|
271
|
+
c1 = cookies.find(c => c.name === '__Secure-monitorandcontrolC1')?.value || c1;
|
|
272
|
+
c2 = cookies.find(c => c.name === '__Secure-monitorandcontrolC2')?.value || c2;
|
|
273
|
+
if (!c1 || !c2) await new Promise(r => setTimeout(r, 500));
|
|
274
|
+
}
|
|
243
275
|
|
|
244
|
-
|
|
245
|
-
const cookies = await page.cookies();
|
|
276
|
+
if (!c1 || !c2) throw new Error('Cookies C1/C2 not found');
|
|
246
277
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const c2 = cookies.find(c => c.name === '__Secure-monitorandcontrolC2')?.value || null;
|
|
278
|
+
const data = { C1: c1, C2: c2, date: new Date().toISOString() };
|
|
279
|
+
await this.functions.saveData(this.cookiesFile, data);
|
|
250
280
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
await this.functions.saveData(this.coociesFile, data);
|
|
281
|
+
this.emit('warn', 'Login successful.');
|
|
282
|
+
return data;
|
|
254
283
|
|
|
255
|
-
|
|
284
|
+
} catch (err) {
|
|
285
|
+
this.emit('error', `Login failed: ${err.message}`);
|
|
286
|
+
return null;
|
|
287
|
+
} finally {
|
|
288
|
+
await browser.close();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
256
291
|
|
|
257
|
-
this.emit('warn', `Login successful.`);
|
|
258
292
|
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
293
|
|
|
262
294
|
async send(accountInfo) {
|
|
263
295
|
try {
|