homebridge-melcloud-control 2.5.0-beta.5 → 2.5.0-beta.51
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/config.schema.json +201 -0
- package/homebridge-ui/public/index.html +73 -33
- package/homebridge-ui/server.js +10 -42
- package/index.js +1 -1
- package/package.json +1 -1
- package/src/melcloud.js +68 -59
package/config.schema.json
CHANGED
|
@@ -205,6 +205,174 @@
|
|
|
205
205
|
"description": "Here select the language used in MELCloud account.",
|
|
206
206
|
"required": true
|
|
207
207
|
},
|
|
208
|
+
"ataDevices": {
|
|
209
|
+
"title": "Devices ATA",
|
|
210
|
+
"type": "array",
|
|
211
|
+
"items": {
|
|
212
|
+
"type": "object",
|
|
213
|
+
"properties": {
|
|
214
|
+
"name": {
|
|
215
|
+
"title": "Name",
|
|
216
|
+
"type": "string",
|
|
217
|
+
"readOnly": true,
|
|
218
|
+
"required": false
|
|
219
|
+
},
|
|
220
|
+
"id": {
|
|
221
|
+
"title": "ID",
|
|
222
|
+
"type": "integer",
|
|
223
|
+
"readOnly": true,
|
|
224
|
+
"required": false
|
|
225
|
+
},
|
|
226
|
+
"type": {
|
|
227
|
+
"title": "Type",
|
|
228
|
+
"type": "integer",
|
|
229
|
+
"readOnly": true,
|
|
230
|
+
"required": false
|
|
231
|
+
},
|
|
232
|
+
"displayMode": {
|
|
233
|
+
"title": "Control",
|
|
234
|
+
"type": "integer",
|
|
235
|
+
"minimum": 0,
|
|
236
|
+
"maximum": 2,
|
|
237
|
+
"oneOf": [
|
|
238
|
+
{
|
|
239
|
+
"title": "None/Disabled",
|
|
240
|
+
"enum": [
|
|
241
|
+
0
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"title": "Heater/Cooler",
|
|
246
|
+
"enum": [
|
|
247
|
+
0
|
|
248
|
+
]
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"title": "Thermostat",
|
|
252
|
+
"enum": [
|
|
253
|
+
1
|
|
254
|
+
]
|
|
255
|
+
}
|
|
256
|
+
],
|
|
257
|
+
"description": "Select device control mode displayed in HomeKit app.",
|
|
258
|
+
"required": true
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
"required": false
|
|
263
|
+
},
|
|
264
|
+
"atwDevices": {
|
|
265
|
+
"title": "Devices ATW",
|
|
266
|
+
"type": "array",
|
|
267
|
+
"items": {
|
|
268
|
+
"type": "object",
|
|
269
|
+
"properties": {
|
|
270
|
+
"name": {
|
|
271
|
+
"title": "Name",
|
|
272
|
+
"type": "string",
|
|
273
|
+
"readOnly": true,
|
|
274
|
+
"required": false
|
|
275
|
+
},
|
|
276
|
+
"id": {
|
|
277
|
+
"title": "Mode",
|
|
278
|
+
"type": "integer",
|
|
279
|
+
"readOnly": true,
|
|
280
|
+
"required": false
|
|
281
|
+
},
|
|
282
|
+
"type": {
|
|
283
|
+
"title": "Type",
|
|
284
|
+
"type": "integer",
|
|
285
|
+
"readOnly": true,
|
|
286
|
+
"required": false
|
|
287
|
+
},
|
|
288
|
+
"displayMode": {
|
|
289
|
+
"title": "Control",
|
|
290
|
+
"type": "integer",
|
|
291
|
+
"minimum": 0,
|
|
292
|
+
"maximum": 2,
|
|
293
|
+
"oneOf": [
|
|
294
|
+
{
|
|
295
|
+
"title": "None/Disabled",
|
|
296
|
+
"enum": [
|
|
297
|
+
0
|
|
298
|
+
]
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"title": "Heater/Cooler",
|
|
302
|
+
"enum": [
|
|
303
|
+
0
|
|
304
|
+
]
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
"title": "Thermostat",
|
|
308
|
+
"enum": [
|
|
309
|
+
1
|
|
310
|
+
]
|
|
311
|
+
}
|
|
312
|
+
],
|
|
313
|
+
"description": "Select device control mode displayed in HomeKit app.",
|
|
314
|
+
"required": true
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
"required": false
|
|
319
|
+
},
|
|
320
|
+
"ervDevices": {
|
|
321
|
+
"title": "Devices ERV",
|
|
322
|
+
"type": "array",
|
|
323
|
+
"items": {
|
|
324
|
+
"type": "object",
|
|
325
|
+
"properties": {
|
|
326
|
+
"name": {
|
|
327
|
+
"title": "Name",
|
|
328
|
+
"type": "string",
|
|
329
|
+
"readOnly": true,
|
|
330
|
+
"required": false
|
|
331
|
+
},
|
|
332
|
+
"id": {
|
|
333
|
+
"title": "Mode",
|
|
334
|
+
"type": "integer",
|
|
335
|
+
"readOnly": true,
|
|
336
|
+
"required": false
|
|
337
|
+
},
|
|
338
|
+
"type": {
|
|
339
|
+
"title": "Type",
|
|
340
|
+
"type": "integer",
|
|
341
|
+
"readOnly": true,
|
|
342
|
+
"required": false
|
|
343
|
+
},
|
|
344
|
+
"displayMode": {
|
|
345
|
+
"title": "Control",
|
|
346
|
+
"type": "integer",
|
|
347
|
+
"minimum": 0,
|
|
348
|
+
"maximum": 2,
|
|
349
|
+
"oneOf": [
|
|
350
|
+
{
|
|
351
|
+
"title": "None/Disabled",
|
|
352
|
+
"enum": [
|
|
353
|
+
0
|
|
354
|
+
]
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
"title": "Heater/Cooler",
|
|
358
|
+
"enum": [
|
|
359
|
+
0
|
|
360
|
+
]
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"title": "Thermostat",
|
|
364
|
+
"enum": [
|
|
365
|
+
1
|
|
366
|
+
]
|
|
367
|
+
}
|
|
368
|
+
],
|
|
369
|
+
"description": "Select device control mode displayed in HomeKit app.",
|
|
370
|
+
"required": true
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
"required": false
|
|
375
|
+
},
|
|
208
376
|
"ataDisplayMode": {
|
|
209
377
|
"title": "Control",
|
|
210
378
|
"type": "integer",
|
|
@@ -1429,6 +1597,17 @@
|
|
|
1429
1597
|
"key": "accounts[]",
|
|
1430
1598
|
"title": "Air Conditioner",
|
|
1431
1599
|
"items": [
|
|
1600
|
+
{
|
|
1601
|
+
"key": "accounts[].ataDevices",
|
|
1602
|
+
"type": "tabarray",
|
|
1603
|
+
"title": "{{ value.name }}",
|
|
1604
|
+
"items": [
|
|
1605
|
+
"accounts[].ataDevices[].name",
|
|
1606
|
+
"accounts[].ataDevices[].id",
|
|
1607
|
+
"accounts[].ataDevices[].type",
|
|
1608
|
+
"accounts[].ataDevices[].displayMode"
|
|
1609
|
+
]
|
|
1610
|
+
},
|
|
1432
1611
|
"accounts[].ataDisplayMode",
|
|
1433
1612
|
"accounts[].ataPresets",
|
|
1434
1613
|
{
|
|
@@ -1498,6 +1677,17 @@
|
|
|
1498
1677
|
"key": "accounts[]",
|
|
1499
1678
|
"title": "Heat Pump",
|
|
1500
1679
|
"items": [
|
|
1680
|
+
{
|
|
1681
|
+
"key": "accounts[].atwDevices",
|
|
1682
|
+
"type": "tabarray",
|
|
1683
|
+
"title": "{{ value.name }}",
|
|
1684
|
+
"items": [
|
|
1685
|
+
"accounts[].atwDevices[].name",
|
|
1686
|
+
"accounts[].atwDevices[].id",
|
|
1687
|
+
"accounts[].atwDevices[].type",
|
|
1688
|
+
"accounts[].atwDevices[].displayMode"
|
|
1689
|
+
]
|
|
1690
|
+
},
|
|
1501
1691
|
"accounts[].atwDisplayMode",
|
|
1502
1692
|
"accounts[].atwPresets",
|
|
1503
1693
|
{
|
|
@@ -1562,6 +1752,17 @@
|
|
|
1562
1752
|
"key": "accounts[]",
|
|
1563
1753
|
"title": "Energy Recovery Ventilation",
|
|
1564
1754
|
"items": [
|
|
1755
|
+
{
|
|
1756
|
+
"key": "accounts[].ervDevices",
|
|
1757
|
+
"type": "tabarray",
|
|
1758
|
+
"title": "{{ value.name }}",
|
|
1759
|
+
"items": [
|
|
1760
|
+
"accounts[].ervDevices[].name",
|
|
1761
|
+
"accounts[].ervDevices[].id",
|
|
1762
|
+
"accounts[].ervDevices[].type",
|
|
1763
|
+
"accounts[].ervDevices[].displayMode"
|
|
1764
|
+
]
|
|
1765
|
+
},
|
|
1565
1766
|
"accounts[].ervDisplayMode",
|
|
1566
1767
|
"accounts[].ervPresets",
|
|
1567
1768
|
{
|
|
@@ -6,21 +6,48 @@
|
|
|
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">
|
|
13
13
|
<label for="name">Name</label>
|
|
14
14
|
<input id="name" type="text" class="form-control"><br>
|
|
15
|
-
<label for="user">
|
|
15
|
+
<label for="user">User Name</label>
|
|
16
16
|
<input id="user" type="text" class="form-control"><br>
|
|
17
|
-
<label for="passwd">
|
|
18
|
-
<input id="passwd" type="
|
|
17
|
+
<label for="passwd">Password</label>
|
|
18
|
+
<input id="passwd" type="password" class="form-control"><br>
|
|
19
19
|
<label for="language">Language</label>
|
|
20
|
-
<
|
|
20
|
+
<select id="language" name="language" class="form-control"><br>
|
|
21
|
+
<option value="0">English</option>
|
|
22
|
+
<option value="1">Български</option>
|
|
23
|
+
<option value="2">Čeština</option>
|
|
24
|
+
<option value="3">Dansk</option>
|
|
25
|
+
<option value="4">Deutsch</option>
|
|
26
|
+
<option value="5">Eesti</option>
|
|
27
|
+
<option value="6">Español</option>
|
|
28
|
+
<option value="7">Français</option>
|
|
29
|
+
<option value="8">Հայերեն</option>
|
|
30
|
+
<option value="9">Latviešu</option>
|
|
31
|
+
<option value="10">Lietuvių</option>
|
|
32
|
+
<option value="11">Magyar</option>
|
|
33
|
+
<option value="12">Nederlands</option>
|
|
34
|
+
<option value="13">Norwegian</option>
|
|
35
|
+
<option value="14">Polski</option>
|
|
36
|
+
<option value="15">Português</option>
|
|
37
|
+
<option value="16">Русский</option>
|
|
38
|
+
<option value="17">Suomi</option>
|
|
39
|
+
<option value="18">Svenska</option>
|
|
40
|
+
<option value="19">Svenska</option>
|
|
41
|
+
<option value="20">Українська</option>
|
|
42
|
+
<option value="21">Türkçe</option>
|
|
43
|
+
<option value="22">Ελληνικά</option>
|
|
44
|
+
<option value="23">Hrvatski</option>
|
|
45
|
+
<option value="24">Română</option>
|
|
46
|
+
<option value="25">Slovenščina</option>
|
|
47
|
+
</select>
|
|
21
48
|
</div>
|
|
22
49
|
<div class="text-center">
|
|
23
|
-
<button id="logIn" type="button" class="btn btn-primary">
|
|
50
|
+
<button id="logIn" type="button" class="btn btn-primary">Connect to MELCloud</button>
|
|
24
51
|
<button id="configButton" type="button" class="btn btn-primary"><i class="fas fa-gear"></i></button>
|
|
25
52
|
</div>
|
|
26
53
|
</form>
|
|
@@ -56,6 +83,8 @@
|
|
|
56
83
|
const setRemoveAtribute = j === i ? document.getElementById(`button${j}`).setAttribute("class", "btn btn-secondary") : document.getElementById(`button${j}`).setAttribute("class", "btn btn-primary");
|
|
57
84
|
}
|
|
58
85
|
|
|
86
|
+
//const devicesCount = pluginConfig[0].accounts[i].devicesAta.length ?? 0;
|
|
87
|
+
//document.getElementById('info').innerHTML = `MELCloud configured ${devicesCount} ${devicesCount} ${devicesCount !== 1 ? 'devices' : 'device'}.`;
|
|
59
88
|
document.getElementById('accountName').innerHTML = pluginConfig[0].accounts[i].name || '';
|
|
60
89
|
document.getElementById('name').value = pluginConfig[0].accounts[i].name || '';
|
|
61
90
|
document.getElementById('user').value = pluginConfig[0].accounts[i].user || '';
|
|
@@ -63,7 +92,8 @@
|
|
|
63
92
|
document.getElementById('language').value = pluginConfig[0].accounts[i].language || '';
|
|
64
93
|
|
|
65
94
|
const accountConfigured = pluginConfig[0].accounts[i].name && pluginConfig[0].accounts[i].user && pluginConfig[0].accounts[i].passwd && pluginConfig[0].accounts[i].language;
|
|
66
|
-
const
|
|
95
|
+
const setButtonState = accountConfigured ? document.getElementById('logIn').removeAttribute('disabled') : document.getElementById('logIn').setAttribute('disabled');
|
|
96
|
+
document.getElementById('configButton').setAttribute('disabled');
|
|
67
97
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
68
98
|
this.deviceIndex = i;
|
|
69
99
|
});
|
|
@@ -82,7 +112,7 @@
|
|
|
82
112
|
pluginConfig[0].accounts[this.deviceIndex].language = document.querySelector('#language').value;
|
|
83
113
|
|
|
84
114
|
const accountConfigured = pluginConfig[0].accounts[i].name && pluginConfig[0].accounts[i].user && pluginConfig[0].accounts[i].passwd && pluginConfig[0].accounts[i].language;
|
|
85
|
-
const
|
|
115
|
+
const setButtonState = accountConfigured ? document.getElementById('logIn').removeAttribute('disabled') : document.getElementById('logIn').setAttribute('disabled');
|
|
86
116
|
|
|
87
117
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
88
118
|
await homebridge.savePluginConfig(pluginConfig);
|
|
@@ -106,60 +136,70 @@
|
|
|
106
136
|
const user = pluginConfig[0].accounts[this.deviceIndex].user;
|
|
107
137
|
const passwd = pluginConfig[0].accounts[this.deviceIndex].passwd;
|
|
108
138
|
const language = pluginConfig[0].accounts[this.deviceIndex].language;
|
|
109
|
-
const enableDebugMode = pluginConfig[0].accounts[this.deviceIndex].enableDebugMode;
|
|
110
|
-
const refreshInterval = pluginConfig[0].accounts[this.deviceIndex].refreshInterval;
|
|
111
139
|
|
|
112
140
|
const payload = {
|
|
113
141
|
accountName: accountName,
|
|
114
142
|
user: user,
|
|
115
143
|
passwd: passwd,
|
|
116
|
-
language: language
|
|
117
|
-
enableDebugMode: enableDebugMode,
|
|
118
|
-
refreshInterval: refreshInterval
|
|
144
|
+
language: language
|
|
119
145
|
};
|
|
120
146
|
const response = await homebridge.request('/connect', payload);
|
|
121
|
-
const info = response.info;
|
|
147
|
+
const info = response.info ?? '';
|
|
122
148
|
const status = response.status;
|
|
123
149
|
const devices = response.data ?? [];
|
|
150
|
+
const newDevices = [];
|
|
124
151
|
|
|
125
152
|
switch (status) {
|
|
126
153
|
case 0:
|
|
127
|
-
|
|
128
154
|
//get device info fom devices
|
|
129
|
-
|
|
155
|
+
devices.forEach((deviceInfo, index) => {
|
|
156
|
+
const deviceType = deviceInfo.Type;
|
|
130
157
|
const deviceId = deviceInfo.DeviceID;
|
|
131
158
|
const deviceName = deviceInfo.DeviceName;
|
|
132
|
-
|
|
159
|
+
const device = { name: deviceName, id: deviceId, type: deviceType, displayMode: 0 };
|
|
160
|
+
|
|
161
|
+
//config account keys
|
|
162
|
+
const accountKeys = Object.keys(pluginConfig[0].accounts[this.deviceIndex]);
|
|
163
|
+
|
|
164
|
+
//devices ata
|
|
165
|
+
const ataDevices = accountKeys.includes('ataDevices') ? pluginConfig[0].accounts[this.deviceIndex].ataDevices : pluginConfig[0].accounts[this.deviceIndex].ataDevices = [];
|
|
166
|
+
const ataDeviceIdExist = ataDevices.some(device => device.id === deviceId)
|
|
167
|
+
const pushTypeAta = deviceType === 0 && !ataDeviceIdExist ? ataDevices.push(device) : false;
|
|
168
|
+
|
|
169
|
+
//devices atw
|
|
170
|
+
const atwDevices = accountKeys.includes('atwDevices') ? pluginConfig[0].accounts[this.deviceIndex].atwDevices : pluginConfig[0].accounts[this.deviceIndex].atwDevices = [];
|
|
171
|
+
const atwDeviceIdExist = atwDevices.some(device => device.id === deviceId)
|
|
172
|
+
const pushTypeAtw = deviceType === 1 && !atwDeviceIdExist ? atwDevices.push(device) : false;
|
|
173
|
+
|
|
174
|
+
//devices erv
|
|
175
|
+
const ervDevices = accountKeys.includes('ervDevices') ? pluginConfig[0].accounts[this.deviceIndex].ervDevices : pluginConfig[0].accounts[this.deviceIndex].ervDevices = [];
|
|
176
|
+
const ervDeviceIdExist = ervDevices.some(device => device.id === deviceId)
|
|
177
|
+
const pushTypeErv = deviceType === 3 && !ervDeviceIdExist ? ervDevices.push(device) : false;
|
|
133
178
|
|
|
134
|
-
|
|
179
|
+
//push new devices to array
|
|
180
|
+
const pushNewDevice = ataDeviceIdExist || atwDeviceIdExist || ervDeviceIdExist ? false : newDevices.push(deviceId);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const devicesCount = newDevices.length;
|
|
184
|
+
document.getElementById('info').innerHTML = `Check devices complete, found ${devicesCount} ${devicesCount !== 1 ? 'new devices' : 'new device'}. ${devicesCount === 0 ? '' : 'Now You can start to configure it'}.`;
|
|
135
185
|
document.getElementById('info').style.color = 'green';
|
|
186
|
+
|
|
136
187
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
137
188
|
await homebridge.savePluginConfig(pluginConfig);
|
|
138
189
|
break;
|
|
139
190
|
case 1:
|
|
140
191
|
document.getElementById('info').innerHTML = info;
|
|
141
|
-
document.getElementById('info').style.color = '
|
|
142
|
-
break;
|
|
143
|
-
case 2:
|
|
144
|
-
document.getElementById('info').innerHTML = info;
|
|
145
|
-
document.getElementById('info').style.color = 'white';
|
|
146
|
-
break;
|
|
147
|
-
case 3:
|
|
148
|
-
document.getElementById('info').innerHTML = info;
|
|
149
|
-
document.getElementById('info').style.color = 'gray';
|
|
192
|
+
document.getElementById('info').style.color = 'red';
|
|
150
193
|
break;
|
|
151
|
-
|
|
152
|
-
document.getElementById('info').innerHTML =
|
|
194
|
+
default:
|
|
195
|
+
document.getElementById('info').innerHTML = `Received unknown status: ${status}, please try again.`;
|
|
153
196
|
document.getElementById('info').style.color = 'yellow';
|
|
154
197
|
break;
|
|
155
|
-
case 5:
|
|
156
|
-
document.getElementById('info').innerHTML = info;
|
|
157
|
-
document.getElementById('info').style.color = 'red';
|
|
158
|
-
break;
|
|
159
198
|
};
|
|
160
199
|
|
|
161
200
|
homebridge.hideSpinner();
|
|
162
201
|
} catch (e) {
|
|
202
|
+
document.getElementById('info').innerHTML = 'Please try again.';
|
|
163
203
|
homebridge.toast.error(`Data error: ${e.message}`);
|
|
164
204
|
} finally {
|
|
165
205
|
homebridge.hideSpinner();
|
package/homebridge-ui/server.js
CHANGED
|
@@ -19,56 +19,24 @@ class PluginUiServer extends HomebridgePluginUiServer {
|
|
|
19
19
|
const user = payload.user;
|
|
20
20
|
const passwd = payload.passwd;
|
|
21
21
|
const language = payload.language;
|
|
22
|
-
const enableDebugMode = payload.enableDebugMode;
|
|
23
|
-
const refreshInterval = payload.refreshInterval;
|
|
24
22
|
const accountInfoFile = `${this.homebridgeStoragePath}/melcloud/${accountName}_Account`;
|
|
25
23
|
const deviceInfoFile = `${this.homebridgeStoragePath}/melcloud/${accountName}_Device_`;
|
|
26
24
|
const buildingsFile = `${this.homebridgeStoragePath}/melcloud/${accountName}_Buildings`;
|
|
27
|
-
let data = {};
|
|
28
25
|
|
|
29
26
|
try {
|
|
30
|
-
|
|
31
|
-
melCloud
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return data = {
|
|
40
|
-
info: message,
|
|
41
|
-
status: 1
|
|
42
|
-
};
|
|
43
|
-
})
|
|
44
|
-
.on('message', (message) => {
|
|
45
|
-
return data = {
|
|
46
|
-
info: message,
|
|
47
|
-
status: 2
|
|
48
|
-
};
|
|
49
|
-
})
|
|
50
|
-
.on('debug', (debug) => {
|
|
51
|
-
return data = {
|
|
52
|
-
info: debug,
|
|
53
|
-
status: 3
|
|
54
|
-
};
|
|
55
|
-
})
|
|
56
|
-
.on('warn', (warn) => {
|
|
57
|
-
return data = {
|
|
58
|
-
info: warn,
|
|
59
|
-
status: 4
|
|
60
|
-
};
|
|
61
|
-
})
|
|
62
|
-
.on('error', async (error) => {
|
|
63
|
-
return data = {
|
|
64
|
-
info: error,
|
|
65
|
-
status: 5
|
|
66
|
-
};
|
|
67
|
-
});
|
|
27
|
+
let data = {};
|
|
28
|
+
const melCloud = new MelCloud(user, passwd, language, accountInfoFile, deviceInfoFile, buildingsFile, false, 0, true);
|
|
29
|
+
const contextKey = await melCloud.connect();
|
|
30
|
+
const devices = await melCloud.chackDevicesList(contextKey);
|
|
31
|
+
return data = {
|
|
32
|
+
info: '',
|
|
33
|
+
status: 0,
|
|
34
|
+
data: devices
|
|
35
|
+
};
|
|
68
36
|
} catch (error) {
|
|
69
37
|
return data = {
|
|
70
38
|
info: error,
|
|
71
|
-
status:
|
|
39
|
+
status: 1
|
|
72
40
|
};
|
|
73
41
|
};
|
|
74
42
|
};
|
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.51",
|
|
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,14 +8,15 @@ 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
|
-
this.enableDebugMode = enableDebugMode;
|
|
14
13
|
this.accountInfoFile = accountInfoFile;
|
|
15
14
|
this.buildingsFile = buildingsFile;
|
|
16
15
|
this.deviceInfoFile = deviceInfoFile;
|
|
16
|
+
this.enableDebugMode = enableDebugMode;
|
|
17
17
|
this.refreshInterval = refreshInterval;
|
|
18
|
-
this.
|
|
18
|
+
this.connectForConfig = connectForConfig;
|
|
19
|
+
this.contextKey = '';
|
|
19
20
|
this.devicesId = [];
|
|
20
21
|
|
|
21
22
|
this.options = {
|
|
@@ -30,16 +31,18 @@ class MelCloud extends EventEmitter {
|
|
|
30
31
|
}
|
|
31
32
|
};
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
if (!connectForConfig) {
|
|
35
|
+
this.impulseGenerator = new ImpulseGenerator();
|
|
36
|
+
this.impulseGenerator.on('checkDevicesList', async () => {
|
|
37
|
+
try {
|
|
38
|
+
await this.chackDevicesList(this.contextKey);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
this.emit('error', `Check devices list: ${error}.`);
|
|
41
|
+
};
|
|
42
|
+
}).on('state', (state) => { });
|
|
43
|
+
|
|
44
|
+
this.connect();
|
|
45
|
+
};
|
|
43
46
|
};
|
|
44
47
|
|
|
45
48
|
async connect() {
|
|
@@ -79,57 +82,26 @@ class MelCloud extends EventEmitter {
|
|
|
79
82
|
this.emit('warn', `Context key: ${contextKey}, missing.`)
|
|
80
83
|
return;
|
|
81
84
|
};
|
|
82
|
-
|
|
83
|
-
//create axios instance get
|
|
84
|
-
this.axiosInstanceGet = axios.create({
|
|
85
|
-
method: 'GET',
|
|
86
|
-
baseURL: CONSTANTS.ApiUrls.BaseURL,
|
|
87
|
-
timeout: 5000,
|
|
88
|
-
headers: {
|
|
89
|
-
'X-MitsContextKey': contextKey
|
|
90
|
-
},
|
|
91
|
-
maxContentLength: 100000000,
|
|
92
|
-
maxBodyLength: 1000000000,
|
|
93
|
-
withCredentials: true,
|
|
94
|
-
httpsAgent: new https.Agent({
|
|
95
|
-
keepAlive: false,
|
|
96
|
-
rejectUnauthorized: false
|
|
97
|
-
})
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
//create axios instance post
|
|
101
|
-
this.axiosInstancePost = axios.create({
|
|
102
|
-
method: 'POST',
|
|
103
|
-
baseURL: CONSTANTS.ApiUrls.BaseURL,
|
|
104
|
-
timeout: 5000,
|
|
105
|
-
headers: {
|
|
106
|
-
'X-MitsContextKey': contextKey,
|
|
107
|
-
'content-type': 'application/json'
|
|
108
|
-
},
|
|
109
|
-
maxContentLength: 100000000,
|
|
110
|
-
maxBodyLength: 1000000000,
|
|
111
|
-
withCredentials: true,
|
|
112
|
-
httpsAgent: new https.Agent({
|
|
113
|
-
keepAlive: false,
|
|
114
|
-
rejectUnauthorized: false
|
|
115
|
-
})
|
|
116
|
-
});
|
|
117
|
-
|
|
118
85
|
this.accountInfo = accountInfo;
|
|
119
86
|
this.contextKey = contextKey;
|
|
120
87
|
|
|
88
|
+
//return if connect for config
|
|
89
|
+
if (this.connectForConfig) {
|
|
90
|
+
return contextKey;
|
|
91
|
+
};
|
|
92
|
+
|
|
121
93
|
//save melcloud info to the file
|
|
122
94
|
await this.saveData(this.accountInfoFile, accountInfo);
|
|
123
95
|
|
|
124
96
|
//check devices list
|
|
125
|
-
await this.chackDevicesList();
|
|
97
|
+
await this.chackDevicesList(contextKey);
|
|
126
98
|
|
|
127
99
|
//emit connect success
|
|
128
100
|
this.emit('success', `Connect to MELCloud Success.`)
|
|
129
101
|
|
|
130
102
|
//start impulse generator
|
|
131
103
|
const timers = [{ name: 'checkDevicesList', sampling: this.refreshInterval }];
|
|
132
|
-
|
|
104
|
+
this.impulseGenerator.start(timers);
|
|
133
105
|
|
|
134
106
|
return true;
|
|
135
107
|
} catch (error) {
|
|
@@ -137,10 +109,27 @@ class MelCloud extends EventEmitter {
|
|
|
137
109
|
};
|
|
138
110
|
}
|
|
139
111
|
|
|
140
|
-
async chackDevicesList() {
|
|
112
|
+
async chackDevicesList(contextKey) {
|
|
141
113
|
try {
|
|
114
|
+
//create axios instance get
|
|
115
|
+
const axiosInstanceGet = axios.create({
|
|
116
|
+
method: 'GET',
|
|
117
|
+
baseURL: CONSTANTS.ApiUrls.BaseURL,
|
|
118
|
+
timeout: 5000,
|
|
119
|
+
headers: {
|
|
120
|
+
'X-MitsContextKey': contextKey
|
|
121
|
+
},
|
|
122
|
+
maxContentLength: 100000000,
|
|
123
|
+
maxBodyLength: 1000000000,
|
|
124
|
+
withCredentials: true,
|
|
125
|
+
httpsAgent: new https.Agent({
|
|
126
|
+
keepAlive: false,
|
|
127
|
+
rejectUnauthorized: false
|
|
128
|
+
})
|
|
129
|
+
});
|
|
130
|
+
|
|
142
131
|
const debug = this.enableDebugMode ? this.emit('debug', `Scanning for devices.`) : false;
|
|
143
|
-
const listDevicesData = await
|
|
132
|
+
const listDevicesData = await axiosInstanceGet(CONSTANTS.ApiUrls.ListDevices);
|
|
144
133
|
const buildingsList = listDevicesData.data;
|
|
145
134
|
const debug1 = this.enableDebugMode ? this.emit('debug', `Buildings: ${JSON.stringify(buildingsList, null, 2)}`) : false;
|
|
146
135
|
|
|
@@ -176,6 +165,11 @@ class MelCloud extends EventEmitter {
|
|
|
176
165
|
}
|
|
177
166
|
const debug3 = this.enableDebugMode ? this.emit('debug', `Found: ${devicesCount} devices.`) : false;
|
|
178
167
|
|
|
168
|
+
//return devices list for config
|
|
169
|
+
if (this.connectForConfig) {
|
|
170
|
+
return devices;
|
|
171
|
+
};
|
|
172
|
+
|
|
179
173
|
//get device info fom devices
|
|
180
174
|
for (const deviceInfo of devices) {
|
|
181
175
|
const deviceId = deviceInfo.DeviceID
|
|
@@ -189,16 +183,13 @@ class MelCloud extends EventEmitter {
|
|
|
189
183
|
//prepare device if not in devices array
|
|
190
184
|
if (!this.devicesId.includes(deviceId)) {
|
|
191
185
|
this.devicesId.push(deviceId);
|
|
192
|
-
this.emit('checkDevicesListComplete', this.accountInfo,
|
|
186
|
+
this.emit('checkDevicesListComplete', this.accountInfo, contextKey, deviceInfo);
|
|
193
187
|
}
|
|
194
188
|
};
|
|
195
189
|
|
|
196
|
-
//emit devices list
|
|
197
|
-
this.emit('devicesList', devices);
|
|
198
|
-
|
|
199
190
|
return true;
|
|
200
191
|
} catch (error) {
|
|
201
|
-
this.impulseGenerator.stop();
|
|
192
|
+
const stop = connectForConfig ? false : this.impulseGenerator.stop();
|
|
202
193
|
throw new Error(`Scanning for devices error: ${error.message ?? error}.`);
|
|
203
194
|
};
|
|
204
195
|
}
|
|
@@ -215,11 +206,29 @@ class MelCloud extends EventEmitter {
|
|
|
215
206
|
|
|
216
207
|
async send(accountInfo) {
|
|
217
208
|
try {
|
|
209
|
+
//create axios instance post
|
|
210
|
+
const axiosInstancePost = axios.create({
|
|
211
|
+
method: 'POST',
|
|
212
|
+
baseURL: CONSTANTS.ApiUrls.BaseURL,
|
|
213
|
+
timeout: 5000,
|
|
214
|
+
headers: {
|
|
215
|
+
'X-MitsContextKey': this.contextKey,
|
|
216
|
+
'content-type': 'application/json'
|
|
217
|
+
},
|
|
218
|
+
maxContentLength: 100000000,
|
|
219
|
+
maxBodyLength: 1000000000,
|
|
220
|
+
withCredentials: true,
|
|
221
|
+
httpsAgent: new https.Agent({
|
|
222
|
+
keepAlive: false,
|
|
223
|
+
rejectUnauthorized: false
|
|
224
|
+
})
|
|
225
|
+
});
|
|
226
|
+
|
|
218
227
|
const options = {
|
|
219
228
|
data: accountInfo
|
|
220
229
|
};
|
|
221
230
|
|
|
222
|
-
await
|
|
231
|
+
await axiosInstancePost(CONSTANTS.ApiUrls.UpdateApplicationOptions, options);
|
|
223
232
|
await this.saveData(this.accountInfoFile, accountInfo);
|
|
224
233
|
return true;
|
|
225
234
|
} catch (error) {
|