homebridge-melcloud-control 4.4.1-beta.5 → 4.4.1-beta.50
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 +10 -0
- package/README.md +55 -55
- package/config.schema.json +54 -54
- package/homebridge-ui/public/index.html +142 -130
- package/index.js +17 -5
- package/package.json +2 -2
- package/src/constants.js +62 -50
- package/src/deviceata.js +25 -18
- package/src/deviceatw.js +6 -10
- package/src/deviceerv.js +61 -60
- package/src/functions.js +105 -111
- package/src/melcloud.js +10 -8
- package/src/melcloudata.js +41 -10
- package/src/melcloudatw.js +25 -9
- package/src/melclouderv.js +24 -8
- package/src/melcloudhome.js +40 -36
package/src/melcloudhome.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
1
|
import axios from 'axios';
|
|
3
2
|
import WebSocket from 'ws';
|
|
4
3
|
import { exec } from 'child_process';
|
|
@@ -7,7 +6,7 @@ import EventEmitter from 'events';
|
|
|
7
6
|
import puppeteer from 'puppeteer';
|
|
8
7
|
import ImpulseGenerator from './impulsegenerator.js';
|
|
9
8
|
import Functions from './functions.js';
|
|
10
|
-
import {
|
|
9
|
+
import { ApiUrls, LanguageLocaleMap } from './constants.js';
|
|
11
10
|
const execPromise = promisify(exec);
|
|
12
11
|
|
|
13
12
|
class MelCloudHome extends EventEmitter {
|
|
@@ -17,7 +16,6 @@ class MelCloudHome extends EventEmitter {
|
|
|
17
16
|
this.user = account.user;
|
|
18
17
|
this.passwd = account.passwd;
|
|
19
18
|
this.language = account.language;
|
|
20
|
-
this.logSuccess = account.log?.success;
|
|
21
19
|
this.logWarn = account.log?.warn;
|
|
22
20
|
this.logError = account.log?.error;
|
|
23
21
|
this.logDebug = account.log?.debug;
|
|
@@ -79,7 +77,7 @@ class MelCloudHome extends EventEmitter {
|
|
|
79
77
|
async checkScenesList() {
|
|
80
78
|
try {
|
|
81
79
|
if (this.logDebug) this.emit('debug', `Scanning for scenes`);
|
|
82
|
-
const listScenesData = await this.client(
|
|
80
|
+
const listScenesData = await this.client(ApiUrls.Home.Get.Scenes, { method: 'GET', });
|
|
83
81
|
|
|
84
82
|
const scenesList = listScenesData.data;
|
|
85
83
|
if (this.logDebug) this.emit('debug', `Scenes: ${JSON.stringify(scenesList, null, 2)}`);
|
|
@@ -109,9 +107,9 @@ class MelCloudHome extends EventEmitter {
|
|
|
109
107
|
|
|
110
108
|
async checkDevicesList() {
|
|
111
109
|
try {
|
|
112
|
-
const devicesList = { State: false, Info: null, Devices: [], Scenes: [] }
|
|
110
|
+
const devicesList = { State: false, Info: null, Buildings: {}, Devices: [], Scenes: [] }
|
|
113
111
|
if (this.logDebug) this.emit('debug', `Scanning for devices`);
|
|
114
|
-
const listDevicesData = await this.client(
|
|
112
|
+
const listDevicesData = await this.client(ApiUrls.Home.Get.ListDevices, { method: 'GET' });
|
|
115
113
|
|
|
116
114
|
const userContext = listDevicesData.data;
|
|
117
115
|
const buildings = userContext.buildings ?? [];
|
|
@@ -124,9 +122,6 @@ class MelCloudHome extends EventEmitter {
|
|
|
124
122
|
return devicesList;
|
|
125
123
|
}
|
|
126
124
|
|
|
127
|
-
await this.functions.saveData(this.buildingsFile, userContext);
|
|
128
|
-
if (this.logDebug) this.emit('debug', `Buildings list saved`);
|
|
129
|
-
|
|
130
125
|
const devices = buildingsList.flatMap(building => {
|
|
131
126
|
// Funkcja kapitalizująca klucze obiektu
|
|
132
127
|
const capitalizeKeys = obj => Object.fromEntries(Object.entries(obj).map(([key, value]) => [key.charAt(0).toUpperCase() + key.slice(1), value]));
|
|
@@ -207,8 +202,13 @@ class MelCloudHome extends EventEmitter {
|
|
|
207
202
|
|
|
208
203
|
devicesList.State = true;
|
|
209
204
|
devicesList.Info = `Found ${devicesCount} devices ${scenes.length > 0 ? `and ${scenes.length} scenes` : ''}`;
|
|
205
|
+
devicesList.Buildings = userContext;
|
|
210
206
|
devicesList.Devices = devices;
|
|
211
207
|
devicesList.Scenes = scenes;
|
|
208
|
+
|
|
209
|
+
await this.functions.saveData(this.buildingsFile, devicesList);
|
|
210
|
+
if (this.logDebug) this.emit('debug', `Buildings list saved`);
|
|
211
|
+
|
|
212
212
|
this.emit('devicesList', devicesList);
|
|
213
213
|
|
|
214
214
|
return devicesList;
|
|
@@ -225,32 +225,36 @@ class MelCloudHome extends EventEmitter {
|
|
|
225
225
|
try {
|
|
226
226
|
const accountInfo = { State: false, Info: '', Account: {}, UseFahrenheit: false };
|
|
227
227
|
|
|
228
|
-
// Get Chromium path
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
228
|
+
// Get Chromium path from resolver
|
|
229
|
+
const chromiumInfo = await this.functions.ensureChromiumInstalled();
|
|
230
|
+
let chromiumPath = chromiumInfo.path;
|
|
231
|
+
const arch = chromiumInfo.arch;
|
|
232
|
+
const system = chromiumInfo.system;
|
|
233
|
+
|
|
234
|
+
// If path is found, use it
|
|
235
|
+
if (chromiumPath) {
|
|
236
|
+
if (!this.logDebug) this.emit('debug', `Using Chromium for ${system} (${arch}) at ${chromiumPath}`);
|
|
237
|
+
} else {
|
|
238
|
+
if (arch === 'arm') {
|
|
239
|
+
accountInfo.Info = `No Chromium found for ${system} (${arch}). Please install it manually and try again.`;
|
|
240
|
+
return accountInfo;
|
|
241
|
+
} else {
|
|
242
|
+
try {
|
|
243
|
+
chromiumPath = puppeteer.executablePath();
|
|
244
|
+
if (!this.logDebug) this.emit('debug', `Using Puppeteer Chromium for ${system} (${arch}) at ${chromiumPath}`);
|
|
245
|
+
} catch (error) {
|
|
246
|
+
accountInfo.Info = `No Puppeteer Chromium for ${system} (${arch}), error: ${error.message}`;
|
|
240
247
|
return accountInfo;
|
|
241
248
|
}
|
|
242
|
-
} catch (error) {
|
|
243
|
-
accountInfo.Info = `Failed to get Puppeteer Chromium path: ${error.message}`;
|
|
244
|
-
return accountInfo;
|
|
245
249
|
}
|
|
246
250
|
}
|
|
247
251
|
|
|
248
252
|
// Verify Chromium executable
|
|
249
253
|
try {
|
|
250
254
|
const { stdout } = await execPromise(`"${chromiumPath}" --version`);
|
|
251
|
-
if (this.logDebug) this.emit('debug', `Chromium detected: ${stdout.trim()}`);
|
|
255
|
+
if (!this.logDebug) this.emit('debug', `Chromium for ${system} (${arch}) detected: ${stdout.trim()}`);
|
|
252
256
|
} catch (error) {
|
|
253
|
-
accountInfo.Info = `Chromium found at ${chromiumPath}, but
|
|
257
|
+
accountInfo.Info = `Chromium for ${system} (${arch}) found at ${chromiumPath}, but execute error: ${error.message}. Please install it manually and try again.`;
|
|
254
258
|
return accountInfo;
|
|
255
259
|
}
|
|
256
260
|
|
|
@@ -282,22 +286,22 @@ class MelCloudHome extends EventEmitter {
|
|
|
282
286
|
await client.send('Network.enable')
|
|
283
287
|
client.on('Network.webSocketCreated', ({ url }) => {
|
|
284
288
|
try {
|
|
285
|
-
if (url.startsWith(`${
|
|
289
|
+
if (url.startsWith(`${ApiUrls.Home.WebSocket}`)) {
|
|
286
290
|
const params = new URL(url).searchParams;
|
|
287
291
|
const hash = params.get('hash');
|
|
288
292
|
if (this.logDebug) this.emit('debug', `Web socket hash detected: ${hash}`);
|
|
289
293
|
|
|
290
|
-
//
|
|
294
|
+
// Web socket connection
|
|
291
295
|
if (!this.connecting && !this.socketConnected) {
|
|
292
296
|
this.connecting = true;
|
|
293
297
|
|
|
294
298
|
try {
|
|
295
299
|
const headers = {
|
|
296
|
-
'Origin':
|
|
300
|
+
'Origin': ApiUrls.Home.Base,
|
|
297
301
|
'Pragma': 'no-cache',
|
|
298
302
|
'Cache-Control': 'no-cache'
|
|
299
303
|
};
|
|
300
|
-
const webSocket = new WebSocket(`${
|
|
304
|
+
const webSocket = new WebSocket(`${ApiUrls.Home.WebSocket}${hash}`, { headers: headers })
|
|
301
305
|
.on('error', (error) => {
|
|
302
306
|
if (this.logError) this.emit('error', `Web socket error: ${error}`);
|
|
303
307
|
try {
|
|
@@ -326,7 +330,7 @@ class MelCloudHome extends EventEmitter {
|
|
|
326
330
|
})
|
|
327
331
|
.on('message', (message) => {
|
|
328
332
|
const parsedMessage = JSON.parse(message);
|
|
329
|
-
if (this.logDebug) this.emit('debug', `Incoming message: ${JSON.stringify(parsedMessage, null, 2)}`);
|
|
333
|
+
if (!this.logDebug) this.emit('debug', `Incoming message: ${JSON.stringify(parsedMessage, null, 2)}`);
|
|
330
334
|
if (parsedMessage.message === 'Forbidden') return;
|
|
331
335
|
|
|
332
336
|
this.emit('webSocket', parsedMessage);
|
|
@@ -343,9 +347,9 @@ class MelCloudHome extends EventEmitter {
|
|
|
343
347
|
});
|
|
344
348
|
|
|
345
349
|
try {
|
|
346
|
-
await page.goto(
|
|
350
|
+
await page.goto(ApiUrls.Home.Base, { waitUntil: ['domcontentloaded', 'networkidle2'], timeout: GLOBAL_TIMEOUT });
|
|
347
351
|
} catch (error) {
|
|
348
|
-
accountInfo.Info = `Navigation to ${
|
|
352
|
+
accountInfo.Info = `Navigation to ${ApiUrls.Home.Base} failed: ${error.message}`;
|
|
349
353
|
return accountInfo;
|
|
350
354
|
}
|
|
351
355
|
|
|
@@ -407,7 +411,7 @@ class MelCloudHome extends EventEmitter {
|
|
|
407
411
|
'Accept-Language': LanguageLocaleMap[this.language],
|
|
408
412
|
'Cookie': cookies,
|
|
409
413
|
'Priority': 'u=3, i',
|
|
410
|
-
'Referer':
|
|
414
|
+
'Referer': ApiUrls.Home.Dashboard,
|
|
411
415
|
'Sec-Fetch-Dest': 'empty',
|
|
412
416
|
'Sec-Fetch-Mode': 'cors',
|
|
413
417
|
'Sec-Fetch-Site': 'same-origin',
|
|
@@ -416,10 +420,10 @@ class MelCloudHome extends EventEmitter {
|
|
|
416
420
|
};
|
|
417
421
|
|
|
418
422
|
this.client = axios.create({
|
|
419
|
-
baseURL:
|
|
423
|
+
baseURL: ApiUrls.Home.Base,
|
|
420
424
|
timeout: 30000,
|
|
421
425
|
headers: headers
|
|
422
|
-
})
|
|
426
|
+
});
|
|
423
427
|
this.emit('client', this.client);
|
|
424
428
|
|
|
425
429
|
accountInfo.State = true;
|