homebridge-melcloud-control 4.0.0-beta.31 → 4.0.0-beta.310
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 +9 -0
- package/README.md +12 -11
- package/config.schema.json +296 -310
- package/homebridge-ui/public/index.html +103 -51
- package/homebridge-ui/server.js +4 -3
- package/index.js +39 -20
- package/package.json +5 -2
- package/src/constants.js +15 -22
- package/src/deviceata.js +199 -188
- package/src/deviceatw.js +7 -5
- package/src/deviceerv.js +28 -26
- package/src/functions.js +18 -3
- package/src/melcloud.js +264 -84
- package/src/melcloudata.js +139 -308
- package/src/melcloudatw.js +3 -228
- package/src/melclouderv.js +5 -162
- package/src/melcloudhometoken.js +179 -0
|
@@ -76,19 +76,28 @@
|
|
|
76
76
|
</select>
|
|
77
77
|
</div>
|
|
78
78
|
|
|
79
|
+
<div class="mb-2">
|
|
80
|
+
<label for="accountType" class="form-label">Account Type</label>
|
|
81
|
+
<select id="accountType" name="accountType" class="form-control">
|
|
82
|
+
<option value="disabled">None/Disabled</option>
|
|
83
|
+
<option value="melcloud">MELCloud</option>
|
|
84
|
+
<option value="melcloudhome">MELCloud Home</option>
|
|
85
|
+
</select>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
79
88
|
<div class="text-center">
|
|
80
89
|
<button id="logIn" type="button" class="btn btn-secondary">Connect to MELCloud</button>
|
|
81
90
|
<button id="configButton" type="button" class="btn btn-secondary"><i class="fas fa-gear"></i></button>
|
|
82
91
|
</div>
|
|
83
92
|
</form>
|
|
93
|
+
<div id="accountButton" class="d-flex flex-wrap justify-content-center gap-1 mt-3"></div>
|
|
84
94
|
</div>
|
|
85
|
-
|
|
86
|
-
<div id="accountButton" class="mt-2"></div>
|
|
87
95
|
</div>
|
|
88
96
|
|
|
89
97
|
<script>
|
|
90
98
|
(async () => {
|
|
91
99
|
const pluginConfig = await homebridge.getPluginConfig();
|
|
100
|
+
|
|
92
101
|
if (!pluginConfig.length) {
|
|
93
102
|
pluginConfig.push({});
|
|
94
103
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
@@ -96,52 +105,79 @@
|
|
|
96
105
|
return;
|
|
97
106
|
}
|
|
98
107
|
|
|
99
|
-
this.
|
|
100
|
-
|
|
101
|
-
const accountsCount =
|
|
102
|
-
|
|
108
|
+
this.accountIndex = 0;
|
|
109
|
+
const accounts = pluginConfig[0].accounts || [];
|
|
110
|
+
const accountsCount = accounts.length;
|
|
111
|
+
|
|
112
|
+
const container = document.getElementById("accountButton");
|
|
113
|
+
container.style.display = 'flex';
|
|
114
|
+
container.style.flexWrap = 'wrap';
|
|
115
|
+
container.style.justifyContent = 'center';
|
|
116
|
+
container.style.gap = '0.25rem';
|
|
117
|
+
container.style.alignItems = 'center';
|
|
118
|
+
|
|
119
|
+
const formElements = {
|
|
120
|
+
name: document.getElementById('name'),
|
|
121
|
+
user: document.getElementById('user'),
|
|
122
|
+
passwd: document.getElementById('passwd'),
|
|
123
|
+
language: document.getElementById('language'),
|
|
124
|
+
accountType: document.getElementById('accountType'),
|
|
125
|
+
logIn: document.getElementById('logIn'),
|
|
126
|
+
accountName: document.getElementById('accountName')
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// Tworzenie przycisków
|
|
130
|
+
accounts.forEach((account, i) => {
|
|
103
131
|
const button = document.createElement("button");
|
|
104
132
|
button.type = "button";
|
|
105
133
|
button.id = `button${i}`;
|
|
106
134
|
button.className = "btn btn-primary";
|
|
107
135
|
button.style.textTransform = 'none';
|
|
108
|
-
button.innerText =
|
|
109
|
-
|
|
136
|
+
button.innerText = account.name || `Account ${i + 1}`;
|
|
137
|
+
container.appendChild(button);
|
|
110
138
|
|
|
111
139
|
button.addEventListener('click', async () => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
140
|
+
this.accountIndex = i;
|
|
141
|
+
|
|
142
|
+
// Zmieniamy klasę wszystkich przycisków
|
|
143
|
+
accounts.forEach((_, j) => {
|
|
144
|
+
document.getElementById(`button${j}`).className = (j === i ? 'btn btn-primary' : 'btn btn-secondary');
|
|
145
|
+
});
|
|
115
146
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
147
|
+
// Ustawiamy formularz
|
|
148
|
+
formElements.accountName.innerText = account.name || '';
|
|
149
|
+
formElements.name.value = account.name || '';
|
|
150
|
+
formElements.user.value = account.user || '';
|
|
151
|
+
formElements.passwd.value = account.passwd || '';
|
|
152
|
+
formElements.language.value = account.language || '0';
|
|
153
|
+
formElements.accountType.value = account.type || 'disabled';
|
|
154
|
+
formElements.logIn.disabled = !(account.name && account.user && account.passwd && account.language && account.type);
|
|
124
155
|
});
|
|
156
|
+
});
|
|
125
157
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
document.getElementById('melCloudAccount').style.display = 'block';
|
|
158
|
+
// Klikamy pierwszy przycisk po zakończeniu pętli
|
|
159
|
+
if (accountsCount > 0) document.getElementById('button0').click();
|
|
130
160
|
|
|
161
|
+
// Jeden listener input dla całego formularza
|
|
131
162
|
document.getElementById('configForm').addEventListener('input', async () => {
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
163
|
+
const account = accounts[this.accountIndex];
|
|
164
|
+
if (!account) return;
|
|
165
|
+
|
|
166
|
+
account.name = formElements.name.value;
|
|
167
|
+
account.user = formElements.user.value;
|
|
168
|
+
account.passwd = formElements.passwd.value;
|
|
169
|
+
account.language = formElements.language.value;
|
|
170
|
+
account.type = formElements.accountType.value;
|
|
137
171
|
|
|
138
|
-
|
|
172
|
+
formElements.logIn.disabled = !(account.name && account.user && account.passwd && account.language && account.type);
|
|
139
173
|
|
|
140
174
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
141
175
|
await homebridge.savePluginConfig(pluginConfig);
|
|
142
176
|
});
|
|
143
177
|
|
|
144
|
-
|
|
178
|
+
document.getElementById('melCloudAccount').style.display = 'block';
|
|
179
|
+
|
|
180
|
+
// Config Button Toggle
|
|
145
181
|
const configButton = document.getElementById('configButton');
|
|
146
182
|
let configButtonState = false;
|
|
147
183
|
configButton.addEventListener('click', () => {
|
|
@@ -163,13 +199,14 @@
|
|
|
163
199
|
}
|
|
164
200
|
});
|
|
165
201
|
|
|
166
|
-
//
|
|
202
|
+
// Device Handling & Login Logic
|
|
167
203
|
function removeStaleDevices(configDevices, melcloudDevices) {
|
|
168
204
|
const melcloudIds = melcloudDevices.map(d => d.DeviceID);
|
|
169
205
|
const removedDevices = [];
|
|
206
|
+
|
|
170
207
|
for (let i = configDevices.length - 1; i >= 0; i--) {
|
|
171
208
|
const device = configDevices[i];
|
|
172
|
-
if (device.id !== 0 && !melcloudIds.includes(device.id)) {
|
|
209
|
+
if (device.id !== "0" && !melcloudIds.includes(device.id)) {
|
|
173
210
|
removedDevices.push(device);
|
|
174
211
|
configDevices.splice(i, 1);
|
|
175
212
|
}
|
|
@@ -186,13 +223,14 @@
|
|
|
186
223
|
}
|
|
187
224
|
|
|
188
225
|
document.getElementById('logIn').addEventListener('click', async () => {
|
|
189
|
-
homebridge.showSpinner();
|
|
190
226
|
document.getElementById(`logIn`).className = "btn btn-primary";
|
|
227
|
+
|
|
191
228
|
updateInfo('info', 'Connecting...', 'yellow');
|
|
229
|
+
homebridge.showSpinner();
|
|
192
230
|
|
|
193
231
|
try {
|
|
194
|
-
const acc = pluginConfig[0].accounts[this.
|
|
195
|
-
const payload = { accountName: acc.name, user: acc.user, passwd: acc.passwd, language: acc.language };
|
|
232
|
+
const acc = pluginConfig[0].accounts[this.accountIndex];
|
|
233
|
+
const payload = { accountName: acc.name, user: acc.user, passwd: acc.passwd, language: acc.language, accountType: acc.type };
|
|
196
234
|
const devicesInMelCloud = await homebridge.request('/connect', payload);
|
|
197
235
|
|
|
198
236
|
// Initialize devices arrays
|
|
@@ -213,24 +251,36 @@
|
|
|
213
251
|
const removedAtw = removeStaleDevices(acc.atwDevices, devicesByType.atw);
|
|
214
252
|
const removedErv = removeStaleDevices(acc.ervDevices, devicesByType.erv);
|
|
215
253
|
|
|
216
|
-
// Function to handle device & presets
|
|
217
254
|
const handleDevices = (devicesInCloud, devicesInConfig, typeString, newArr, newPresets) => {
|
|
218
255
|
devicesInCloud.forEach(device => {
|
|
219
256
|
const { DeviceID: id, Type: type, DeviceName: name, Presets: presets = [] } = device;
|
|
220
|
-
const devObj = {
|
|
257
|
+
const devObj = structuredClone({
|
|
258
|
+
id,
|
|
259
|
+
type,
|
|
260
|
+
typeString,
|
|
261
|
+
name,
|
|
262
|
+
displayType: 0,
|
|
263
|
+
presets: [],
|
|
264
|
+
buttonsSensors: []
|
|
265
|
+
});
|
|
266
|
+
|
|
221
267
|
if (!devicesInConfig.some(d => d.id === id)) {
|
|
222
268
|
devicesInConfig.push(devObj);
|
|
223
|
-
newArr.push(devObj);
|
|
269
|
+
newArr.push(structuredClone(devObj));
|
|
224
270
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
p
|
|
228
|
-
|
|
229
|
-
|
|
271
|
+
|
|
272
|
+
presets.forEach(preset => {
|
|
273
|
+
const p = structuredClone({
|
|
274
|
+
id: preset.ID,
|
|
275
|
+
name: preset.NumberDescription,
|
|
276
|
+
displayType: 0,
|
|
277
|
+
namePrefix: false
|
|
278
|
+
});
|
|
279
|
+
|
|
230
280
|
const devConfig = devicesInConfig.find(d => d.id === id);
|
|
231
|
-
if (devConfig && !devConfig.presets.some(x => x.id === p.
|
|
281
|
+
if (devConfig && !devConfig.presets.some(x => x.id === p.id)) {
|
|
232
282
|
devConfig.presets.push(p);
|
|
233
|
-
newPresets.push(p);
|
|
283
|
+
newPresets.push(structuredClone(p));
|
|
234
284
|
}
|
|
235
285
|
});
|
|
236
286
|
});
|
|
@@ -238,9 +288,8 @@
|
|
|
238
288
|
|
|
239
289
|
handleDevices(devicesByType.ata, acc.ataDevices, "Air Conditioner", newDevices.ata, newDevices.ataPresets);
|
|
240
290
|
handleDevices(devicesByType.atw, acc.atwDevices, "Heat Pump", newDevices.atw, newDevices.atwPresets);
|
|
241
|
-
handleDevices(devicesByType.erv, acc.ervDevices, "Energy Recovery
|
|
291
|
+
handleDevices(devicesByType.erv, acc.ervDevices, "Energy Recovery Ventilation", newDevices.erv, newDevices.ervPresets);
|
|
242
292
|
|
|
243
|
-
// Display summary
|
|
244
293
|
const newDevicesCount = newDevices.ata.length + newDevices.atw.length + newDevices.erv.length;
|
|
245
294
|
const newPresetsCount = newDevices.ataPresets.length + newDevices.atwPresets.length + newDevices.ervPresets.length;
|
|
246
295
|
const removedDevicesCount = removedAta.length + removedAtw.length + removedErv.length;
|
|
@@ -248,9 +297,12 @@
|
|
|
248
297
|
if (!newDevicesCount && !newPresetsCount && !removedDevicesCount) {
|
|
249
298
|
updateInfo('info', 'No changes detected.', 'white');
|
|
250
299
|
} else {
|
|
251
|
-
if (newDevicesCount)
|
|
252
|
-
|
|
253
|
-
if (
|
|
300
|
+
if (newDevicesCount)
|
|
301
|
+
updateInfo('info', `Found new devices: ATA: ${newDevices.ata.length}, ATW: ${newDevices.atw.length}, ERV: ${newDevices.erv.length}.`, 'green');
|
|
302
|
+
if (newPresetsCount)
|
|
303
|
+
updateInfo('info1', `Found new presets: ATA: ${newDevices.ataPresets.length}, ATW: ${newDevices.atwPresets.length}, ERV: ${newDevices.ervPresets.length}.`, 'green');
|
|
304
|
+
if (removedDevicesCount)
|
|
305
|
+
updateInfo('info2', `Removed devices: ATA: ${removedAta.length}, ATW: ${removedAtw.length}, ERV: ${removedErv.length}.`, 'orange');
|
|
254
306
|
}
|
|
255
307
|
|
|
256
308
|
await homebridge.updatePluginConfig(pluginConfig);
|
|
@@ -259,7 +311,7 @@
|
|
|
259
311
|
|
|
260
312
|
} catch (error) {
|
|
261
313
|
updateInfo('info', 'Check Your credentials data and try again.', 'yellow');
|
|
262
|
-
updateInfo('info1', `Error: ${error}`, 'red');
|
|
314
|
+
updateInfo('info1', `Error: ${JSON.stringify(error)}`, 'red');
|
|
263
315
|
document.getElementById('logIn').className = "btn btn-secondary";
|
|
264
316
|
} finally {
|
|
265
317
|
homebridge.hideSpinner();
|
package/homebridge-ui/server.js
CHANGED
|
@@ -17,14 +17,15 @@ class PluginUiServer extends HomebridgePluginUiServer {
|
|
|
17
17
|
const user = payload.user;
|
|
18
18
|
const passwd = payload.passwd;
|
|
19
19
|
const language = payload.language;
|
|
20
|
+
const accountType = payload.accountType;
|
|
20
21
|
const accountFile = `${this.homebridgeStoragePath}/melcloud/${accountName}_Account`;
|
|
21
22
|
const buildingsFile = `${this.homebridgeStoragePath}/melcloud/${accountName}_Buildings`;
|
|
22
23
|
const devicesFile = `${this.homebridgeStoragePath}/melcloud/${accountName}_Devices`;
|
|
23
|
-
const melCloud = new MelCloud(user, passwd, language, accountFile, buildingsFile, devicesFile, false, true);
|
|
24
|
+
const melCloud = new MelCloud(accountType, user, passwd, language, accountFile, buildingsFile, devicesFile, false, true);
|
|
24
25
|
|
|
25
26
|
try {
|
|
26
|
-
const
|
|
27
|
-
const devices = await melCloud.checkDevicesList(
|
|
27
|
+
const accountInfo = await melCloud.connect();
|
|
28
|
+
const devices = await melCloud.checkDevicesList(accountInfo.ContextKey);
|
|
28
29
|
return devices;
|
|
29
30
|
} catch (error) {
|
|
30
31
|
throw new Error(`MELCloud error: ${error.message ?? error}.`);
|
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { join } from 'path';
|
|
2
|
-
import { mkdirSync } from 'fs';
|
|
2
|
+
import { mkdirSync, existsSync, writeFileSync } from 'fs';
|
|
3
3
|
import MelCloud from './src/melcloud.js';
|
|
4
4
|
import DeviceAta from './src/deviceata.js';
|
|
5
5
|
import DeviceAtw from './src/deviceatw.js';
|
|
@@ -30,6 +30,9 @@ class MelCloudPlatform {
|
|
|
30
30
|
api.on('didFinishLaunching', async () => {
|
|
31
31
|
//loop through accounts
|
|
32
32
|
for (const account of config.accounts) {
|
|
33
|
+
const accountType = account.type || 'disabled';
|
|
34
|
+
if (accountType === 'disabled') continue;
|
|
35
|
+
|
|
33
36
|
const accountName = account.name;
|
|
34
37
|
const user = account.user;
|
|
35
38
|
const passwd = account.passwd;
|
|
@@ -76,8 +79,6 @@ class MelCloudPlatform {
|
|
|
76
79
|
const accountFile = `${prefDir}/${accountName}_Account`;
|
|
77
80
|
const buildingsFile = `${prefDir}/${accountName}_Buildings`;
|
|
78
81
|
const devicesFile = `${prefDir}/${accountName}_Devices`;
|
|
79
|
-
const cookiesFile = `${prefDir}/${accountName}_Cookies`;
|
|
80
|
-
|
|
81
82
|
|
|
82
83
|
//set account refresh interval
|
|
83
84
|
const refreshInterval = (account.refreshInterval ?? 120) * 1000
|
|
@@ -88,7 +89,7 @@ class MelCloudPlatform {
|
|
|
88
89
|
.on('start', async () => {
|
|
89
90
|
try {
|
|
90
91
|
//melcloud account
|
|
91
|
-
const melCloud = new MelCloud(user, passwd, language, accountFile, buildingsFile, devicesFile,
|
|
92
|
+
const melCloud = new MelCloud(accountType, user, passwd, language, accountFile, buildingsFile, devicesFile, logLevel.warn, logLevel.debug, false)
|
|
92
93
|
.on('success', (msg) => logLevel.success && log.success(`${accountName}, ${msg}`))
|
|
93
94
|
.on('info', (msg) => logLevel.info && log.info(`${accountName}, ${msg}`))
|
|
94
95
|
.on('debug', (msg) => logLevel.debug && log.info(`${accountName}, debug: ${msg}`))
|
|
@@ -96,20 +97,18 @@ class MelCloudPlatform {
|
|
|
96
97
|
.on('error', (msg) => logLevel.error && log.error(`${accountName}, ${msg}`));
|
|
97
98
|
|
|
98
99
|
//connect
|
|
99
|
-
let
|
|
100
|
+
let accountInfo;
|
|
100
101
|
try {
|
|
101
|
-
|
|
102
|
-
return;
|
|
102
|
+
accountInfo = await melCloud.connect();
|
|
103
103
|
} catch (error) {
|
|
104
104
|
if (logLevel.error) log.error(`${accountName}, Connect error: ${error.message ?? error}`);
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
const
|
|
109
|
-
const
|
|
110
|
-
const useFahrenheit = response.useFahrenheit ?? false;
|
|
108
|
+
const contextKey = accountInfo.ContextKey;
|
|
109
|
+
const useFahrenheit = accountInfo.UseFahrenheit;
|
|
111
110
|
|
|
112
|
-
if (contextKey
|
|
111
|
+
if (!contextKey) {
|
|
113
112
|
return;
|
|
114
113
|
}
|
|
115
114
|
|
|
@@ -132,10 +131,9 @@ class MelCloudPlatform {
|
|
|
132
131
|
|
|
133
132
|
for (const device of devices) {
|
|
134
133
|
//chack device from config exist on melcloud
|
|
135
|
-
const
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
if (!deviceExistInMelCloud || !displayMode) {
|
|
134
|
+
const displayType = device.displayType > 0;
|
|
135
|
+
const deviceExistInMelCloud = devicesInMelcloud.some(dev => dev.DeviceID === device.id);
|
|
136
|
+
if (!deviceExistInMelCloud || !displayType) {
|
|
139
137
|
continue;
|
|
140
138
|
}
|
|
141
139
|
|
|
@@ -143,19 +141,39 @@ class MelCloudPlatform {
|
|
|
143
141
|
const deviceType = device.type;
|
|
144
142
|
const deviceTypeText = device.typeString;
|
|
145
143
|
const deviceRefreshInterval = (device.refreshInterval ?? 5) * 1000;
|
|
144
|
+
const defaultTempsFile = `${prefDir}/${accountName}_${device.id}_Temps`;
|
|
145
|
+
|
|
146
|
+
if (accountType === 'melcloudhome') {
|
|
147
|
+
try {
|
|
148
|
+
const temps = {
|
|
149
|
+
defaultCoolingSetTemperature: 24,
|
|
150
|
+
defaultHeatingSetTemperature: 20
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
if (!existsSync(defaultTempsFile)) {
|
|
154
|
+
writeFileSync(defaultTempsFile, JSON.stringify(temps, null, 2));
|
|
155
|
+
if (logLevel.debug) log.debug(`Default temperature file created: ${defaultTempsFile}`);
|
|
156
|
+
}
|
|
157
|
+
} catch (error) {
|
|
158
|
+
if (logLevel.error) {
|
|
159
|
+
log.error(`Device: ${host} ${deviceName}, File init error: ${error.message}`);
|
|
160
|
+
}
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
146
164
|
|
|
147
165
|
let configuredDevice;
|
|
148
166
|
switch (deviceType) {
|
|
149
167
|
case 0: //ATA
|
|
150
|
-
configuredDevice = new DeviceAta(api, account, device,
|
|
168
|
+
configuredDevice = new DeviceAta(api, account, device, devicesFile, defaultTempsFile, useFahrenheit, restFul, mqtt);
|
|
151
169
|
break;
|
|
152
170
|
case 1: //ATW
|
|
153
|
-
configuredDevice = new DeviceAtw(api, account, device, contextKey, devicesFile, useFahrenheit, restFul, mqtt);
|
|
171
|
+
configuredDevice = new DeviceAtw(api, account, device, contextKey, devicesFile, defaultTempsFile, useFahrenheit, restFul, mqtt);
|
|
154
172
|
break;
|
|
155
173
|
case 2:
|
|
156
174
|
break;
|
|
157
175
|
case 3: //ERV
|
|
158
|
-
configuredDevice = new DeviceErv(api, account, device, contextKey, devicesFile, useFahrenheit, restFul, mqtt);
|
|
176
|
+
configuredDevice = new DeviceErv(api, account, device, contextKey, devicesFile, defaultTempsFile, useFahrenheit, restFul, mqtt);
|
|
159
177
|
break;
|
|
160
178
|
default:
|
|
161
179
|
if (logLevel.warn) log.warn(`${accountName}, ${deviceTypeText}, ${deviceName}, unknown device: ${deviceType}.`);
|
|
@@ -182,8 +200,9 @@ class MelCloudPlatform {
|
|
|
182
200
|
api.publishExternalAccessories(PluginName, [accessory]);
|
|
183
201
|
if (logLevel.success) log.success(`${accountName}, ${deviceTypeText}, ${deviceName}, Published as external accessory.`);
|
|
184
202
|
|
|
185
|
-
//start impulse generators
|
|
186
|
-
|
|
203
|
+
//start impulse generators\
|
|
204
|
+
const timmers = accountType === 'melcloudhome' ? [{ name: 'connect', sampling: 150000 }, { name: 'checkDevicesList', sampling: deviceRefreshInterval }] : [{ name: 'checkDevicesList', sampling: refreshInterval }];
|
|
205
|
+
await melCloud.impulseGenerator.state(true, timmers);
|
|
187
206
|
await configuredDevice.startStopImpulseGenerator(true, [{ name: 'checkState', sampling: deviceRefreshInterval }]);
|
|
188
207
|
|
|
189
208
|
//stop impulse generator
|
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.310",
|
|
5
5
|
"description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "grzegorz914",
|
|
@@ -39,7 +39,10 @@
|
|
|
39
39
|
"async-mqtt": "^2.6.3",
|
|
40
40
|
"axios": "^1.12.2",
|
|
41
41
|
"express": "^5.1.0",
|
|
42
|
-
"puppeteer": "^24.26.
|
|
42
|
+
"puppeteer": "^24.26.1",
|
|
43
|
+
"axios-cookiejar-support": "^6.0.4",
|
|
44
|
+
"tough-cookie": "^6.0.0",
|
|
45
|
+
"cheerio": "^1.1.2"
|
|
43
46
|
},
|
|
44
47
|
"keywords": [
|
|
45
48
|
"homebridge",
|
package/src/constants.js
CHANGED
|
@@ -18,8 +18,7 @@ export const ApiUrls = {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
export const ApiUrlsHome = {
|
|
21
|
-
|
|
22
|
-
BaseURL: 'https://melcloudhome.com',
|
|
21
|
+
BaseURL: "https://melcloudhome.com",
|
|
23
22
|
GetUserContext: "/api/user/context",
|
|
24
23
|
SetAta: "/api/ataunit/deviceid",
|
|
25
24
|
SetAtw: "/api/atwunit/deviceid",
|
|
@@ -36,25 +35,19 @@ export const DeviceType = [
|
|
|
36
35
|
export const TemperatureDisplayUnits = ["°C", "°F"];
|
|
37
36
|
|
|
38
37
|
export const AirConditioner = {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"STRONG", "VERY STRONG", "OFF"
|
|
53
|
-
],
|
|
54
|
-
CurrentOperationModeHeatherCooler: [
|
|
55
|
-
"INACTIVE", "IDLE", "HEATING", "COOLING"
|
|
56
|
-
],
|
|
57
|
-
CurrentOperationModeThermostat: ["INACTIVE", "HEATING", "COOLING"],
|
|
38
|
+
SystemMapEnumToString: { 0: "Air Conditioner Off", 1: "ir Conditioner On", 2: "ir Conditioner Offline" },
|
|
39
|
+
AirDirectionMapEnumToString: { 0: "Auto", 1: "Swing" },
|
|
40
|
+
CurrentOperationModeHeatherCoolerMapEnumToString: { 0: "Inactive", 1: "Idle", 2: "Heating", 3: "Cooling" },
|
|
41
|
+
CurrentOperationModeThermostatMapEnumToString: { 0: "Inactive", 1: "Heating", 2: "Cooling" },
|
|
42
|
+
OperationModeMapStringToEnum: { "0": 0, "Heat": 1, "Dry": 2, "Cool": 3, "4": 4, "5": 5, "6": 6, "Fan": 7, "Automatic": 8, "Isee Heat": 9, "Isee Dry": 10, "Isee Cool": 11 },
|
|
43
|
+
OperationModeMapEnumToString: { 0: "0", 1: "Heat", 2: "Dry", 3: "Cool", 4: "4", 5: "5", 6: "6", 7: "Fan", 8: "Automatic", 9: "Isee Heat", 10: "Isee Dry", 11: "Isee Cool" },
|
|
44
|
+
FanSpeedMapStringToEnum: { "Auto": 0, "One": 1, "Two": 2, "Three": 3, "Four": 4, "Five": 5 },
|
|
45
|
+
FanSpeedMapEnumToString: { 0: "Auto", 1: "One", 2: "Two", 3: "Three", 4: "Four", 5: "Five" },
|
|
46
|
+
FanSpeedCurrentMapEnumToString: { 0: "Quiet", 1: "One", 2: "Two", 3: "Three", 4: "Four", 5: "Five" },
|
|
47
|
+
VaneVerticalDirectionMapStringToEnum: { "Auto": 0, "One": 1, "Two": 2, "Three": 3, "Four": 4, "Five": 5, "Six": 6, "Swing": 7 },
|
|
48
|
+
VaneVerticalDirectionMapEnumToString: { 0: "Auto", 1: "One", 2: "Two", 3: "Three", 4: "Four", 5: "Five", 6: "Six", 7: "Swing" },
|
|
49
|
+
VaneHorizontalDirectionMapStringToEnum: { "Auto": 0, "Left": 1, "LeftCentre": 2, "Centre": 3, "RightCentre": 4, "Right": 5, "Six": 6, "Seven": 7, "Split": 8, "Nine": 9, "Ten": 10, "Eleven": 11, "Swing": 12 },
|
|
50
|
+
VaneHorizontalDirectionMapEnumToString: { 0: "Auto", 1: "Left", 2: "LeftCentre", 3: "Centre", 4: "RightCentre", 5: "Right", 6: "Six", 7: "Seven", 8: "Split", 9: "Nine", 10: "Ten", 11: "Eleven", 12: "Swing" },
|
|
58
51
|
EffectiveFlags: {
|
|
59
52
|
Power: 1,
|
|
60
53
|
OperationMode: 2,
|
|
@@ -74,7 +67,7 @@ export const AirConditioner = {
|
|
|
74
67
|
Presets: 287,
|
|
75
68
|
HolidayMode: 131072,
|
|
76
69
|
All: 281483566710825
|
|
77
|
-
}
|
|
70
|
+
},
|
|
78
71
|
};
|
|
79
72
|
|
|
80
73
|
export const HeatPump = {
|