homebridge-melcloud-control 4.3.13 → 4.3.15-beta.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "MELCloud Control",
3
3
  "name": "homebridge-melcloud-control",
4
- "version": "4.3.13",
4
+ "version": "4.3.15-beta.0",
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/functions.js CHANGED
@@ -55,106 +55,135 @@ class Functions extends EventEmitter {
55
55
  }
56
56
 
57
57
  async ensureChromiumInstalled() {
58
- let chromiumPath = '/usr/bin/chromium-browser';
58
+ let chromiumPath = null;
59
59
 
60
60
  try {
61
- // Detect OS
62
- const { stdout: osOut } = await execPromise('uname -s');
61
+ // --- Detect OS ---
62
+ const { stdout: osOut } = await execPromise("uname -s");
63
63
  const osName = osOut.trim();
64
- if (this.logDebug) this.emit('debug', `Detected OS: ${osName}`);
65
-
66
- // Detect Architecture
67
- const { stdout: archOut } = await execPromise('uname -m');
64
+ const { stdout: archOut } = await execPromise("uname -m");
68
65
  const arch = archOut.trim();
69
- if (this.logDebug) this.emit('debug', `Detected architecture: ${arch}`);
70
66
 
71
- // Docker detection
72
- let isDocker = false;
73
- try {
74
- await access('/.dockerenv', fs.constants.F_OK);
75
- isDocker = true;
76
- } catch { }
67
+ const isARM = arch.startsWith("arm") || arch.startsWith("aarch64") || arch.startsWith("aarch");
68
+ const isMac = osName === "Darwin";
69
+ const isLinux = osName === "Linux";
77
70
 
71
+ // --- Detect Docker ---
72
+ let isDocker = false;
73
+ try { await access("/.dockerenv"); isDocker = true; } catch { }
78
74
  try {
79
- const { stdout } = await execPromise('cat /proc/1/cgroup || true');
80
- if (stdout.includes('docker') || stdout.includes('containerd')) isDocker = true;
75
+ const { stdout } = await execPromise("cat /proc/1/cgroup || true");
76
+ if (stdout.includes("docker") || stdout.includes("containerd")) isDocker = true;
81
77
  } catch { }
82
- if (isDocker && this.logDebug) this.emit('debug', 'Running inside Docker container');
83
78
 
84
- // macOS
85
- if (osName === 'Darwin') {
86
- chromiumPath = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
87
- try {
88
- await access(chromiumPath, fs.constants.X_OK);
89
- return chromiumPath;
90
- } catch {
91
- return null;
79
+ // --- macOS ---
80
+ if (isMac) {
81
+ const macCandidates = [
82
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
83
+ "/Applications/Chromium.app/Contents/MacOS/Chromium"
84
+ ];
85
+ for (const p of macCandidates) {
86
+ try { await access(p, fs.constants.X_OK); return p; } catch { }
92
87
  }
88
+ return null;
93
89
  }
94
90
 
95
- // ARM
96
- if (arch.startsWith('arm') || arch.startsWith('aarch')) {
97
- try {
98
- await access(chromiumPath, fs.constants.X_OK);
99
- return chromiumPath;
100
- } catch {
101
- try {
102
- await execPromise('sudo apt-get update -y && sudo apt-get install -y chromium-browser chromium-codecs-ffmpeg');
103
- return chromiumPath;
104
- } catch {
105
- return null;
106
- }
91
+ // --- ARM / Raspberry Pi ---
92
+ if (isARM && isLinux) {
93
+ const armCandidates = [
94
+ "/usr/bin/chromium-browser",
95
+ "/usr/bin/chromium",
96
+ "/snap/bin/chromium"
97
+ ];
98
+
99
+ // Try existing
100
+ for (const p of armCandidates) {
101
+ try { await access(p, fs.constants.X_OK); return p; } catch { }
102
+ }
103
+
104
+ // If not in Docker, try apt installation
105
+ if (!isDocker) {
106
+ try { await execPromise("sudo apt-get update -y"); } catch { }
107
+ try { await execPromise("sudo apt-get install -y chromium-browser chromium-codecs-ffmpeg || true"); } catch { }
108
+ try { await execPromise("sudo apt-get install -y chromium || true"); } catch { }
109
+ }
110
+
111
+ // Retry after installation
112
+ for (const p of armCandidates) {
113
+ try { await access(p, fs.constants.X_OK); return p; } catch { }
107
114
  }
115
+
116
+ return null;
108
117
  }
109
118
 
110
- // Linux x64
111
- if (osName === 'Linux') {
112
- let systemChromium = null;
119
+ // --- QNAP / Entware ---
120
+ let entwareExists = false;
121
+ try { await access("/opt/bin/opkg", fs.constants.X_OK); entwareExists = true; } catch { }
122
+
123
+ if (entwareExists) {
113
124
  try {
114
- const { stdout: checkOut } = await execPromise('which chromium || which chromium-browser || true');
115
- systemChromium = checkOut.trim() || null;
125
+ await execPromise("/opt/bin/opkg update");
126
+ await execPromise("/opt/bin/opkg install nspr nss libx11 libxcomposite libxdamage libxrandr atk libcups libdrm libgbm alsa-lib");
127
+ process.env.LD_LIBRARY_PATH = `/opt/lib:${process.env.LD_LIBRARY_PATH || ""}`;
116
128
  } catch { }
129
+ }
130
+
131
+ // --- Synology DSM 7 ---
132
+ const synoCandidates = [
133
+ "/var/packages/Chromium/target/usr/bin/chromium",
134
+ "/usr/local/chromium/bin/chromium"
135
+ ];
136
+ for (const p of synoCandidates) {
137
+ try { await access(p, fs.constants.X_OK); return p; } catch { }
138
+ }
139
+
140
+ // --- Linux x64 ---
141
+ if (isLinux) {
142
+ const linuxCandidates = [
143
+ "/usr/bin/chromium",
144
+ "/usr/bin/chromium-browser",
145
+ "/usr/bin/google-chrome",
146
+ "/snap/bin/chromium",
147
+ "/usr/local/bin/chromium"
148
+ ];
117
149
 
118
- // Entware (QNAP)
119
- let entwareExists = false;
120
150
  try {
121
- await access('/opt/bin/opkg', fs.constants.X_OK);
122
- entwareExists = true;
151
+ const { stdout } = await execPromise("which chromium || which chromium-browser || which google-chrome || true");
152
+ const found = stdout.trim();
153
+ if (found) return found;
123
154
  } catch { }
124
155
 
125
- if (entwareExists) {
126
- try {
127
- await execPromise('/opt/bin/opkg update');
128
- await execPromise('/opt/bin/opkg install nspr nss libx11 libxcomposite libxdamage libxrandr libatk libatk-bridge libcups libdrm libgbm libasound');
129
- process.env.LD_LIBRARY_PATH = `/opt/lib:${process.env.LD_LIBRARY_PATH || ''}`;
130
- } catch { }
156
+ for (const p of linuxCandidates) {
157
+ try { await access(p, fs.constants.X_OK); return p; } catch { }
158
+ }
159
+
160
+ // Docker: try installing chromium inside container (if allowed)
161
+ if (isDocker) {
162
+ try { await execPromise("apt-get update -y && apt-get install -y chromium || true"); } catch { }
163
+ try { await access("/usr/bin/chromium", fs.constants.X_OK); return "/usr/bin/chromium"; } catch { }
131
164
  }
132
165
 
133
- // Install missing libs
166
+ // Install missing libraries
134
167
  const depCommands = [
135
- 'apt-get update -y && apt-get install -y libnspr4 libnss3 libx11-6 libxcomposite1 libxdamage1 libxrandr2 libatk1.0-0 libcups2 libdrm2 libgbm1 libasound2',
136
- 'apk add --no-cache nspr nss libx11 libxcomposite libxdamage libxrandr atk cups libdrm libgbm alsa-lib',
137
- 'yum install -y nspr nss libX11 libXcomposite libXdamage libXrandr atk cups libdrm libgbm alsa-lib'
168
+ "apt-get update -y && apt-get install -y libnspr4 libnss3 libx11-6 libxcomposite1 libxdamage1 libxrandr2 libatk1.0-0 libcups2 libdrm2 libgbm1 libasound2 || true",
169
+ "yum install -y nspr nss libX11 libXcomposite libXdamage libXrandr atk cups libdrm libgbm alsa-lib || true",
170
+ "apk add --no-cache nspr nss libx11 libxcomposite libxdamage libxrandr atk cups libdrm libgbm alsa-lib || true"
138
171
  ];
139
-
140
172
  for (const cmd of depCommands) {
141
- try {
142
- await execPromise(`sudo ${cmd}`);
143
- } catch { }
173
+ try { await execPromise(`sudo ${cmd}`); } catch { }
144
174
  }
145
175
 
146
- process.env.LD_LIBRARY_PATH = `/usr/lib:/usr/lib64:${process.env.LD_LIBRARY_PATH || ''}`;
147
- return systemChromium;
176
+ return null;
148
177
  }
149
178
 
150
- if (this.logDebug) this.emit('debug', `Unsupported OS: ${osName}`);
151
179
  return null;
152
- } catch (error) {
153
- if (this.logError) this.emit('error', `Chromium detection/install error: ${error.message}`);
180
+ } catch (err) {
181
+ if (this.logError) this.emit("error", `Chromium detection error: ${err.message}`);
154
182
  return null;
155
183
  }
156
184
  }
157
185
 
186
+
158
187
  isValidValue(v) {
159
188
  return v !== undefined && v !== null && !(typeof v === 'number' && Number.isNaN(v));
160
189
  }
@@ -228,18 +228,13 @@ class MelCloudHome extends EventEmitter {
228
228
  // Get Chromium path
229
229
  let chromiumPath = await this.functions.ensureChromiumInstalled();
230
230
 
231
- // === Fallback to Puppeteer's built-in Chromium ===
231
+ // === Fallback to Puppeteer's bundled Chromium ===
232
232
  if (!chromiumPath) {
233
233
  try {
234
234
  const puppeteerPath = puppeteer.executablePath();
235
235
  if (puppeteerPath && puppeteerPath.length > 0) {
236
- if (fs.existsSync(puppeteerPath)) {
237
- chromiumPath = puppeteerPath;
238
- if (this.logDebug) this.emit('debug', `Using Puppeteer bundled Chromium at ${chromiumPath}`);
239
- } else {
240
- accountInfo.Info = `Puppeteer returned path, but file does not exist: ${puppeteerPath}`;
241
- return accountInfo;
242
- }
236
+ chromiumPath = puppeteerPath;
237
+ if (this.logDebug) this.emit('debug', `Using Puppeteer bundled Chromium at ${chromiumPath}`);
243
238
  } else {
244
239
  accountInfo.Info = `Puppeteer returned empty Chromium path`;
245
240
  return accountInfo;
@@ -250,7 +245,7 @@ class MelCloudHome extends EventEmitter {
250
245
  }
251
246
  }
252
247
 
253
- // Verify executable works
248
+ // === Verify Chromium executable ===
254
249
  try {
255
250
  const { stdout } = await execPromise(`"${chromiumPath}" --version`);
256
251
  if (this.logDebug) this.emit('debug', `Chromium detected: ${stdout.trim()}`);
@@ -290,7 +285,7 @@ class MelCloudHome extends EventEmitter {
290
285
  if (url.startsWith(`${ApiUrlsHome.WebSocketURL}`)) {
291
286
  const params = new URL(url).searchParams;
292
287
  const hash = params.get('hash');
293
- if (this.logDebug) this.emit('debug', `MelCloudHome WS hash detected: ${hash}`);
288
+ if (this.logDebug) this.emit('debug', `Web socket hash detected: ${hash}`);
294
289
 
295
290
  //web socket connection
296
291
  if (!this.connecting && !this.socketConnected) {
@@ -304,24 +299,24 @@ class MelCloudHome extends EventEmitter {
304
299
  };
305
300
  const webSocket = new WebSocket(`${ApiUrlsHome.WebSocketURL}${hash}`, { headers: headers })
306
301
  .on('error', (error) => {
307
- if (this.logError) this.emit('error', `Socket error: ${error}`);
302
+ if (this.logError) this.emit('error', `Web socket error: ${error}`);
308
303
  try {
309
304
  webSocket.close();
310
305
  } catch { }
311
306
  })
312
307
  .on('close', () => {
313
- if (this.logDebug) this.emit('debug', `Socket closed`);
308
+ if (this.logDebug) this.emit('debug', `Web socket closed`);
314
309
  this.cleanupSocket();
315
310
  })
316
311
  .on('open', () => {
317
312
  this.socketConnected = true;
318
313
  this.connecting = false;
319
- if (this.logSuccess) this.emit('success', `Socket Connect Success`);
314
+ if (this.logSuccess) this.emit('success', `Web Socket Connect Success`);
320
315
 
321
316
  // heartbeat
322
317
  this.heartbeat = setInterval(() => {
323
318
  if (webSocket.readyState === webSocket.OPEN) {
324
- if (this.logDebug) this.emit('debug', `Socket send heartbeat`);
319
+ if (this.logDebug) this.emit('debug', `Web socket send heartbeat`);
325
320
  webSocket.ping();
326
321
  }
327
322
  }, 30000);
@@ -337,13 +332,13 @@ class MelCloudHome extends EventEmitter {
337
332
  this.emit('webSocket', parsedMessage);
338
333
  });
339
334
  } catch (error) {
340
- if (this.logError) this.emit('error', `Socket connection failed: ${error}`);
335
+ if (this.logError) this.emit('error', `Web socket connection failed: ${error}`);
341
336
  this.cleanupSocket();
342
337
  }
343
338
  }
344
339
  }
345
340
  } catch (error) {
346
- if (this.logError) this.emit('error', `CDP WebSocketCreated handler error: ${error.message}`);
341
+ if (this.logError) this.emit('error', `CDP web socket created handler error: ${error.message}`);
347
342
  }
348
343
  });
349
344