homebridge-melcloud-control 4.0.0-beta.3 → 4.0.0-beta.30

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 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 coociesFile = `${prefDir}/${accountName}_Coocies`;
79
+ const cookiesFile = `${prefDir}/${accountName}_Cookies`;
80
80
 
81
81
 
82
82
  //set account refresh interval
@@ -88,21 +88,17 @@ 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, coociesFile, logLevel.warn, logLevel.debug, false)
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.connectHomeCoocies()
99
- return;
100
-
101
-
102
98
  //connect
103
99
  let response;
104
100
  try {
105
- response = await melCloud.connect();
101
+ response = await melCloud.connect('home');
106
102
  } catch (error) {
107
103
  if (logLevel.error) log.error(`${accountName}, Connect error: ${error.message ?? error}`);
108
104
  return;
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.3",
4
+ "version": "4.0.0-beta.30",
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, coociesFile, logWarn, logDebug, requestConfig) {
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.coociesFile = coociesFile;
18
+ this.cookiesFile = cookiesFile;
19
19
  this.logWarn = logWarn;
20
20
  this.logDebug = logDebug;
21
21
  this.requestConfig = requestConfig;
@@ -109,7 +109,7 @@ class MelCloud extends EventEmitter {
109
109
  }
110
110
  }
111
111
 
112
- async connect() {
112
+ async connectMelCloud() {
113
113
  if (this.logDebug) this.emit('debug', `Connecting to MELCloud`);
114
114
 
115
115
  try {
@@ -166,14 +166,15 @@ class MelCloud extends EventEmitter {
166
166
  }
167
167
  }
168
168
 
169
- async connectHome(cookieC1, cookieC2) {
169
+ async connectMelCloudHome() {
170
170
  if (this.logDebug) this.emit('debug', `Connecting to MELCloud Home`);
171
171
 
172
172
  try {
173
- const c1 = cookieC1.trim();
174
- const c2 = cookieC2.trim();
173
+ const coocies = await this.getCookies();
174
+ const c1 = coocies.C1.trim();
175
+ const c2 = coocies.C2.trim();
175
176
 
176
- const cookieString = [
177
+ const cookies = [
177
178
  '__Secure-monitorandcontrol=chunks-2',
178
179
  `__Secure-monitorandcontrolC1=${c1}`,
179
180
  `__Secure-monitorandcontrolC2=${c2}`,
@@ -189,7 +190,7 @@ class MelCloud extends EventEmitter {
189
190
  headers: {
190
191
  'Accept': '*/*',
191
192
  'Accept-Language': 'en-US,en;q=0.9',
192
- 'Cookie': cookieString,
193
+ 'Cookie': cookies,
193
194
  'User-Agent': 'homebridge-melcloud-home/0.2.0',
194
195
  'DNT': '1',
195
196
  'Origin': 'https://melcloudhome.com',
@@ -203,7 +204,7 @@ class MelCloud extends EventEmitter {
203
204
 
204
205
  const response = await axiosInstance.get(ApiUrlsHome.GetUserContext);
205
206
  const homeData = response.data;
206
- if (this.logDebug) this.emit('debug', `[MELCloudHome] Response data: ${JSON.stringify(homeData, null, 2)}`);
207
+ if (this.logDebug) this.emit('debug', `MELCloud Home data: ${JSON.stringify(homeData, null, 2)}`);
207
208
 
208
209
  this.emit('success', `Connect to MELCloud Home Success`);
209
210
 
@@ -213,81 +214,83 @@ class MelCloud extends EventEmitter {
213
214
  }
214
215
  }
215
216
 
216
- async connectHomeCoocies() {
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
-
224
-
225
-
226
- const browser = await puppeteer.launch({
227
- headless: true,
228
- args: ['--no-sandbox', '--disable-setuid-sandbox']
229
- });
230
-
217
+ async getCookies() {
218
+ const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] });
231
219
  const page = await browser.newPage();
232
220
 
233
- // Otwórz stronę logowania
234
- this.emit('warn', `Opening login page...`);
235
- await page.goto(loginUrl, { waitUntil: 'networkidle2' });
236
-
237
- // Wpisz login i hasło
238
- this.emit('warn', `Typing credentials...`);
239
- await page.type('input[name="username"]', this.user, { delay: 50 });
240
- await page.type('input[name="password"]', this.passwd, { delay: 50 });
241
-
242
- // Sprawdź kilka możliwych wariantów
243
- const buttonSelectors = [
244
- 'button[type="submit"]',
245
- 'input[type="submit"]',
246
- 'button[name="signIn"]',
247
- 'button.btn-primary',
248
- 'button:has-text("Sign in")',
249
- 'button:has-text("Zaloguj")'
250
- ];
251
-
252
- // Kliknij "Sign in" (przycisk AWS Cognito)
253
- let buttonFound = false;
254
- for (const selector of buttonSelectors) {
255
- const button = await page.$(selector);
256
- if (button) {
257
- console.log(`Found submit button: ${selector}`);
258
- await Promise.all([
259
- button.click(),
260
- page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 15000 })
261
- ]);
262
- buttonFound = true;
263
- break;
221
+ try {
222
+ this.emit('warn', 'Opening login page...');
223
+ await page.goto(ApiUrlsHome.BaseURL, { waitUntil: 'networkidle2' });
224
+
225
+ // Kliknij przycisk logowania
226
+ const buttons = await page.$$('button.btn--blue');
227
+ let loginBtn = null;
228
+ for (const btn of buttons) {
229
+ const text = await page.evaluate(el => el.textContent, btn);
230
+ if (text.trim() === 'Zaloguj') {
231
+ loginBtn = btn;
232
+ break;
233
+ }
264
234
  }
265
- }
266
235
 
267
- if (!buttonFound) {
268
- throw new Error('❌ Could not find login button on the page.');
269
- }
236
+ if (!loginBtn) throw new Error('Login button not found on homepage');
270
237
 
271
- // Poczekaj aż załaduje się MELCloud Home
272
- this.emit('warn', `Waiting for redirect to melcloudhome.com...`);
273
- await page.waitForTimeout(5000);
238
+ await Promise.all([
239
+ loginBtn.click(),
240
+ page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 20000 })
241
+ ]);
274
242
 
275
- // Pobierz cookies dla domeny melcloudhome.com
276
- const cookies = await page.cookies();
243
+ // Poczekaj, strona przekieruje do Cognito login
244
+ await page.waitForSelector('input[name="username"]', { timeout: 15000 });
277
245
 
278
- // Znajdź __Secure-monitorandcontrolC1 i C2
279
- const c1 = cookies.find(c => c.name === '__Secure-monitorandcontrolC1')?.value || null;
280
- const c2 = cookies.find(c => c.name === '__Secure-monitorandcontrolC2')?.value || null;
246
+ this.emit('warn', 'Typing credentials...');
247
+ await page.type('input[name="username"]', this.user, { delay: 50 });
248
+ await page.type('input[name="password"]', this.passwd, { delay: 50 });
281
249
 
282
- // Zapisz do pliku
283
- const data = { C1: c1, C2: c2, date: new Date().toISOString() };
284
- await this.functions.saveData(this.coociesFile, data);
250
+ // Kliknij przycisk logowania
251
+ const button1 = await page.$('input[type="submit"]');
252
+ await Promise.all([
253
+ button1.click(),
254
+ page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 20000 })
255
+ ]);
285
256
 
286
- await browser.close();
257
+ let c1 = null, c2 = null;
258
+ const start = Date.now();
287
259
 
288
- this.emit('warn', `Login successful.`);
260
+ // Loop max 20s, czekamy aż pojawią się cookies
261
+ while ((!c1 || !c2) && Date.now() - start < 20000) {
262
+ const cookies = await page.cookies();
263
+ c1 = cookies.find(c => c.name === '__Secure-monitorandcontrolC1')?.value || c1;
264
+ c2 = cookies.find(c => c.name === '__Secure-monitorandcontrolC2')?.value || c2;
265
+ if (!c1 || !c2) await new Promise(r => setTimeout(r, 500));
266
+ }
267
+
268
+ if (!c1 || !c2) {
269
+ await browser.close();
270
+ throw new Error('Cookies C1/C2 not found after login');
271
+ }
289
272
 
290
- return false;
273
+ // Zapis do pliku
274
+ const data = { C1: c1, C2: c2, date: new Date().toISOString() };
275
+ await this.functions.saveData(this.cookiesFile, data);
276
+
277
+ this.emit('warn', 'Login successful.');
278
+ return data;
279
+ } catch (err) {
280
+ this.emit('error', `Login failed: ${err.message}`);
281
+ return null;
282
+ } finally {
283
+ await browser.close();
284
+ }
285
+ }
286
+
287
+ async connect(mode) {
288
+ switch (mode) {
289
+ case 'home':
290
+ return await this.connectMelCloudHome();
291
+ default:
292
+ return await this.connectMelCloud();
293
+ }
291
294
  }
292
295
 
293
296
  async send(accountInfo) {