homebridge-melcloud-control 4.0.0-beta.21 → 4.0.0-beta.210
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 +60 -32
- package/homebridge-ui/public/index.html +72 -35
- package/homebridge-ui/server.js +4 -3
- package/index.js +40 -24
- package/package.json +2 -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 +205 -82
- package/src/melcloudata.js +139 -308
- package/src/melcloudatw.js +3 -228
- package/src/melclouderv.js +5 -162
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;
|
|
@@ -64,7 +67,7 @@ class MelCloudPlatform {
|
|
|
64
67
|
passwd: 'removed',
|
|
65
68
|
mqtt: {
|
|
66
69
|
auth: {
|
|
67
|
-
...
|
|
70
|
+
...account.mqtt?.auth,
|
|
68
71
|
passwd: 'removed',
|
|
69
72
|
}
|
|
70
73
|
},
|
|
@@ -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,31 +89,26 @@ 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}`))
|
|
95
96
|
.on('warn', (msg) => logLevel.warn && log.warn(`${accountName}, ${msg}`))
|
|
96
97
|
.on('error', (msg) => logLevel.error && log.error(`${accountName}, ${msg}`));
|
|
97
98
|
|
|
98
|
-
await melCloud.connectHomeCookies();
|
|
99
|
-
return;
|
|
100
|
-
|
|
101
|
-
|
|
102
99
|
//connect
|
|
103
|
-
let
|
|
100
|
+
let accountInfo;
|
|
104
101
|
try {
|
|
105
|
-
|
|
102
|
+
accountInfo = await melCloud.connect();
|
|
106
103
|
} catch (error) {
|
|
107
104
|
if (logLevel.error) log.error(`${accountName}, Connect error: ${error.message ?? error}`);
|
|
108
105
|
return;
|
|
109
106
|
}
|
|
110
107
|
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
const useFahrenheit = response.useFahrenheit ?? false;
|
|
108
|
+
const contextKey = accountInfo.ContextKey;
|
|
109
|
+
const useFahrenheit = accountInfo.UseFahrenheit;
|
|
114
110
|
|
|
115
|
-
if (contextKey
|
|
111
|
+
if (!contextKey) {
|
|
116
112
|
return;
|
|
117
113
|
}
|
|
118
114
|
|
|
@@ -135,10 +131,9 @@ class MelCloudPlatform {
|
|
|
135
131
|
|
|
136
132
|
for (const device of devices) {
|
|
137
133
|
//chack device from config exist on melcloud
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
if (!deviceExistInMelCloud || !displayMode) {
|
|
134
|
+
const displayType = device.displayType > 0;
|
|
135
|
+
const deviceExistInMelCloud = devicesInMelcloud.some(dev => dev.DeviceID === device.id);
|
|
136
|
+
if (!deviceExistInMelCloud || !displayType) {
|
|
142
137
|
continue;
|
|
143
138
|
}
|
|
144
139
|
|
|
@@ -146,19 +141,39 @@ class MelCloudPlatform {
|
|
|
146
141
|
const deviceType = device.type;
|
|
147
142
|
const deviceTypeText = device.typeString;
|
|
148
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
|
+
}
|
|
149
164
|
|
|
150
165
|
let configuredDevice;
|
|
151
166
|
switch (deviceType) {
|
|
152
167
|
case 0: //ATA
|
|
153
|
-
configuredDevice = new DeviceAta(api, account, device,
|
|
168
|
+
configuredDevice = new DeviceAta(api, account, device, devicesFile, defaultTempsFile, useFahrenheit, restFul, mqtt);
|
|
154
169
|
break;
|
|
155
170
|
case 1: //ATW
|
|
156
|
-
configuredDevice = new DeviceAtw(api, account, device, contextKey, devicesFile, useFahrenheit, restFul, mqtt);
|
|
171
|
+
configuredDevice = new DeviceAtw(api, account, device, contextKey, devicesFile, defaultTempsFile, useFahrenheit, restFul, mqtt);
|
|
157
172
|
break;
|
|
158
173
|
case 2:
|
|
159
174
|
break;
|
|
160
175
|
case 3: //ERV
|
|
161
|
-
configuredDevice = new DeviceErv(api, account, device, contextKey, devicesFile, useFahrenheit, restFul, mqtt);
|
|
176
|
+
configuredDevice = new DeviceErv(api, account, device, contextKey, devicesFile, defaultTempsFile, useFahrenheit, restFul, mqtt);
|
|
162
177
|
break;
|
|
163
178
|
default:
|
|
164
179
|
if (logLevel.warn) log.warn(`${accountName}, ${deviceTypeText}, ${deviceName}, unknown device: ${deviceType}.`);
|
|
@@ -185,8 +200,9 @@ class MelCloudPlatform {
|
|
|
185
200
|
api.publishExternalAccessories(PluginName, [accessory]);
|
|
186
201
|
if (logLevel.success) log.success(`${accountName}, ${deviceTypeText}, ${deviceName}, Published as external accessory.`);
|
|
187
202
|
|
|
188
|
-
//start impulse generators
|
|
189
|
-
|
|
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);
|
|
190
206
|
await configuredDevice.startStopImpulseGenerator(true, [{ name: 'checkState', sampling: deviceRefreshInterval }]);
|
|
191
207
|
|
|
192
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.210",
|
|
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,7 @@
|
|
|
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
43
|
},
|
|
44
44
|
"keywords": [
|
|
45
45
|
"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 = {
|