homebridge-melcloud-control 4.0.0-beta.6 → 4.0.0-beta.60

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/CHANGELOG.md CHANGED
@@ -16,6 +16,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16
16
  - do not configure it manually, always using Config UI X
17
17
  - required Homebridge v2.0.0 and above
18
18
 
19
+ ## [4.0.0] - (xx.10.2025)
20
+
21
+ ## Changes
22
+
23
+ - added support for MELCloud Home [#215](https://github.com/grzegorz914/homebridge-melcloud-control/issues/215)
24
+ - redme updated
25
+ - config schema updated
26
+ - cleanup
27
+
19
28
  ## [3.9.5] - (02.09.2025)
20
29
 
21
30
  ## Changes
package/README.md CHANGED
@@ -204,9 +204,10 @@ Homebridge plugin for Air Conditioner, Heat Pump and Energy Recovery Ventilation
204
204
  | Key | Description |
205
205
  | --- | --- |
206
206
  | `name` | Here set the own account name. |
207
- | `user` | Here set the MELCloud username. |
208
- | `passwd` | Here set the MELCloud password. |
209
- | `language` | Here select the MELCloud language. |
207
+ | `user` | Here set the account username. |
208
+ | `passwd` | Here set the account password. |
209
+ | `language` | Here select the account language. |
210
+ | `displayMode` | Here select the account type `None/Disabled`, `MELCloud`, `MELCloud Home`. |
210
211
  | `ataDevices[]` | Array of ATA devices created automatically after login to MELCloud from plugin config UI. |
211
212
  | `ataDevices[].id` | Read only data, do not change it. |
212
213
  | `ataDevices[].type` | Read only data, do not change it. |
@@ -201,6 +201,32 @@
201
201
  }
202
202
  ]
203
203
  },
204
+ "displayType": {
205
+ "title": "Account Type",
206
+ "type": "string",
207
+ "default": "disabled",
208
+ "description": "Here select the language used in MELCloud account.",
209
+ "oneOf": [
210
+ {
211
+ "title": "None/Disabled",
212
+ "enum": [
213
+ "disabled"
214
+ ]
215
+ },
216
+ {
217
+ "title": "MELCLoud",
218
+ "enum": [
219
+ "melcloud"
220
+ ]
221
+ },
222
+ {
223
+ "title": "MELCLoud Home",
224
+ "enum": [
225
+ "melcloudhome"
226
+ ]
227
+ }
228
+ ]
229
+ },
204
230
  "ataDevices": {
205
231
  "title": "Devices ATA",
206
232
  "type": "array",
@@ -1798,7 +1824,8 @@
1798
1824
  "name",
1799
1825
  "user",
1800
1826
  "passwd",
1801
- "language"
1827
+ "language",
1828
+ "displayType"
1802
1829
  ]
1803
1830
  }
1804
1831
  }
@@ -1817,6 +1844,7 @@
1817
1844
  "type": "password"
1818
1845
  },
1819
1846
  "accounts[].language",
1847
+ "accounts[].displayType",
1820
1848
  {
1821
1849
  "key": "accounts[]",
1822
1850
  "type": "tabarray",
@@ -76,14 +76,22 @@
76
76
  </select>
77
77
  </div>
78
78
 
79
+ <div class="mb-2">
80
+ <label for="displayType" class="form-label">Account Type</label>
81
+ <select id="displayType" name="displayType" class="form-control">
82
+ <option value="disabled">None/Disabled</option>
83
+ <option value="melcloud">MELCloud</option>
84
+ <option value="melcloudhome">MELCloud Home</option>
85
+ </select>
86
+ </div>
87
+
79
88
  <div class="text-center">
80
- <button id="logIn" type="button" class="btn btn-secondary">Connect to MELCloud</button>
89
+ <button id="logIn" type="button" class="btn btn-secondary">Log In</button>
81
90
  <button id="configButton" type="button" class="btn btn-secondary"><i class="fas fa-gear"></i></button>
82
91
  </div>
83
92
  </form>
93
+ <div id="accountButton" class="text-center mt-2"></div>
84
94
  </div>
85
-
86
- <div id="accountButton" class="mt-2"></div>
87
95
  </div>
88
96
 
89
97
  <script>
@@ -96,8 +104,7 @@
96
104
  return;
97
105
  }
98
106
 
99
- this.deviceIndex = 0;
100
-
107
+ this.accountIndex = 0;
101
108
  const accountsCount = pluginConfig[0].accounts.length;
102
109
  for (let i = 0; i < accountsCount; i++) {
103
110
  const button = document.createElement("button");
@@ -110,7 +117,7 @@
110
117
 
111
118
  button.addEventListener('click', async () => {
112
119
  for (let j = 0; j < accountsCount; j++) {
113
- document.getElementById(`button${j}`).className = (j === i ? 'btn btn-secondary' : 'btn btn-primary');
120
+ document.getElementById(`button${j}`).className = (j === i ? 'btn btn-primary' : 'btn btn-secondary');
114
121
  }
115
122
 
116
123
  const acc = pluginConfig[0].accounts[i];
@@ -118,9 +125,10 @@
118
125
  document.getElementById('name').value = acc.name || '';
119
126
  document.getElementById('user').value = acc.user || '';
120
127
  document.getElementById('passwd').value = acc.passwd || '';
121
- document.getElementById('language').value = acc.language || '';
122
- document.getElementById('logIn').disabled = !(acc.name && acc.user && acc.passwd && acc.language);
123
- this.deviceIndex = i;
128
+ document.getElementById('language').value = acc.language || '0';
129
+ document.getElementById('displayType').value = acc.displayType || 'disabled';
130
+ document.getElementById('logIn').disabled = !(acc.name && acc.user && acc.passwd && acc.language && acc.displayType);
131
+ this.accountIndex = i;
124
132
  });
125
133
 
126
134
  if (i === accountsCount - 1) document.getElementById(`button0`).click();
@@ -129,13 +137,14 @@
129
137
  document.getElementById('melCloudAccount').style.display = 'block';
130
138
 
131
139
  document.getElementById('configForm').addEventListener('input', async () => {
132
- const acc = pluginConfig[0].accounts[this.deviceIndex];
140
+ const acc = pluginConfig[0].accounts[this.accountIndex];
133
141
  acc.name = document.querySelector('#name').value;
134
142
  acc.user = document.querySelector('#user').value;
135
143
  acc.passwd = document.querySelector('#passwd').value;
136
144
  acc.language = document.querySelector('#language').value;
145
+ acc.displayType = document.querySelector('#displayType').value;
137
146
 
138
- document.getElementById('logIn').disabled = !(acc.name && acc.user && acc.passwd && acc.language);
147
+ document.getElementById('logIn').disabled = !(acc.name && acc.user && acc.passwd && acc.languaged && acc.displayType);
139
148
 
140
149
  await homebridge.updatePluginConfig(pluginConfig);
141
150
  await homebridge.savePluginConfig(pluginConfig);
@@ -191,8 +200,8 @@
191
200
  updateInfo('info', 'Connecting...', 'yellow');
192
201
 
193
202
  try {
194
- const acc = pluginConfig[0].accounts[this.deviceIndex];
195
- const payload = { accountName: acc.name, user: acc.user, passwd: acc.passwd, language: acc.language };
203
+ const acc = pluginConfig[0].accounts[this.accountIndex];
204
+ const payload = { accountName: acc.name, user: acc.user, passwd: acc.passwd, language: acc.language, displayType: acc.displayType };
196
205
  const devicesInMelCloud = await homebridge.request('/connect', payload);
197
206
 
198
207
  // Initialize devices arrays
@@ -17,14 +17,15 @@ class PluginUiServer extends HomebridgePluginUiServer {
17
17
  const user = payload.user;
18
18
  const passwd = payload.passwd;
19
19
  const language = payload.language;
20
+ const displayType = payload.displayType;
20
21
  const accountFile = `${this.homebridgeStoragePath}/melcloud/${accountName}_Account`;
21
22
  const buildingsFile = `${this.homebridgeStoragePath}/melcloud/${accountName}_Buildings`;
22
23
  const devicesFile = `${this.homebridgeStoragePath}/melcloud/${accountName}_Devices`;
23
- const melCloud = new MelCloud(user, passwd, language, accountFile, buildingsFile, devicesFile, false, true);
24
+ const melCloud = new MelCloud(displayType, user, passwd, language, accountFile, buildingsFile, devicesFile, false, true);
24
25
 
25
26
  try {
26
- const response = await melCloud.connect();
27
- const devices = await melCloud.checkDevicesList(response.contextKey);
27
+ const accountInfo = await melCloud.connect();
28
+ const devices = await melCloud.checkDevicesList(accountInfo.ContextKey);
28
29
  return devices;
29
30
  } catch (error) {
30
31
  throw new Error(`MELCloud error: ${error.message ?? error}.`);
package/index.js CHANGED
@@ -30,6 +30,9 @@ class MelCloudPlatform {
30
30
  api.on('didFinishLaunching', async () => {
31
31
  //loop through accounts
32
32
  for (const account of config.accounts) {
33
+ const displayType = account.displayType || 'disabled';
34
+ if (displayType === 'disabled') continue;
35
+
33
36
  const accountName = account.name;
34
37
  const user = account.user;
35
38
  const passwd = account.passwd;
@@ -64,7 +67,7 @@ class MelCloudPlatform {
64
67
  passwd: 'removed',
65
68
  mqtt: {
66
69
  auth: {
67
- ...device.mqtt?.auth,
70
+ ...account.mqtt?.auth,
68
71
  passwd: 'removed',
69
72
  }
70
73
  },
@@ -76,7 +79,6 @@ class MelCloudPlatform {
76
79
  const accountFile = `${prefDir}/${accountName}_Account`;
77
80
  const buildingsFile = `${prefDir}/${accountName}_Buildings`;
78
81
  const devicesFile = `${prefDir}/${accountName}_Devices`;
79
- const cookiesFile = `${prefDir}/${accountName}cookies`;
80
82
 
81
83
 
82
84
  //set account refresh interval
@@ -88,31 +90,26 @@ class MelCloudPlatform {
88
90
  .on('start', async () => {
89
91
  try {
90
92
  //melcloud account
91
- const melCloud = new MelCloud(user, passwd, language, accountFile, buildingsFile, devicesFile, cookiesFile, logLevel.warn, logLevel.debug, false)
93
+ const melCloud = new MelCloud(displayType, user, passwd, language, accountFile, buildingsFile, devicesFile, logLevel.warn, logLevel.debug, false)
92
94
  .on('success', (msg) => logLevel.success && log.success(`${accountName}, ${msg}`))
93
95
  .on('info', (msg) => logLevel.info && log.info(`${accountName}, ${msg}`))
94
96
  .on('debug', (msg) => logLevel.debug && log.info(`${accountName}, debug: ${msg}`))
95
97
  .on('warn', (msg) => logLevel.warn && log.warn(`${accountName}, ${msg}`))
96
98
  .on('error', (msg) => logLevel.error && log.error(`${accountName}, ${msg}`));
97
99
 
98
- await melCloud.connectHomeCoocies()
99
- return;
100
-
101
-
102
100
  //connect
103
- let response;
101
+ let accountInfo;
104
102
  try {
105
- response = await melCloud.connect();
103
+ accountInfo = await melCloud.connect();
106
104
  } catch (error) {
107
105
  if (logLevel.error) log.error(`${accountName}, Connect error: ${error.message ?? error}`);
108
106
  return;
109
107
  }
110
108
 
111
- const accountInfo = response.accountInfo ?? false;
112
- const contextKey = response.contextKey ?? false;
113
- const useFahrenheit = response.useFahrenheit ?? false;
109
+ const contextKey = accountInfo.ContextKey;
110
+ const useFahrenheit = accountInfo.UseFahrenheit;
114
111
 
115
- if (contextKey === false) {
112
+ if (!contextKey) {
116
113
  return;
117
114
  }
118
115
 
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.6",
4
+ "version": "4.0.0-beta.60",
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,15 +7,15 @@ 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, cookiesFile, logWarn, logDebug, requestConfig) {
10
+ constructor(displayType, user, passwd, language, accountFile, buildingsFile, devicesFile, logWarn, logDebug, requestConfig) {
11
11
  super();
12
+ this.displayType = displayType;
12
13
  this.user = user;
13
14
  this.passwd = passwd;
14
15
  this.language = language;
15
16
  this.accountFile = accountFile;
16
17
  this.buildingsFile = buildingsFile;
17
18
  this.devicesFile = devicesFile;
18
- this.cookiesFile = cookiesFile;
19
19
  this.logWarn = logWarn;
20
20
  this.logDebug = logDebug;
21
21
  this.requestConfig = requestConfig;
@@ -58,7 +58,7 @@ class MelCloud extends EventEmitter {
58
58
  }
59
59
  }
60
60
 
61
- async checkDevicesList(contextKey) {
61
+ async checkMelcloudDevicesList(contextKey) {
62
62
  try {
63
63
  const axiosInstanceGet = axios.create({
64
64
  method: 'GET',
@@ -109,7 +109,7 @@ class MelCloud extends EventEmitter {
109
109
  }
110
110
  }
111
111
 
112
- async connect() {
112
+ async connectToMelCloud() {
113
113
  if (this.logDebug) this.emit('debug', `Connecting to MELCloud`);
114
114
 
115
115
  try {
@@ -123,7 +123,6 @@ class MelCloud extends EventEmitter {
123
123
  const account = accountData.data;
124
124
  const accountInfo = account.LoginData;
125
125
  const contextKey = accountInfo?.ContextKey;
126
- const useFahrenheit = accountInfo?.UseFahrenheit ?? false;
127
126
  this.contextKey = contextKey;
128
127
 
129
128
  const debugData = {
@@ -153,44 +152,24 @@ class MelCloud extends EventEmitter {
153
152
  });
154
153
 
155
154
  await this.functions.saveData(this.accountFile, accountInfo);
156
-
157
155
  this.emit('success', `Connect to MELCloud Success`);
158
156
 
159
- return {
160
- accountInfo,
161
- contextKey,
162
- useFahrenheit
163
- };
157
+ return accountInfo
164
158
  } catch (error) {
165
159
  throw new Error(`Connect to MELCloud error: ${error.message}`);
166
160
  }
167
161
  }
168
162
 
169
- async connectHome(cookieC1, cookieC2) {
170
- if (this.logDebug) this.emit('debug', `Connecting to MELCloud Home`);
171
-
163
+ async checkMelcloudHomeDevicesList(contextKey) {
172
164
  try {
173
- const c1 = cookieC1.trim();
174
- const c2 = cookieC2.trim();
175
-
176
- const cookieString = [
177
- '__Secure-monitorandcontrol=chunks-2',
178
- `__Secure-monitorandcontrolC1=${c1}`,
179
- `__Secure-monitorandcontrolC2=${c2}`,
180
- ].join('; ');
181
-
182
165
  const axiosInstance = axios.create({
166
+ method: 'GET',
183
167
  baseURL: ApiUrlsHome.BaseURL,
184
- timeout: 10000,
185
- httpsAgent: new Agent({
186
- keepAlive: false,
187
- rejectUnauthorized: false
188
- }),
189
168
  headers: {
190
169
  'Accept': '*/*',
191
170
  'Accept-Language': 'en-US,en;q=0.9',
192
- 'Cookie': cookieString,
193
- 'User-Agent': 'homebridge-melcloud-home/0.2.0',
171
+ 'Cookie': contextKey,
172
+ 'User-Agent': 'homebridge-melcloud-control/4.0.0',
194
173
  'DNT': '1',
195
174
  'Origin': 'https://melcloudhome.com',
196
175
  'Referer': 'https://melcloudhome.com/dashboard',
@@ -198,93 +177,188 @@ class MelCloud extends EventEmitter {
198
177
  'Sec-Fetch-Mode': 'cors',
199
178
  'Sec-Fetch-Site': 'same-origin',
200
179
  'X-CSRF': '1'
201
- }
180
+ },
181
+ ...this.axiosDefaults
202
182
  });
203
183
 
204
- const response = await axiosInstance.get(ApiUrlsHome.GetUserContext);
205
- const homeData = response.data;
206
- if (this.logDebug) this.emit('debug', `[MELCloudHome] Response data: ${JSON.stringify(homeData, null, 2)}`);
184
+ if (this.logDebug) this.emit('debug', `Scanning for devices`);
185
+ const listDevicesData = await axiosInstance(ApiUrlsHome.GetUserContext);
186
+ const buildingsList = listDevicesData.data.buildings;
187
+ if (this.logDebug) this.emit('debug', `Buildings: ${JSON.stringify(buildingsList, null, 2)}`);
207
188
 
208
- this.emit('success', `Connect to MELCloud Home Success`);
189
+ if (!buildingsList) {
190
+ if (this.logWarn) this.emit('warn', `No building found`);
191
+ return null;
192
+ }
193
+
194
+ await this.functions.saveData(this.buildingsFile, buildingsList);
195
+ if (this.logDebug) this.emit('debug', `Buildings list saved`);
209
196
 
210
- return
197
+ const devices = buildingsList.flatMap(building => {
198
+ // Funkcja kapitalizująca klucze obiektu
199
+ const capitalizeKeys = obj =>
200
+ Object.fromEntries(
201
+ Object.entries(obj).map(([key, value]) => [
202
+ key.charAt(0).toUpperCase() + key.slice(1),
203
+ value
204
+ ])
205
+ );
206
+
207
+ // Funkcja tworząca finalny obiekt Device
208
+ const createDevice = (device, type) => {
209
+ // Settings już kapitalizowane w nazwach
210
+ const settingsArray = device.Settings || [];
211
+
212
+ const settingsObject = Object.fromEntries(
213
+ settingsArray.map(({ name, value }) => {
214
+ let parsedValue = value;
215
+ if (value === "True") parsedValue = true;
216
+ else if (value === "False") parsedValue = false;
217
+ else if (!isNaN(value) && value !== "") parsedValue = Number(value);
218
+
219
+ const key = name.charAt(0).toUpperCase() + name.slice(1);
220
+ return [key, parsedValue];
221
+ })
222
+ );
223
+
224
+ // Scal Capabilities + Settings + DeviceType w Device
225
+ const deviceObject = {
226
+ ...capitalizeKeys(device.Capabilities || {}),
227
+ ...settingsObject,
228
+ DeviceType: type
229
+ };
230
+
231
+ // Usuń stare pola Settings i Capabilities
232
+ const { Settings, Capabilities, Id, GivenDisplayName, ...rest } = device;
233
+
234
+ return {
235
+ ...rest,
236
+ Type: type, // <-- Type na głównym poziomie według źródła
237
+ DeviceID: Id,
238
+ DeviceName: GivenDisplayName,
239
+ Device: deviceObject
240
+ };
241
+ };
242
+
243
+ return [
244
+ ...(building.airToAirUnits || []).map(d => createDevice(capitalizeKeys(d), 0)),
245
+ ...(building.airToWaterUnits || []).map(d => createDevice(capitalizeKeys(d), 1)),
246
+ ...(building.airToVentilationUnits || []).map(d => createDevice(capitalizeKeys(d), 3))
247
+ ];
248
+ });
249
+
250
+ // Jeśli nie ma urządzeń
251
+ if (devices.length === 0) {
252
+ if (this.logWarn) this.emit('warn', `No devices found`);
253
+ return null;
254
+ }
255
+
256
+
257
+ // Jeśli nie ma urządzeń
258
+ if (devices.length === 0) {
259
+ if (this.logWarn) this.emit('warn', `No devices found`);
260
+ return null;
261
+ }
262
+
263
+
264
+ await this.functions.saveData(this.devicesFile, devices);
265
+ if (this.logDebug) this.emit('debug', `${devices.length} devices saved`);
266
+
267
+ return devices;
211
268
  } catch (error) {
212
269
  throw new Error(`Connect to MELCloud Home error: ${error.message}`);
213
270
  }
214
271
  }
215
272
 
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
-
224
- const browser = await puppeteer.launch({
225
- headless: true,
226
- args: ['--no-sandbox', '--disable-setuid-sandbox']
227
- });
273
+ async connectToMelCloudHome() {
274
+ if (this.logDebug) this.emit('debug', `Connecting to MELCloud Home`);
228
275
 
276
+ const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] });
229
277
  const page = await browser.newPage();
230
278
 
231
279
  try {
232
- this.emit('warn', 'Opening login page...');
233
- await page.goto(loginUrl.toString(), { waitUntil: 'networkidle2' });
280
+ // Open MELCloud Home
281
+ await page.goto(ApiUrlsHome.BaseURL, { waitUntil: 'networkidle2' });
282
+ const buttons = await page.$$('button.btn--blue');
283
+ let loginBtn = null;
284
+ for (const btn of buttons) {
285
+ const text = await page.evaluate(el => el.textContent, btn);
286
+ if (text.trim() === 'Zaloguj' || text.trim() === 'Log In') {
287
+ loginBtn = btn;
288
+ break;
289
+ }
290
+ }
234
291
 
235
- this.emit('warn', 'Typing credentials...');
292
+ if (!loginBtn && this.logWarn) this.emit('warn', `Login button not found`);
293
+
294
+ // Set credentials and login
295
+ await Promise.all([loginBtn.click(), page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 20000 })]);
296
+ await page.waitForSelector('input[name="username"]', { timeout: 15000 });
236
297
  await page.type('input[name="username"]', this.user, { delay: 50 });
237
298
  await page.type('input[name="password"]', this.passwd, { delay: 50 });
238
299
 
239
- // Wyszukiwanie przycisku logowania
240
- const buttonSelectors = [
241
- 'button[type="submit"]',
242
- 'input[type="submit"]',
243
- 'button[name="signIn"]',
244
- 'button.btn-primary'
245
- ];
246
-
247
- let buttonFound = false;
248
- for (const selector of buttonSelectors) {
249
- const button = await page.$(selector);
250
- if (button) {
251
- this.emit('warn', `Found submit button: ${selector}`);
252
- await Promise.all([
253
- button.click(),
254
- page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 20000 }) // czekamy na redirect
255
- ]);
256
- buttonFound = true;
257
- break;
258
- }
259
- }
300
+ const button1 = await page.$('input[type="submit"]');
301
+ await Promise.all([button1.click(), page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 20000 })]);
302
+
303
+ // Get cookies C1 and C2
304
+ let c1 = null, c2 = null;
305
+ const start = Date.now();
260
306
 
261
- if (!buttonFound) {
262
- throw new Error('❌ Could not find login button on the page.');
307
+ // Loop max 20s
308
+ while ((!c1 || !c2) && Date.now() - start < 20000) {
309
+ const cookies = await page.cookies();
310
+ c1 = cookies.find(c => c.name === '__Secure-monitorandcontrolC1')?.value || c1;
311
+ c2 = cookies.find(c => c.name === '__Secure-monitorandcontrolC2')?.value || c2;
312
+ if (!c1 || !c2) await new Promise(r => setTimeout(r, 500));
263
313
  }
264
314
 
265
- // Poczekaj dashboard MELCloud Home będzie gotowy
266
- this.emit('warn', 'Waiting for MELCloud Home dashboard...');
267
- await page.waitForSelector('#dashboard, .dashboard-container', { timeout: 20000 });
315
+ if (!c1 || !c2) {
316
+ if (this.logWarn) this.emit('warn', `Cookies C1/C2 missing`);
317
+ return null;
318
+ }
268
319
 
269
- // Pobranie cookies po zalogowaniu
270
- const cookies = await page.cookies();
271
- const c1 = cookies.find(c => c.name === '__Secure-monitorandcontrolC1')?.value || null;
272
- const c2 = cookies.find(c => c.name === '__Secure-monitorandcontrolC2')?.value || null;
320
+ const contextKey = ['__Secure-monitorandcontrol=chunks-2', `__Secure-monitorandcontrolC1=${c1}`, `__Secure-monitorandcontrolC2=${c2}`,].join('; ');
321
+ const accountInfo = { ContextKey: contextKey, UseFahrenheit: false };
322
+ this.contextKey = contextKey;
273
323
 
274
- const data = { C1: c1, C2: c2, date: new Date().toISOString() };
275
- await this.functions.saveData(this.cookiesFile, data);
324
+ await this.functions.saveData(this.accountFile, accountInfo);
325
+ this.emit('success', `Connect to MELCloud Home Success`);
276
326
 
277
- this.emit('warn', 'Login successful.');
278
- return data;
279
- } catch (err) {
280
- this.emit('error', `Login failed: ${err.message}`);
281
- return null;
327
+ return accountInfo;
328
+ } catch (error) {
329
+ throw new Error(`Connect to MELCloud Home error: ${error.message}`);
282
330
  } finally {
283
331
  await browser.close();
284
332
  }
285
333
  }
286
334
 
335
+ async connect() {
336
+ let response = {};
337
+ switch (this.displayType) {
338
+ case "melcloud":
339
+ response = await this.connectToMelCloud();
340
+ return response
341
+ case "melcloudhome":
342
+ response = await this.connectToMelCloudHome();
343
+ return response
344
+ default:
345
+ return response
346
+ }
347
+ }
287
348
 
349
+ async checkDevicesList(contextKey) {
350
+ let devices = [];
351
+ switch (this.displayType) {
352
+ case "melcloud":
353
+ devices = await this.checkMelcloudDevicesList(contextKey);
354
+ return devices
355
+ case "melcloudhome":
356
+ devices = await this.checkMelcloudHomeDevicesList(contextKey);
357
+ return devices;
358
+ default:
359
+ return devices;
360
+ }
361
+ }
288
362
 
289
363
  async send(accountInfo) {
290
364
  try {