homebridge-melcloud-control 4.0.0-beta.307 → 4.0.0-beta.309
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 +17 -5
- package/src/melcloudhometoken.js +46 -6
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.309",
|
|
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
|
@@ -284,14 +284,27 @@ class MelCloud extends EventEmitter {
|
|
|
284
284
|
async connectToMelCloudHome() {
|
|
285
285
|
let browser;
|
|
286
286
|
try {
|
|
287
|
+
|
|
288
|
+
const melCloudHomeToken = new MelCloudHomeToken({
|
|
289
|
+
user: this.user,
|
|
290
|
+
passwd: this.passwd,
|
|
291
|
+
logWarn: this.logWarn,
|
|
292
|
+
logError: this.logError,
|
|
293
|
+
})
|
|
294
|
+
.on('success', message => this.emit('success', message))
|
|
295
|
+
.on('warn', warn => this.emit('warn', warn))
|
|
296
|
+
.on('error', error => this.emit('error', error));
|
|
297
|
+
|
|
298
|
+
const data = await melCloudHomeToken.buildAuthorizeUrl();
|
|
299
|
+
const code = await melCloudHomeToken.loginToMelCloudHome(data.url);
|
|
300
|
+
|
|
301
|
+
return false
|
|
302
|
+
|
|
287
303
|
browser = await puppeteer.launch({
|
|
288
304
|
headless: true,
|
|
289
305
|
args: ['--no-sandbox', '--disable-setuid-sandbox']
|
|
290
306
|
});
|
|
291
307
|
|
|
292
|
-
const melCloudHomeToken = new MelCloudHomeToken();
|
|
293
|
-
const data = await melCloudHomeToken.buildAuthorizeUrl();
|
|
294
|
-
|
|
295
308
|
const page = await browser.newPage();
|
|
296
309
|
await page.goto(data.url, { waitUntil: 'networkidle2' });
|
|
297
310
|
|
|
@@ -301,7 +314,7 @@ class MelCloud extends EventEmitter {
|
|
|
301
314
|
const button1 = await page.$('input[type="submit"]');
|
|
302
315
|
await Promise.all([button1.click(), page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 10000 })]);
|
|
303
316
|
const html = await page.content();
|
|
304
|
-
const
|
|
317
|
+
const code1 = await melCloudHomeToken.extractCodeFromHtml(html);
|
|
305
318
|
this.emit('warn', code);
|
|
306
319
|
|
|
307
320
|
// 5. Wymień code na access_token
|
|
@@ -321,7 +334,6 @@ class MelCloud extends EventEmitter {
|
|
|
321
334
|
}
|
|
322
335
|
}
|
|
323
336
|
|
|
324
|
-
|
|
325
337
|
async connectToMelCloudHome1(refresh = false) {
|
|
326
338
|
if (this.logDebug) this.emit('debug', `Connecting to MELCloud Home`);
|
|
327
339
|
|
package/src/melcloudhometoken.js
CHANGED
|
@@ -2,6 +2,7 @@ import axios from 'axios';
|
|
|
2
2
|
import crypto from 'crypto';
|
|
3
3
|
import { wrapper } from 'axios-cookiejar-support';
|
|
4
4
|
import { CookieJar } from 'tough-cookie';
|
|
5
|
+
import EventEmitter from 'events';
|
|
5
6
|
|
|
6
7
|
const MOBILE_USER_AGENT = 'MonitorAndControl.App.Mobile/35 CFNetwork/3860.100.1 Darwin/25.0.0';
|
|
7
8
|
const CLIENT_ID = 'homemobile';
|
|
@@ -10,8 +11,14 @@ const SCOPE = 'openid profile email offline_access IdentityServerApi';
|
|
|
10
11
|
const TOKEN_ENDPOINT = 'https://auth.melcloudhome.com/connect/token';
|
|
11
12
|
const AUTHORIZE_ENDPOINT = 'https://auth.melcloudhome.com/connect/authorize';
|
|
12
13
|
|
|
13
|
-
class MelCloudHomeToken {
|
|
14
|
-
constructor() {
|
|
14
|
+
class MelCloudHomeToken extends EventEmitter {
|
|
15
|
+
constructor(config) {
|
|
16
|
+
super();
|
|
17
|
+
this.user = config.user;
|
|
18
|
+
this.passwd = config.passwd;
|
|
19
|
+
this.serialNumber = config.serialNumber;
|
|
20
|
+
this.logWarn = config.logWarn;
|
|
21
|
+
this.logError = config.logError;
|
|
15
22
|
const jar = new CookieJar();
|
|
16
23
|
this.client = wrapper(axios.create({ jar, withCredentials: true }));
|
|
17
24
|
this.client.defaults.headers['User-Agent'] = MOBILE_USER_AGENT;
|
|
@@ -90,8 +97,7 @@ class MelCloudHomeToken {
|
|
|
90
97
|
url: TOKEN_ENDPOINT,
|
|
91
98
|
headers: {
|
|
92
99
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
93
|
-
'Content-Length': data.toString().length
|
|
94
|
-
'Authorization': 'Basic aG9tZW1vYmlsZTo='
|
|
100
|
+
'Content-Length': data.toString().length
|
|
95
101
|
},
|
|
96
102
|
data: data
|
|
97
103
|
});
|
|
@@ -107,7 +113,6 @@ class MelCloudHomeToken {
|
|
|
107
113
|
}
|
|
108
114
|
}
|
|
109
115
|
|
|
110
|
-
|
|
111
116
|
async buildAuthorizeUrl() {
|
|
112
117
|
try {
|
|
113
118
|
const pkce = this.generatePKCE();
|
|
@@ -120,8 +125,8 @@ class MelCloudHomeToken {
|
|
|
120
125
|
authUrl.searchParams.set('code_challenge', pkce.challenge);
|
|
121
126
|
authUrl.searchParams.set('code_challenge_method', 'S256');
|
|
122
127
|
authUrl.searchParams.set('state', state);
|
|
123
|
-
const loginPage = await this.getLoginPage(authUrl.toString());
|
|
124
128
|
|
|
129
|
+
const loginPage = await this.getLoginPage(authUrl.toString());
|
|
125
130
|
const data = { codeVerifier: pkce.verifier, url: loginPage.url }
|
|
126
131
|
return data;
|
|
127
132
|
} catch (error) {
|
|
@@ -129,6 +134,41 @@ class MelCloudHomeToken {
|
|
|
129
134
|
throw error;
|
|
130
135
|
}
|
|
131
136
|
}
|
|
137
|
+
|
|
138
|
+
async loginToMelCloudHome(url) {
|
|
139
|
+
try {
|
|
140
|
+
const form = new URLSearchParams();
|
|
141
|
+
form.append('user[email]', this.user);
|
|
142
|
+
form.append('user[password]', this.passwd);
|
|
143
|
+
|
|
144
|
+
const response = await axios({
|
|
145
|
+
method: 'POST',
|
|
146
|
+
baseURL: url,
|
|
147
|
+
headers: {
|
|
148
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
149
|
+
},
|
|
150
|
+
data: form,
|
|
151
|
+
timeout: 10000
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
this.emit('warn', `No cookie returned from login. Response headers: ${JSON.stringify(response)}`);
|
|
155
|
+
|
|
156
|
+
if (response.status !== 200) {
|
|
157
|
+
if (this.logError) this.emit('error', `Login failed with status code: ${response.status}`);
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const cookie = response.headers['set-cookie'];
|
|
162
|
+
if (!cookie) {
|
|
163
|
+
if (this.logWarn) this.emit('warn', `No cookie returned from login. Response headers: ${JSON.stringify(response.headers)}`);
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return cookie;
|
|
168
|
+
} catch (error) {
|
|
169
|
+
throw new Error(`Login to Enlighten error: ${error}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
132
172
|
}
|
|
133
173
|
|
|
134
174
|
export default MelCloudHomeToken;
|