homebridge-melcloud-control 2.5.0-beta.2 → 2.5.0-beta.21
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 +21 -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,8 @@
|
|
|
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');
|
|
67
|
+
document.getElementById('configButton').setAttribute('disabled');
|
|
68
68
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
69
69
|
this.deviceIndex = i;
|
|
70
70
|
});
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
pluginConfig[0].accounts[this.deviceIndex].language = document.querySelector('#language').value;
|
|
84
84
|
|
|
85
85
|
const accountConfigured = pluginConfig[0].accounts[i].name && pluginConfig[0].accounts[i].user && pluginConfig[0].accounts[i].passwd && pluginConfig[0].accounts[i].language;
|
|
86
|
-
const
|
|
86
|
+
const setButtonState = accountConfigured ? document.getElementById('logIn').removeAttribute('disabled') : document.getElementById('logIn').setAttribute('disabled');
|
|
87
87
|
|
|
88
88
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
89
89
|
await homebridge.savePluginConfig(pluginConfig);
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
|
|
102
102
|
try {
|
|
103
103
|
await homebridge.updatePluginConfig(pluginConfig)
|
|
104
|
-
document.getElementById('info').innerHTML = '';
|
|
104
|
+
document.getElementById('info').innerHTML = 'Connecting...';
|
|
105
105
|
|
|
106
106
|
const accountName = pluginConfig[0].accounts[this.deviceIndex].name;
|
|
107
107
|
const user = pluginConfig[0].accounts[this.deviceIndex].user;
|
|
@@ -111,7 +111,6 @@
|
|
|
111
111
|
const refreshInterval = pluginConfig[0].accounts[this.deviceIndex].refreshInterval;
|
|
112
112
|
|
|
113
113
|
const payload = {
|
|
114
|
-
mode: 'connect',
|
|
115
114
|
accountName: accountName,
|
|
116
115
|
user: user,
|
|
117
116
|
passwd: passwd,
|
|
@@ -120,77 +119,42 @@
|
|
|
120
119
|
refreshInterval: refreshInterval
|
|
121
120
|
};
|
|
122
121
|
const response = await homebridge.request('/connect', payload);
|
|
123
|
-
const info = response.info;
|
|
122
|
+
const info = response.info ?? '';
|
|
124
123
|
const status = response.status;
|
|
125
|
-
const
|
|
126
|
-
const error = response.error;
|
|
124
|
+
const devices = response.data ?? [];
|
|
127
125
|
|
|
128
126
|
switch (status) {
|
|
129
127
|
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
128
|
//get device info fom devices
|
|
167
129
|
for (const deviceInfo of devices) {
|
|
168
130
|
const deviceId = deviceInfo.DeviceID;
|
|
169
131
|
const deviceName = deviceInfo.DeviceName;
|
|
170
|
-
|
|
171
|
-
//prepare device if not in devices array
|
|
172
|
-
if (!devicesId.includes(deviceId)) {
|
|
173
|
-
devicesId.push(deviceId);
|
|
174
|
-
}
|
|
175
132
|
};
|
|
176
133
|
|
|
177
|
-
|
|
134
|
+
const devicesCount = devices.length;
|
|
135
|
+
document.getElementById('info').innerHTML = `Success, found ${devicesCount} ${devicesCount !== 1 ? 'devices' : 'device'}. Now You can start to configure it.`;
|
|
136
|
+
document.getElementById('info').style.color = 'green';
|
|
137
|
+
document.getElementById('configButton').removeAttribute('disabled');
|
|
178
138
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
179
139
|
await homebridge.savePluginConfig(pluginConfig);
|
|
180
140
|
break;
|
|
181
|
-
case
|
|
182
|
-
document.getElementById('info').innerHTML =
|
|
141
|
+
case 1:
|
|
142
|
+
document.getElementById('info').innerHTML = info;
|
|
183
143
|
document.getElementById('info').style.color = 'red';
|
|
184
144
|
break;
|
|
145
|
+
default:
|
|
146
|
+
document.getElementById('info').innerHTML = `Received unknown status: ${status}, please try again.`;
|
|
147
|
+
document.getElementById('info').style.color = 'yellow';
|
|
148
|
+
break;
|
|
185
149
|
};
|
|
186
150
|
|
|
187
151
|
homebridge.hideSpinner();
|
|
188
152
|
} catch (e) {
|
|
189
|
-
|
|
153
|
+
document.getElementById('info').innerHTML = 'Please try again.';
|
|
154
|
+
homebridge.toast.error(`Data error: ${e.message}`);
|
|
190
155
|
} finally {
|
|
191
156
|
homebridge.hideSpinner();
|
|
192
|
-
}
|
|
157
|
+
};
|
|
193
158
|
});
|
|
194
|
-
|
|
195
159
|
})();
|
|
196
160
|
</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: '',
|
|
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.21",
|
|
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) {
|