homebridge-melcloud-control 4.3.11-beta.7 → 4.3.11-beta.9
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/package.json +1 -1
- package/src/constants.js +1 -1
- package/src/deviceata.js +3 -3
- package/src/deviceatw.js +2 -2
- package/src/deviceerv.js +2 -2
- package/src/functions.js +78 -1
- package/src/melcloudata.js +1 -1
- package/src/melcloudhome.js +14 -9
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"displayName": "MELCloud Control",
|
|
3
3
|
"name": "homebridge-melcloud-control",
|
|
4
|
-
"version": "4.3.11-beta.
|
|
4
|
+
"version": "4.3.11-beta.9",
|
|
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/constants.js
CHANGED
|
@@ -60,7 +60,7 @@ export const AirConditioner = {
|
|
|
60
60
|
SystemMapEnumToString: { 0: "Air Conditioner Off", 1: "Air Conditioner On", 2: "Air Conditioner Offline" },
|
|
61
61
|
OperationModeMapStringToEnum: { "0": 0, "Heat": 1, "Dry": 2, "Cool": 3, "4": 4, "5": 5, "6": 6, "Fan": 7, "Automatic": 8, "Heat Isee": 9, "Dry Isee": 10, "Cool Isee": 11 },
|
|
62
62
|
OperationModeMapEnumToString: { 0: "0", 1: "Heat", 2: "Dry", 3: "Cool", 4: "4", 5: "5", 6: "6", 7: "Fan", 8: "Automatic", 9: "Heat Isee", 10: "Dry Isee", 11: "Cool Isee" },
|
|
63
|
-
OperationModeMapEnumToEnumWs: { 0: 0, 1: 1, 2: 2, 3: 3, 4: 7, 5: 8
|
|
63
|
+
OperationModeMapEnumToEnumWs: { 0: 0, 1: 1, 2: 2, 3: 3, 4: 7, 5: 8 },
|
|
64
64
|
FanSpeedMapStringToEnum: { "Auto": 0, "One": 1, "Two": 2, "Three": 3, "Four": 4, "Five": 5, "0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5 },
|
|
65
65
|
FanSpeedMapEnumToString: { 0: "Auto", 1: "One", 2: "Two", 3: "Three", 4: "Four", 5: "Five" },
|
|
66
66
|
SetFanSpeedMapStringToEnum: { "Auto": 0, "One": 1, "Two": 2, "Three": 3, "Four": 4, "Five": 5, "0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5 },
|
package/src/deviceata.js
CHANGED
|
@@ -142,7 +142,7 @@ class DeviceAta extends EventEmitter {
|
|
|
142
142
|
});
|
|
143
143
|
}
|
|
144
144
|
} catch (error) {
|
|
145
|
-
this.emit('warn', `RESTFul integration start error: ${error}`);
|
|
145
|
+
if (this.logWarn) this.emit('warn', `RESTFul integration start error: ${error}`);
|
|
146
146
|
};
|
|
147
147
|
}
|
|
148
148
|
|
|
@@ -186,7 +186,7 @@ class DeviceAta extends EventEmitter {
|
|
|
186
186
|
});
|
|
187
187
|
}
|
|
188
188
|
} catch (error) {
|
|
189
|
-
this.emit('warn', `MQTT integration start error: ${error}`);
|
|
189
|
+
if (this.logWarn) this.emit('warn', `MQTT integration start error: ${error}`);
|
|
190
190
|
};
|
|
191
191
|
}
|
|
192
192
|
|
|
@@ -1861,7 +1861,7 @@ class DeviceAta extends EventEmitter {
|
|
|
1861
1861
|
if (supportsFanSpeed) this.emit('info', `Current fan speed: ${AirConditioner.AktualFanSpeedMapEnumToString[actualFanSpeed]}`);
|
|
1862
1862
|
if (vaneHorizontalDirection !== null) this.emit('info', `Vane horizontal: ${AirConditioner.VaneHorizontalDirectionMapEnumToString[vaneHorizontalDirection]}`);
|
|
1863
1863
|
if (vaneVerticalDirection !== null) this.emit('info', `Vane vertical: ${AirConditioner.VaneVerticalDirectionMapEnumToString[vaneVerticalDirection]}`);
|
|
1864
|
-
if (supportsSwingFunction) this.emit('info', `Air direction: ${AirConditioner.AirDirectionMapEnumToString[
|
|
1864
|
+
if (supportsSwingFunction) this.emit('info', `Air direction: ${AirConditioner.AirDirectionMapEnumToString[currentSwingMode]}`);
|
|
1865
1865
|
this.emit('info', `Temperature display unit: ${obj.temperatureUnit}`);
|
|
1866
1866
|
this.emit('info', `Lock physical controls: ${obj.lockPhysicalControl ? 'Locked' : 'Unlocked'}`);
|
|
1867
1867
|
if (this.accountType === 'melcloudhome') this.emit('info', `Signal strength: ${deviceData.Rssi}dBm`);
|
package/src/deviceatw.js
CHANGED
|
@@ -146,7 +146,7 @@ class DeviceAtw extends EventEmitter {
|
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
148
|
} catch (error) {
|
|
149
|
-
this.emit('warn', `RESTFul integration start error: ${error}`);
|
|
149
|
+
if (this.logWarn) this.emit('warn', `RESTFul integration start error: ${error}`);
|
|
150
150
|
};
|
|
151
151
|
}
|
|
152
152
|
|
|
@@ -190,7 +190,7 @@ class DeviceAtw extends EventEmitter {
|
|
|
190
190
|
});
|
|
191
191
|
}
|
|
192
192
|
} catch (error) {
|
|
193
|
-
this.emit('warn', `MQTT integration start error: ${error}`);
|
|
193
|
+
if (this.logWarn) this.emit('warn', `MQTT integration start error: ${error}`);
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
196
|
}
|
package/src/deviceerv.js
CHANGED
|
@@ -138,7 +138,7 @@ class DeviceErv extends EventEmitter {
|
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
140
|
} catch (error) {
|
|
141
|
-
this.emit('warn', `RESTFul integration start error: ${error}`);
|
|
141
|
+
if (this.logWarn) this.emit('warn', `RESTFul integration start error: ${error}`);
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
144
|
|
|
@@ -182,7 +182,7 @@ class DeviceErv extends EventEmitter {
|
|
|
182
182
|
});
|
|
183
183
|
}
|
|
184
184
|
} catch (error) {
|
|
185
|
-
this.emit('warn', `MQTT integration start error: ${error}`);
|
|
185
|
+
if (this.logWarn) this.emit('warn', `MQTT integration start error: ${error}`);
|
|
186
186
|
};
|
|
187
187
|
}
|
|
188
188
|
}
|
package/src/functions.js
CHANGED
|
@@ -71,7 +71,8 @@ class Functions extends EventEmitter {
|
|
|
71
71
|
// --- Detect Docker ---
|
|
72
72
|
let isDocker = false;
|
|
73
73
|
try {
|
|
74
|
-
await access('/.dockerenv', fs.constants.F_OK);
|
|
74
|
+
await access('/.dockerenv', fs.constants.F_OK);
|
|
75
|
+
isDocker = true;
|
|
75
76
|
} catch { }
|
|
76
77
|
|
|
77
78
|
try {
|
|
@@ -156,6 +157,82 @@ class Functions extends EventEmitter {
|
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
159
|
|
|
160
|
+
async ensureChromiumInstalled() {
|
|
161
|
+
let chromiumPath = '/usr/bin/chromium-browser';
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
const { stdout: osOut } = await execPromise('uname -s');
|
|
165
|
+
const osName = osOut.trim();
|
|
166
|
+
if (this.logDebug) this.emit('debug', `Detected OS: ${osName}`);
|
|
167
|
+
|
|
168
|
+
const { stdout: archOut } = await execPromise('uname -m');
|
|
169
|
+
const arch = archOut.trim();
|
|
170
|
+
if (this.logDebug) this.emit('debug', `Detected architecture: ${arch}`);
|
|
171
|
+
|
|
172
|
+
// Docker detection
|
|
173
|
+
let isDocker = false;
|
|
174
|
+
try { await access('/.dockerenv', fs.constants.F_OK); isDocker = true; } catch { }
|
|
175
|
+
try {
|
|
176
|
+
const { stdout } = await execPromise('cat /proc/1/cgroup || true');
|
|
177
|
+
if (stdout.includes('docker') || stdout.includes('containerd')) isDocker = true;
|
|
178
|
+
} catch { }
|
|
179
|
+
if (isDocker && this.logDebug) this.emit('debug', 'Running inside Docker container.');
|
|
180
|
+
|
|
181
|
+
// macOS
|
|
182
|
+
if (osName === 'Darwin') {
|
|
183
|
+
chromiumPath = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
|
|
184
|
+
try { await access(chromiumPath, fs.constants.X_OK); return chromiumPath; } catch { return null; }
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// ARM
|
|
188
|
+
if (arch.startsWith('arm') || arch.startsWith('aarch')) {
|
|
189
|
+
try { await access(chromiumPath, fs.constants.X_OK); return chromiumPath; }
|
|
190
|
+
catch {
|
|
191
|
+
try { await execPromise('sudo apt-get update -y && sudo apt-get install -y chromium-browser chromium-codecs-ffmpeg'); return chromiumPath; }
|
|
192
|
+
catch { return null; }
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Linux x64
|
|
197
|
+
if (osName === 'Linux') {
|
|
198
|
+
let systemChromium = null;
|
|
199
|
+
try {
|
|
200
|
+
const { stdout: checkOut } = await execPromise('which chromium || which chromium-browser || true');
|
|
201
|
+
systemChromium = checkOut.trim() || null;
|
|
202
|
+
} catch { }
|
|
203
|
+
|
|
204
|
+
// Entware (QNAP)
|
|
205
|
+
let entwareExists = false;
|
|
206
|
+
try { await access('/opt/bin/opkg', fs.constants.X_OK); entwareExists = true; } catch { }
|
|
207
|
+
if (entwareExists) {
|
|
208
|
+
try {
|
|
209
|
+
await execPromise('/opt/bin/opkg update');
|
|
210
|
+
await execPromise('/opt/bin/opkg install nspr nss libx11 libxcomposite libxdamage libxrandr libatk libatk-bridge libcups libdrm libgbm libasound');
|
|
211
|
+
process.env.LD_LIBRARY_PATH = `/opt/lib:${process.env.LD_LIBRARY_PATH || ''}`;
|
|
212
|
+
} catch { }
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Install missing libs
|
|
216
|
+
const depCommands = [
|
|
217
|
+
'apt-get update -y && apt-get install -y libnspr4 libnss3 libx11-6 libxcomposite1 libxdamage1 libxrandr2 libatk1.0-0 libcups2 libdrm2 libgbm1 libasound2',
|
|
218
|
+
'apk add --no-cache nspr nss libx11 libxcomposite libxdamage libxrandr atk cups libdrm libgbm alsa-lib',
|
|
219
|
+
'yum install -y nspr nss libX11 libXcomposite libXdamage libXrandr atk cups libdrm libgbm alsa-lib'
|
|
220
|
+
];
|
|
221
|
+
for (const cmd of depCommands) { try { await execPromise(`sudo ${cmd}`); } catch { } }
|
|
222
|
+
|
|
223
|
+
process.env.LD_LIBRARY_PATH = `/usr/lib:/usr/lib64:${process.env.LD_LIBRARY_PATH || ''}`;
|
|
224
|
+
return systemChromium;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (this.logDebug) this.emit('debug', `Unsupported OS: ${osName}`);
|
|
228
|
+
return null;
|
|
229
|
+
|
|
230
|
+
} catch (error) {
|
|
231
|
+
if (this.logError) this.emit('error', `Chromium detection/install error: ${error.message}`);
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
159
236
|
isValidValue(v) {
|
|
160
237
|
return v !== undefined && v !== null && !(typeof v === 'number' && Number.isNaN(v));
|
|
161
238
|
}
|
package/src/melcloudata.js
CHANGED
|
@@ -324,7 +324,7 @@ class MelCloudAta extends EventEmitter {
|
|
|
324
324
|
//sens payload
|
|
325
325
|
headers['Content-Type'] = 'application/json; charset=utf-8';
|
|
326
326
|
headers.Origin = ApiUrlsHome.Origin;
|
|
327
|
-
if (
|
|
327
|
+
if (this.logDebug) this.emit('debug', `Send data: ${JSON.stringify(payload, null, 2)}`);
|
|
328
328
|
|
|
329
329
|
await axios(path, {
|
|
330
330
|
method: method,
|
package/src/melcloudhome.js
CHANGED
|
@@ -274,19 +274,23 @@ class MelCloudHome extends EventEmitter {
|
|
|
274
274
|
let browser;
|
|
275
275
|
try {
|
|
276
276
|
const accountInfo = { State: false, Info: '', Account: {}, UseFahrenheit: false };
|
|
277
|
+
|
|
278
|
+
// Get Chromium path
|
|
277
279
|
let chromiumPath = await this.functions.ensureChromiumInstalled();
|
|
278
280
|
|
|
279
281
|
// === Fallback to Puppeteer's built-in Chromium ===
|
|
280
282
|
if (!chromiumPath) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
283
|
+
if (!arch.startsWith('arm')) {
|
|
284
|
+
try {
|
|
285
|
+
const puppeteerPath = puppeteer.executablePath();
|
|
286
|
+
if (puppeteerPath && fs.existsSync(puppeteerPath)) {
|
|
287
|
+
chromiumPath = puppeteerPath;
|
|
288
|
+
if (this.logDebug) this.emit('debug', `Using Puppeteer Chromium at ${chromiumPath}`);
|
|
289
|
+
}
|
|
290
|
+
} catch { }
|
|
291
|
+
} else {
|
|
292
|
+
if (this.logDebug) this.emit('debug', 'Skipping Puppeteer Chromium on ARM (incompatible)');
|
|
293
|
+
}
|
|
290
294
|
}
|
|
291
295
|
|
|
292
296
|
if (!chromiumPath) {
|
|
@@ -303,6 +307,7 @@ class MelCloudHome extends EventEmitter {
|
|
|
303
307
|
return accountInfo;
|
|
304
308
|
}
|
|
305
309
|
|
|
310
|
+
// Launch Chromium
|
|
306
311
|
if (this.logDebug) this.emit('debug', `Launching Chromium...`);
|
|
307
312
|
browser = await puppeteer.launch({
|
|
308
313
|
headless: true,
|