homebridge-melcloud-control 3.9.8 → 3.9.10-beta.2
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/index.js +107 -104
- package/package.json +3 -3
package/index.js
CHANGED
|
@@ -23,7 +23,7 @@ class MelCloudPlatform {
|
|
|
23
23
|
//create directory if it doesn't exist
|
|
24
24
|
mkdirSync(prefDir, { recursive: true });
|
|
25
25
|
} catch (error) {
|
|
26
|
-
log.error(`Prepare directory error: ${error}`);
|
|
26
|
+
log.error(`Prepare directory error: ${error.message ?? error}`);
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -36,15 +36,9 @@ class MelCloudPlatform {
|
|
|
36
36
|
const language = account.language;
|
|
37
37
|
|
|
38
38
|
//check mandatory properties
|
|
39
|
-
if (!accountName || !user || !passwd || !language) {
|
|
40
|
-
log.warn(`
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
//check duplicate account name
|
|
45
|
-
if (accountsName.includes(accountName)) {
|
|
46
|
-
log.warn(`Account name: ${accountName}, must be unique.`);
|
|
47
|
-
return;
|
|
39
|
+
if (!accountName || accountsName.includes(accountName) || !user || !passwd || !language) {
|
|
40
|
+
log.warn(`Account name: ${accountName ? accountsName.includes(accountName) ? 'Duplicated' : 'OK' : accountName}, user: ${user ? 'OK' : user}, password: ${passwd ? 'OK' : passwd}, language: ${language ? 'OK' : language} in config missing.`);
|
|
41
|
+
continue;
|
|
48
42
|
}
|
|
49
43
|
accountsName.push(accountName);
|
|
50
44
|
|
|
@@ -66,7 +60,7 @@ class MelCloudPlatform {
|
|
|
66
60
|
if (logLevel.debug) log.info(`${accountName}, debug: Did finish launching.`);
|
|
67
61
|
|
|
68
62
|
//remove sensitive data
|
|
69
|
-
const
|
|
63
|
+
const safeConfig = {
|
|
70
64
|
...account,
|
|
71
65
|
passwd: 'removed',
|
|
72
66
|
mqtt: {
|
|
@@ -74,7 +68,7 @@ class MelCloudPlatform {
|
|
|
74
68
|
passwd: 'removed'
|
|
75
69
|
}
|
|
76
70
|
};
|
|
77
|
-
if (logLevel.debug) log.info(`${accountName}, Config: ${JSON.stringify(
|
|
71
|
+
if (logLevel.debug) log.info(`${accountName}, Config: ${JSON.stringify(safeConfig, null, 2)}`);
|
|
78
72
|
|
|
79
73
|
//define directory and file paths
|
|
80
74
|
const accountFile = `${prefDir}/${accountName}_Account`;
|
|
@@ -82,94 +76,106 @@ class MelCloudPlatform {
|
|
|
82
76
|
const devicesFile = `${prefDir}/${accountName}_Devices`;
|
|
83
77
|
|
|
84
78
|
//set account refresh interval
|
|
85
|
-
const refreshInterval = account.refreshInterval * 1000
|
|
79
|
+
const refreshInterval = (account.refreshInterval ?? 120) * 1000
|
|
86
80
|
|
|
87
81
|
try {
|
|
88
|
-
//
|
|
89
|
-
const
|
|
90
|
-
.on('
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
82
|
+
//create impulse generator
|
|
83
|
+
const impulseGenerator = new ImpulseGenerator()
|
|
84
|
+
.on('start', async () => {
|
|
85
|
+
try {
|
|
86
|
+
//melcloud account
|
|
87
|
+
const melCloud = new MelCloud(user, passwd, language, accountFile, buildingsFile, devicesFile, enableDebugMode, false)
|
|
88
|
+
.on('success', (msg) => logLevel.success && log.success(`${accountName}, ${msg}`))
|
|
89
|
+
.on('info', (msg) => logLevel.info && log.info(`${accountName}, ${msg}`))
|
|
90
|
+
.on('debug', (msg) => logLevel.debug && log.info(`${accountName}, debug: ${msg}`))
|
|
91
|
+
.on('warn', (msg) => logLevel.warn && log.warn(`${accountName}, ${msg}`))
|
|
92
|
+
.on('error', (msg) => logLevel.error && log.error(`${accountName}, ${msg}`));
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
//connect
|
|
96
|
+
let response;
|
|
97
|
+
try {
|
|
98
|
+
response = await melCloud.connect();
|
|
99
|
+
} catch (error) {
|
|
100
|
+
if (logLevel.error) log.error(`${accountName}, Connect error: ${error.message ?? error}`);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
106
103
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
104
|
+
const accountInfo = response.accountInfo ?? false;
|
|
105
|
+
const contextKey = response.contextKey ?? false;
|
|
106
|
+
const useFahrenheit = response.useFahrenheit ?? false;
|
|
112
107
|
|
|
113
|
-
|
|
114
|
-
await melCloud.impulseGenerator.start([{ name: 'checkDevicesList', sampling: refreshInterval }]);
|
|
115
|
-
|
|
116
|
-
//configured devices
|
|
117
|
-
const ataDevices = account.ataDevices ?? [];
|
|
118
|
-
const atwDevices = account.atwDevices ?? [];
|
|
119
|
-
const ervDevices = account.ervDevices ?? [];
|
|
120
|
-
const devices = [...ataDevices, ...atwDevices, ...ervDevices];
|
|
121
|
-
if (logLevel.debug) log.info(`Found configured devices ATA: ${ataDevices.length}, ATW: ${atwDevices.length}, ERV: ${ervDevices.length}.`);
|
|
122
|
-
for (const device of devices) {
|
|
123
|
-
//chack device from config exist on melcloud
|
|
124
|
-
const deviceId = device.id;
|
|
125
|
-
const displayMode = device.displayMode > 0;
|
|
126
|
-
const deviceExistInMelCloud = devicesInMelcloud.some(dev => dev.DeviceID === deviceId);
|
|
127
|
-
if (!deviceExistInMelCloud || !displayMode) {
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const deviceName = device.name;
|
|
132
|
-
const deviceType = device.type;
|
|
133
|
-
const deviceTypeText = device.typeString;
|
|
134
|
-
const deviceRefreshInterval = device.refreshInterval * 1000 || 5000;
|
|
135
|
-
try {
|
|
136
|
-
let configuredDevice;
|
|
137
|
-
switch (deviceType) {
|
|
138
|
-
case 0: //ATA
|
|
139
|
-
configuredDevice = new DeviceAta(api, account, device, contextKey, accountName, deviceId, deviceName, deviceTypeText, devicesFile, deviceRefreshInterval, useFahrenheit, restFul, mqtt);
|
|
140
|
-
break;
|
|
141
|
-
case 1: //ATW
|
|
142
|
-
configuredDevice = new DeviceAtw(api, account, device, contextKey, accountName, deviceId, deviceName, deviceTypeText, devicesFile, deviceRefreshInterval, useFahrenheit, restFul, mqtt);
|
|
143
|
-
break;
|
|
144
|
-
case 2:
|
|
145
|
-
break;
|
|
146
|
-
case 3: //ERV
|
|
147
|
-
configuredDevice = new DeviceErv(api, account, device, contextKey, accountName, deviceId, deviceName, deviceTypeText, devicesFile, deviceRefreshInterval, useFahrenheit, restFul, mqtt);
|
|
148
|
-
break;
|
|
149
|
-
default:
|
|
150
|
-
if (logLevel.warn) log.warn(`${accountName}, ${deviceTypeText}, ${deviceName}, unknown device: ${deviceType}.`);
|
|
108
|
+
if (contextKey === false) {
|
|
151
109
|
return;
|
|
152
|
-
|
|
110
|
+
}
|
|
153
111
|
|
|
154
|
-
|
|
112
|
+
//check devices list
|
|
113
|
+
let devicesInMelcloud;
|
|
155
114
|
try {
|
|
156
|
-
|
|
157
|
-
await melCloud.send(accountInfo);
|
|
115
|
+
devicesInMelcloud = await melCloud.checkDevicesList(contextKey);
|
|
158
116
|
} catch (error) {
|
|
159
|
-
if (logLevel.error) log.error(`${accountName},
|
|
117
|
+
if (logLevel.error) log.error(`${accountName}, Check devices list error: ${error.message ?? error}`);
|
|
118
|
+
return;
|
|
160
119
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
120
|
+
if (!devicesInMelcloud || !Array.isArray(devicesInMelcloud)) return;
|
|
121
|
+
|
|
122
|
+
//start account impulse generator
|
|
123
|
+
await melCloud.impulseGenerator.start([{ name: 'checkDevicesList', sampling: refreshInterval }]);
|
|
124
|
+
|
|
125
|
+
//configured devices
|
|
126
|
+
const ataDevices = account.ataDevices ?? [];
|
|
127
|
+
const atwDevices = account.atwDevices ?? [];
|
|
128
|
+
const ervDevices = account.ervDevices ?? [];
|
|
129
|
+
const devices = [...ataDevices, ...atwDevices, ...ervDevices];
|
|
130
|
+
if (logLevel.debug) log.info(`Found configured devices ATA: ${ataDevices.length}, ATW: ${atwDevices.length}, ERV: ${ervDevices.length}.`);
|
|
131
|
+
|
|
132
|
+
for (const device of devices) {
|
|
133
|
+
//chack device from config exist on melcloud
|
|
134
|
+
const deviceId = device.id;
|
|
135
|
+
const displayMode = device.displayMode > 0;
|
|
136
|
+
const deviceExistInMelCloud = devicesInMelcloud.some(dev => dev.DeviceID === deviceId);
|
|
137
|
+
if (!deviceExistInMelCloud || !displayMode) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const deviceName = device.name;
|
|
142
|
+
const deviceType = device.type;
|
|
143
|
+
const deviceTypeText = device.typeString;
|
|
144
|
+
const deviceRefreshInterval = (device.refreshInterval ?? 5) * 1000;
|
|
145
|
+
|
|
146
|
+
let configuredDevice;
|
|
147
|
+
switch (deviceType) {
|
|
148
|
+
case 0: //ATA
|
|
149
|
+
configuredDevice = new DeviceAta(api, account, device, contextKey, accountName, deviceId, deviceName, deviceTypeText, devicesFile, deviceRefreshInterval, useFahrenheit, restFul, mqtt);
|
|
150
|
+
break;
|
|
151
|
+
case 1: //ATW
|
|
152
|
+
configuredDevice = new DeviceAtw(api, account, device, contextKey, accountName, deviceId, deviceName, deviceTypeText, devicesFile, deviceRefreshInterval, useFahrenheit, restFul, mqtt);
|
|
153
|
+
break;
|
|
154
|
+
case 2:
|
|
155
|
+
break;
|
|
156
|
+
case 3: //ERV
|
|
157
|
+
configuredDevice = new DeviceErv(api, account, device, contextKey, accountName, deviceId, deviceName, deviceTypeText, devicesFile, deviceRefreshInterval, useFahrenheit, restFul, mqtt);
|
|
158
|
+
break;
|
|
159
|
+
default:
|
|
160
|
+
if (logLevel.warn) log.warn(`${accountName}, ${deviceTypeText}, ${deviceName}, unknown device: ${deviceType}.`);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
configuredDevice.on('melCloud', async (key, value) => {
|
|
165
|
+
try {
|
|
166
|
+
accountInfo[key] = value;
|
|
167
|
+
await melCloud.send(accountInfo);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
if (logLevel.error) log.error(`${accountName}, ${deviceTypeText}, ${deviceName}, ${error}.`);
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
.on('devInfo', (info) => logLevel.devInfo && log.info(info))
|
|
173
|
+
.on('success', (msg) => logLevel.success && log.success(`${accountName}, ${deviceTypeText}, ${deviceName}, ${msg}`))
|
|
174
|
+
.on('info', (msg) => logLevel.info && log.info(`${accountName}, ${deviceTypeText}, ${deviceName}, ${msg}`))
|
|
175
|
+
.on('debug', (msg) => logLevel.debug && log.info(`${accountName}, ${deviceTypeText}, ${deviceName}, debug: ${msg}`))
|
|
176
|
+
.on('warn', (msg) => logLevel.warn && log.warn(`${accountName}, ${deviceTypeText}, ${deviceName}, ${msg}`))
|
|
177
|
+
.on('error', (msg) => logLevel.error && log.error(`${accountName}, ${deviceTypeText}, ${deviceName}, ${msg}`));
|
|
178
|
+
|
|
173
179
|
const accessory = await configuredDevice.start();
|
|
174
180
|
if (accessory) {
|
|
175
181
|
api.publishExternalAccessories(PluginName, [accessory]);
|
|
@@ -178,21 +184,18 @@ class MelCloudPlatform {
|
|
|
178
184
|
await impulseGenerator.stop();
|
|
179
185
|
await configuredDevice.startImpulseGenerator();
|
|
180
186
|
}
|
|
181
|
-
} catch (error) {
|
|
182
|
-
if (logLevel.error) log.error(`${accountName}, ${deviceTypeText}, ${deviceName}, ${error}, trying again.`);
|
|
183
187
|
}
|
|
184
|
-
}
|
|
185
|
-
if (logLevel.
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
188
|
+
} catch (error) {
|
|
189
|
+
if (logLevel.error) log.error(`${accountName}, Start impulse generator error, ${error.message ?? error}, trying again.`);
|
|
190
|
+
}
|
|
191
|
+
}).on('state', (state) => {
|
|
192
|
+
if (logLevel.debug) log.info(`${accountName}, Start impulse generator ${state ? 'started' : 'stopped'}.`);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
//start impulse generator
|
|
196
|
+
await impulseGenerator.start([{ name: 'start', sampling: 60000 }]);
|
|
194
197
|
} catch (error) {
|
|
195
|
-
if (logLevel.error) log.error(`${accountName},
|
|
198
|
+
if (logLevel.error) log.error(`${accountName}, Did finish launching error: ${error.message ?? error}.`);
|
|
196
199
|
}
|
|
197
200
|
}
|
|
198
201
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"displayName": "MELCloud Control",
|
|
3
3
|
"name": "homebridge-melcloud-control",
|
|
4
|
-
"version": "3.9.
|
|
4
|
+
"version": "3.9.10-beta.2",
|
|
5
5
|
"description": "Homebridge plugin to control Mitsubishi Air Conditioner, Heat Pump and Energy Recovery Ventilation.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "grzegorz914",
|
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
"LICENSE"
|
|
32
32
|
],
|
|
33
33
|
"engines": {
|
|
34
|
-
"homebridge": "^1.9.0 || ^2.0.0 || ^2.0.0-beta.
|
|
34
|
+
"homebridge": "^1.9.0 || ^2.0.0 || ^2.0.0-beta.30 || ^2.0.0-alpha.40",
|
|
35
35
|
"node": "^20 || ^22 || ^24"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@homebridge/plugin-ui-utils": "^2.1.0",
|
|
39
39
|
"async-mqtt": "^2.6.3",
|
|
40
|
-
"axios": "^1.
|
|
40
|
+
"axios": "^1.12.2",
|
|
41
41
|
"express": "^5.1.0"
|
|
42
42
|
},
|
|
43
43
|
"keywords": [
|