homebridge-melcloud-control 2.5.0-beta.2 → 2.5.0-beta.20
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/homebridge-ui/public/index.html +19 -57
- package/homebridge-ui/server.js +15 -38
- package/index.js +1 -1
- package/package.json +1 -1
- package/src/melcloud.js +59 -44
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<div id="melCloudAccount" style="display: none;" class="card card-body">
|
|
7
7
|
<form id="configForm">
|
|
8
8
|
<div class="text-center">
|
|
9
|
-
<label id="accountName" style="font-size: 23px">Account
|
|
9
|
+
<label id="accountName" style="font-size: 23px">Account</label><br>
|
|
10
10
|
<label id="info" style="text-align: center; font-size: 17px;">MELCloud</label><br><br>
|
|
11
11
|
</div>
|
|
12
12
|
<div class="form-group">
|
|
@@ -20,8 +20,7 @@
|
|
|
20
20
|
<input id="language" type="text" class="form-control"><br>
|
|
21
21
|
</div>
|
|
22
22
|
<div class="text-center">
|
|
23
|
-
<button id="logIn" type="button" class="btn btn-primary">
|
|
24
|
-
<button id="getDevices" type="button" class="btn btn-primary">Get Devices</button>
|
|
23
|
+
<button id="logIn" type="button" class="btn btn-primary">Connect to MELCloud</button>
|
|
25
24
|
<button id="configButton" type="button" class="btn btn-primary"><i class="fas fa-gear"></i></button>
|
|
26
25
|
</div>
|
|
27
26
|
</form>
|
|
@@ -64,7 +63,7 @@
|
|
|
64
63
|
document.getElementById('language').value = pluginConfig[0].accounts[i].language || '';
|
|
65
64
|
|
|
66
65
|
const accountConfigured = pluginConfig[0].accounts[i].name && pluginConfig[0].accounts[i].user && pluginConfig[0].accounts[i].passwd && pluginConfig[0].accounts[i].language;
|
|
67
|
-
const
|
|
66
|
+
const setButtonState = accountConfigured ? document.getElementById('logIn').removeAttribute('disabled') : document.getElementById('logIn').setAttribute('disabled');
|
|
68
67
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
69
68
|
this.deviceIndex = i;
|
|
70
69
|
});
|
|
@@ -83,7 +82,7 @@
|
|
|
83
82
|
pluginConfig[0].accounts[this.deviceIndex].language = document.querySelector('#language').value;
|
|
84
83
|
|
|
85
84
|
const accountConfigured = pluginConfig[0].accounts[i].name && pluginConfig[0].accounts[i].user && pluginConfig[0].accounts[i].passwd && pluginConfig[0].accounts[i].language;
|
|
86
|
-
const
|
|
85
|
+
const setButtonState = accountConfigured ? document.getElementById('logIn').removeAttribute('disabled') : document.getElementById('logIn').setAttribute('disabled');
|
|
87
86
|
|
|
88
87
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
89
88
|
await homebridge.savePluginConfig(pluginConfig);
|
|
@@ -101,7 +100,7 @@
|
|
|
101
100
|
|
|
102
101
|
try {
|
|
103
102
|
await homebridge.updatePluginConfig(pluginConfig)
|
|
104
|
-
document.getElementById('info').innerHTML = '';
|
|
103
|
+
document.getElementById('info').innerHTML = 'Connecting...';
|
|
105
104
|
|
|
106
105
|
const accountName = pluginConfig[0].accounts[this.deviceIndex].name;
|
|
107
106
|
const user = pluginConfig[0].accounts[this.deviceIndex].user;
|
|
@@ -111,7 +110,6 @@
|
|
|
111
110
|
const refreshInterval = pluginConfig[0].accounts[this.deviceIndex].refreshInterval;
|
|
112
111
|
|
|
113
112
|
const payload = {
|
|
114
|
-
mode: 'connect',
|
|
115
113
|
accountName: accountName,
|
|
116
114
|
user: user,
|
|
117
115
|
passwd: passwd,
|
|
@@ -120,77 +118,41 @@
|
|
|
120
118
|
refreshInterval: refreshInterval
|
|
121
119
|
};
|
|
122
120
|
const response = await homebridge.request('/connect', payload);
|
|
123
|
-
const info = response.info;
|
|
121
|
+
const info = response.info ?? '';
|
|
124
122
|
const status = response.status;
|
|
125
|
-
const
|
|
126
|
-
const error = response.error;
|
|
123
|
+
const devices = response.data ?? [];
|
|
127
124
|
|
|
128
125
|
switch (status) {
|
|
129
126
|
case 0:
|
|
130
|
-
document.getElementById('info').innerHTML = info;
|
|
131
|
-
document.getElementById('getDevices').removeAttribute('disabled');
|
|
132
|
-
break;
|
|
133
|
-
case 2:
|
|
134
|
-
document.getElementById('getDevices').setAttribute('disabled');
|
|
135
|
-
document.getElementById('info').innerHTML = `MELCloud error: ${JSON.stringify(error, null, 2)}`;
|
|
136
|
-
document.getElementById('info').style.color = 'red';
|
|
137
|
-
break;
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
homebridge.hideSpinner();
|
|
141
|
-
} catch (e) {
|
|
142
|
-
homebridge.toast.error(`Data error: ${e.message}`);
|
|
143
|
-
} finally {
|
|
144
|
-
homebridge.hideSpinner();
|
|
145
|
-
};
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
//get devices
|
|
149
|
-
document.getElementById('getDevices').addEventListener('click', async () => {
|
|
150
|
-
homebridge.showSpinner();
|
|
151
|
-
try {
|
|
152
|
-
const devicesId = [];
|
|
153
|
-
|
|
154
|
-
const payload = {
|
|
155
|
-
mode: 'getdevices'
|
|
156
|
-
};
|
|
157
|
-
const response = await homebridge.request('/getDevices', payload);
|
|
158
|
-
|
|
159
|
-
const info = response.info;
|
|
160
|
-
const status = response.status;
|
|
161
|
-
const devices = response.data;
|
|
162
|
-
const error = response.error;
|
|
163
|
-
|
|
164
|
-
switch (status) {
|
|
165
|
-
case 1:
|
|
166
127
|
//get device info fom devices
|
|
167
128
|
for (const deviceInfo of devices) {
|
|
168
129
|
const deviceId = deviceInfo.DeviceID;
|
|
169
130
|
const deviceName = deviceInfo.DeviceName;
|
|
170
|
-
|
|
171
|
-
//prepare device if not in devices array
|
|
172
|
-
if (!devicesId.includes(deviceId)) {
|
|
173
|
-
devicesId.push(deviceId);
|
|
174
|
-
}
|
|
175
131
|
};
|
|
176
132
|
|
|
177
|
-
|
|
133
|
+
const devicesCount = devices.length;
|
|
134
|
+
document.getElementById('info').innerHTML = `${info}, found ${devicesCount} ${devicesCount !== 1 ? 'devices' : 'device'}. Now You can start to configure it.`;
|
|
135
|
+
document.getElementById('info').style.color = 'green';
|
|
178
136
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
179
137
|
await homebridge.savePluginConfig(pluginConfig);
|
|
180
138
|
break;
|
|
181
|
-
case
|
|
182
|
-
document.getElementById('info').innerHTML =
|
|
139
|
+
case 1:
|
|
140
|
+
document.getElementById('info').innerHTML = info;
|
|
183
141
|
document.getElementById('info').style.color = 'red';
|
|
184
142
|
break;
|
|
143
|
+
default:
|
|
144
|
+
document.getElementById('info').innerHTML = `Received unknown status: ${status}, please try again.`;
|
|
145
|
+
document.getElementById('info').style.color = 'yellow';
|
|
146
|
+
break;
|
|
185
147
|
};
|
|
186
148
|
|
|
187
149
|
homebridge.hideSpinner();
|
|
188
150
|
} catch (e) {
|
|
189
|
-
|
|
151
|
+
document.getElementById('info').innerHTML = 'Please try again.';
|
|
152
|
+
homebridge.toast.error(`Data error: ${e.message}`);
|
|
190
153
|
} finally {
|
|
191
154
|
homebridge.hideSpinner();
|
|
192
|
-
}
|
|
155
|
+
};
|
|
193
156
|
});
|
|
194
|
-
|
|
195
157
|
})();
|
|
196
158
|
</script>
|
package/homebridge-ui/server.js
CHANGED
|
@@ -7,9 +7,6 @@ class PluginUiServer extends HomebridgePluginUiServer {
|
|
|
7
7
|
constructor() {
|
|
8
8
|
super();
|
|
9
9
|
|
|
10
|
-
//get devices
|
|
11
|
-
this.onRequest('/getdevices', this.start.bind(this));
|
|
12
|
-
|
|
13
10
|
//connect
|
|
14
11
|
this.onRequest('/connect', this.start.bind(this));
|
|
15
12
|
|
|
@@ -18,8 +15,6 @@ class PluginUiServer extends HomebridgePluginUiServer {
|
|
|
18
15
|
};
|
|
19
16
|
|
|
20
17
|
async start(payload) {
|
|
21
|
-
|
|
22
|
-
const mode = payload.mode;
|
|
23
18
|
const accountName = payload.accountName;
|
|
24
19
|
const user = payload.user;
|
|
25
20
|
const passwd = payload.passwd;
|
|
@@ -29,40 +24,22 @@ class PluginUiServer extends HomebridgePluginUiServer {
|
|
|
29
24
|
const accountInfoFile = `${this.homebridgeStoragePath}/melcloud/${accountName}_Account`;
|
|
30
25
|
const deviceInfoFile = `${this.homebridgeStoragePath}/melcloud/${accountName}_Device_`;
|
|
31
26
|
const buildingsFile = `${this.homebridgeStoragePath}/melcloud/${accountName}_Buildings`;
|
|
32
|
-
const melCloud = new MelCloud(user, passwd, language, accountInfoFile, deviceInfoFile, buildingsFile, enableDebugMode, refreshInterval);
|
|
33
27
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
};
|
|
50
|
-
};
|
|
51
|
-
case 'getdevices':
|
|
52
|
-
try {
|
|
53
|
-
const response = await melCloud.chackDevicesList();
|
|
54
|
-
return data = {
|
|
55
|
-
info: 'Get devices success.',
|
|
56
|
-
status: 0,
|
|
57
|
-
data: response
|
|
58
|
-
};
|
|
59
|
-
} catch (error) {
|
|
60
|
-
return data = {
|
|
61
|
-
info: 'Get devices error:',
|
|
62
|
-
status: 2,
|
|
63
|
-
data: error
|
|
64
|
-
};
|
|
65
|
-
};
|
|
28
|
+
try {
|
|
29
|
+
let data = {};
|
|
30
|
+
const melCloud = new MelCloud(user, passwd, language, accountInfoFile, deviceInfoFile, buildingsFile, enableDebugMode, refreshInterval, true);
|
|
31
|
+
const contextKey = await melCloud.connect();
|
|
32
|
+
const devices = await melCloud.chackDevicesList(contextKey);
|
|
33
|
+
return data = {
|
|
34
|
+
info: 'Success!',
|
|
35
|
+
status: 0,
|
|
36
|
+
data: devices
|
|
37
|
+
};
|
|
38
|
+
} catch (error) {
|
|
39
|
+
return data = {
|
|
40
|
+
info: error,
|
|
41
|
+
status: 1
|
|
42
|
+
};
|
|
66
43
|
};
|
|
67
44
|
};
|
|
68
45
|
};
|
package/index.js
CHANGED
|
@@ -78,7 +78,7 @@ class MelCloudPlatform {
|
|
|
78
78
|
const deviceRefreshInterval = account.deviceRefreshInterval * 1000 || 5000;
|
|
79
79
|
|
|
80
80
|
//melcloud account
|
|
81
|
-
const melCloud = new MelCloud(user, passwd, language, accountInfoFile, buildingsFile, deviceInfoFile, enableDebugMode, refreshInterval);
|
|
81
|
+
const melCloud = new MelCloud(user, passwd, language, accountInfoFile, buildingsFile, deviceInfoFile, enableDebugMode, refreshInterval, false);
|
|
82
82
|
melCloud.on('checkDevicesListComplete', (accountInfo, contextKey, deviceInfo) => {
|
|
83
83
|
const deviceId = deviceInfo.DeviceID.toString();
|
|
84
84
|
const deviceType = deviceInfo.Type;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"displayName": "MELCloud Control",
|
|
3
3
|
"name": "homebridge-melcloud-control",
|
|
4
|
-
"version": "2.5.0-beta.
|
|
4
|
+
"version": "2.5.0-beta.20",
|
|
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
|
@@ -8,13 +8,14 @@ const ImpulseGenerator = require('./impulsegenerator.js');
|
|
|
8
8
|
const CONSTANTS = require('./constants.json');
|
|
9
9
|
|
|
10
10
|
class MelCloud extends EventEmitter {
|
|
11
|
-
constructor(user, passwd, language, accountInfoFile, deviceInfoFile, buildingsFile, enableDebugMode, refreshInterval) {
|
|
11
|
+
constructor(user, passwd, language, accountInfoFile, deviceInfoFile, buildingsFile, enableDebugMode, refreshInterval, connectForConfig) {
|
|
12
12
|
super();
|
|
13
13
|
this.enableDebugMode = enableDebugMode;
|
|
14
14
|
this.accountInfoFile = accountInfoFile;
|
|
15
15
|
this.buildingsFile = buildingsFile;
|
|
16
16
|
this.deviceInfoFile = deviceInfoFile;
|
|
17
17
|
this.refreshInterval = refreshInterval;
|
|
18
|
+
this.connectForConfig = connectForConfig;
|
|
18
19
|
this.devicesId = [];
|
|
19
20
|
|
|
20
21
|
this.options = {
|
|
@@ -38,7 +39,9 @@ class MelCloud extends EventEmitter {
|
|
|
38
39
|
};
|
|
39
40
|
}).on('state', (state) => { });
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
if (!connectForConfig) {
|
|
43
|
+
this.connect();
|
|
44
|
+
};
|
|
42
45
|
};
|
|
43
46
|
|
|
44
47
|
async connect() {
|
|
@@ -79,56 +82,26 @@ class MelCloud extends EventEmitter {
|
|
|
79
82
|
return;
|
|
80
83
|
};
|
|
81
84
|
|
|
82
|
-
//create axios instance get
|
|
83
|
-
this.axiosInstanceGet = axios.create({
|
|
84
|
-
method: 'GET',
|
|
85
|
-
baseURL: CONSTANTS.ApiUrls.BaseURL,
|
|
86
|
-
timeout: 5000,
|
|
87
|
-
headers: {
|
|
88
|
-
'X-MitsContextKey': contextKey
|
|
89
|
-
},
|
|
90
|
-
maxContentLength: 100000000,
|
|
91
|
-
maxBodyLength: 1000000000,
|
|
92
|
-
withCredentials: true,
|
|
93
|
-
httpsAgent: new https.Agent({
|
|
94
|
-
keepAlive: false,
|
|
95
|
-
rejectUnauthorized: false
|
|
96
|
-
})
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
//create axios instance post
|
|
100
|
-
this.axiosInstancePost = axios.create({
|
|
101
|
-
method: 'POST',
|
|
102
|
-
baseURL: CONSTANTS.ApiUrls.BaseURL,
|
|
103
|
-
timeout: 5000,
|
|
104
|
-
headers: {
|
|
105
|
-
'X-MitsContextKey': contextKey,
|
|
106
|
-
'content-type': 'application/json'
|
|
107
|
-
},
|
|
108
|
-
maxContentLength: 100000000,
|
|
109
|
-
maxBodyLength: 1000000000,
|
|
110
|
-
withCredentials: true,
|
|
111
|
-
httpsAgent: new https.Agent({
|
|
112
|
-
keepAlive: false,
|
|
113
|
-
rejectUnauthorized: false
|
|
114
|
-
})
|
|
115
|
-
});
|
|
116
|
-
|
|
117
85
|
this.accountInfo = accountInfo;
|
|
118
86
|
this.contextKey = contextKey;
|
|
119
87
|
|
|
120
88
|
//save melcloud info to the file
|
|
121
89
|
await this.saveData(this.accountInfoFile, accountInfo);
|
|
122
90
|
|
|
91
|
+
//return if connect for config
|
|
92
|
+
if (this.connectForConfig) {
|
|
93
|
+
return contextKey;
|
|
94
|
+
};
|
|
95
|
+
|
|
123
96
|
//check devices list
|
|
124
|
-
await this.chackDevicesList();
|
|
97
|
+
await this.chackDevicesList(contextKey);
|
|
125
98
|
|
|
126
99
|
//emit connect success
|
|
127
100
|
this.emit('success', `Connect to MELCloud Success.`)
|
|
128
101
|
|
|
129
102
|
//start impulse generator
|
|
130
103
|
const timers = [{ name: 'checkDevicesList', sampling: this.refreshInterval }];
|
|
131
|
-
this.impulseGenerator.start(timers)
|
|
104
|
+
this.impulseGenerator.start(timers);
|
|
132
105
|
|
|
133
106
|
return true;
|
|
134
107
|
} catch (error) {
|
|
@@ -136,10 +109,29 @@ class MelCloud extends EventEmitter {
|
|
|
136
109
|
};
|
|
137
110
|
}
|
|
138
111
|
|
|
139
|
-
async chackDevicesList() {
|
|
112
|
+
async chackDevicesList(key) {
|
|
140
113
|
try {
|
|
114
|
+
const contextKey = this.contextKey ?? key;
|
|
115
|
+
|
|
116
|
+
//create axios instance get
|
|
117
|
+
const axiosInstanceGet = axios.create({
|
|
118
|
+
method: 'GET',
|
|
119
|
+
baseURL: CONSTANTS.ApiUrls.BaseURL,
|
|
120
|
+
timeout: 5000,
|
|
121
|
+
headers: {
|
|
122
|
+
'X-MitsContextKey': contextKey
|
|
123
|
+
},
|
|
124
|
+
maxContentLength: 100000000,
|
|
125
|
+
maxBodyLength: 1000000000,
|
|
126
|
+
withCredentials: true,
|
|
127
|
+
httpsAgent: new https.Agent({
|
|
128
|
+
keepAlive: false,
|
|
129
|
+
rejectUnauthorized: false
|
|
130
|
+
})
|
|
131
|
+
});
|
|
132
|
+
|
|
141
133
|
const debug = this.enableDebugMode ? this.emit('debug', `Scanning for devices.`) : false;
|
|
142
|
-
const listDevicesData = await
|
|
134
|
+
const listDevicesData = await axiosInstanceGet(CONSTANTS.ApiUrls.ListDevices);
|
|
143
135
|
const buildingsList = listDevicesData.data;
|
|
144
136
|
const debug1 = this.enableDebugMode ? this.emit('debug', `Buildings: ${JSON.stringify(buildingsList, null, 2)}`) : false;
|
|
145
137
|
|
|
@@ -175,6 +167,11 @@ class MelCloud extends EventEmitter {
|
|
|
175
167
|
}
|
|
176
168
|
const debug3 = this.enableDebugMode ? this.emit('debug', `Found: ${devicesCount} devices.`) : false;
|
|
177
169
|
|
|
170
|
+
//return devices list for config
|
|
171
|
+
if (this.connectForConfig) {
|
|
172
|
+
return devices;
|
|
173
|
+
};
|
|
174
|
+
|
|
178
175
|
//get device info fom devices
|
|
179
176
|
for (const deviceInfo of devices) {
|
|
180
177
|
const deviceId = deviceInfo.DeviceID
|
|
@@ -188,11 +185,11 @@ class MelCloud extends EventEmitter {
|
|
|
188
185
|
//prepare device if not in devices array
|
|
189
186
|
if (!this.devicesId.includes(deviceId)) {
|
|
190
187
|
this.devicesId.push(deviceId);
|
|
191
|
-
this.emit('checkDevicesListComplete', this.accountInfo,
|
|
188
|
+
this.emit('checkDevicesListComplete', this.accountInfo, contextKey, deviceInfo);
|
|
192
189
|
}
|
|
193
190
|
};
|
|
194
191
|
|
|
195
|
-
return
|
|
192
|
+
return true;
|
|
196
193
|
} catch (error) {
|
|
197
194
|
this.impulseGenerator.stop();
|
|
198
195
|
throw new Error(`Scanning for devices error: ${error.message ?? error}.`);
|
|
@@ -211,11 +208,29 @@ class MelCloud extends EventEmitter {
|
|
|
211
208
|
|
|
212
209
|
async send(accountInfo) {
|
|
213
210
|
try {
|
|
211
|
+
//create axios instance post
|
|
212
|
+
const axiosInstancePost = axios.create({
|
|
213
|
+
method: 'POST',
|
|
214
|
+
baseURL: CONSTANTS.ApiUrls.BaseURL,
|
|
215
|
+
timeout: 5000,
|
|
216
|
+
headers: {
|
|
217
|
+
'X-MitsContextKey': this.contextKey,
|
|
218
|
+
'content-type': 'application/json'
|
|
219
|
+
},
|
|
220
|
+
maxContentLength: 100000000,
|
|
221
|
+
maxBodyLength: 1000000000,
|
|
222
|
+
withCredentials: true,
|
|
223
|
+
httpsAgent: new https.Agent({
|
|
224
|
+
keepAlive: false,
|
|
225
|
+
rejectUnauthorized: false
|
|
226
|
+
})
|
|
227
|
+
});
|
|
228
|
+
|
|
214
229
|
const options = {
|
|
215
230
|
data: accountInfo
|
|
216
231
|
};
|
|
217
232
|
|
|
218
|
-
await
|
|
233
|
+
await axiosInstancePost(CONSTANTS.ApiUrls.UpdateApplicationOptions, options);
|
|
219
234
|
await this.saveData(this.accountInfoFile, accountInfo);
|
|
220
235
|
return true;
|
|
221
236
|
} catch (error) {
|