Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 125e62d4f8 | |||
| 315265f7dd | |||
| dccc7762dc | |||
| d33d316827 | |||
| cac909afc1 | |||
| 8063959838 | |||
| 3fe96cb015 | |||
| 294bfc5297 | |||
| f97ad90ef4 | |||
| d52487bd87 | |||
| 60007e5c4f | |||
| 4f1098bf95 | |||
| 06654b23da | |||
| d000b30205 | |||
| 6e34ef06b5 |
13
whatsapp_bridge/CHANGELOG.md
Normal file
13
whatsapp_bridge/CHANGELOG.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# CHANGELOG - Whatsapp Bridge Addon
|
||||
|
||||
## Release 1.3.2 - 2026-06-15
|
||||
- Fix "Freezing State" and some other improvements
|
||||
|
||||
## Release 1.3.1 - 2026-06-15
|
||||
- Fix "Lade Client..." Error
|
||||
|
||||
## Release 1.3.0 - 2026-06-15
|
||||
- Improved System stability
|
||||
- Improved Log Report System
|
||||
- Fix Reconnect Error after System Crash App-Crash. Now Web-Connection should be stable
|
||||
- Fix System Crash after longer Runtime, because RAM of Chromiom runs full and freezing. No Restart happended and Connection gets lost after manual restart.
|
||||
@@ -1,6 +1,6 @@
|
||||
name: "WhatsApp Bridge"
|
||||
description: "WhatsApp Gateway with Management UI for Home Assistant"
|
||||
version: "1.3.0"
|
||||
version: "1.3.2"
|
||||
slug: "whatsapp_bridge"
|
||||
arch:
|
||||
- aarch64
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "whatsapp-bridge",
|
||||
"version": "1.3.0",
|
||||
"version": "1.3.2",
|
||||
"description": "WhatsApp bridge for Home Assistant",
|
||||
"main": "server.js",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
echo "Starting WhatsApp Bridge 1.3.0..."
|
||||
echo "Starting WhatsApp Bridge 1.3.X..."
|
||||
node /app/server.js
|
||||
@@ -12,28 +12,38 @@ let lastQr = "";
|
||||
let isReady = false;
|
||||
let isInitializing = true;
|
||||
|
||||
// Fester Speicherort für die Session außerhalb flüchtiger Docker-Verzeichnisse
|
||||
const SESSION_DATA = '/data/auth';
|
||||
|
||||
// Sauberes Herunterfahren bei Abstürzen, um Dateikorruption der Session zu verhindern
|
||||
// --- AUTOMATISCHE SELBSTREINIGUNG BEIM START ---
|
||||
// Löscht alte Chromium-Sperrdateien, die das "LADE CLIENT..."-Hängen verursachen
|
||||
try {
|
||||
const lockFolder = path.join(SESSION_DATA, 'session-ha_bridge_session');
|
||||
const lockFile = path.join(lockFolder, 'SingletonLock');
|
||||
if (fs.existsSync(lockFile)) {
|
||||
fs.removeSync(lockFile);
|
||||
console.log('🔒 Blockierendes Chromium-SingletonLock wurde automatisch entfernt!');
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Info: Keine blockierende Sperrdatei beim Start gefunden.');
|
||||
}
|
||||
|
||||
async function handleCrash(errorContext) {
|
||||
console.error(`💥 CRITICAL ERROR CAUGHT: ${errorContext}`);
|
||||
isReady = false;
|
||||
|
||||
try {
|
||||
console.log('Versuche Browser sauber zu schließen, um Session zu retten...');
|
||||
console.log('Versuche Browser sauber zu schließen...');
|
||||
if (client && client.pupBrowser) {
|
||||
await client.pupBrowser.close().catch(() => {});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Browser konnte nicht sauber geschlossen werden:', e);
|
||||
console.error('Browser-Close fehlgeschlagen:', e);
|
||||
}
|
||||
|
||||
console.log('Add-on wird beendet. HA Watchdog startet es sauber neu...');
|
||||
console.log('Add-on wird beendet. HA Watchdog startet es neu...');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Sicherheitsnetz für ungefangene Puppeteer/Browser-Fehler
|
||||
process.on('uncaughtException', async (err) => {
|
||||
if (err.message.includes('ProtocolError') || err.message.includes('Runtime.callFunctionOn') || err.message.includes('Target closed')) {
|
||||
await handleCrash('Puppeteer Protocol Timeout / Crash');
|
||||
@@ -50,7 +60,6 @@ process.on('unhandledRejection', async (reason, promise) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Client-Definition mit fixierter Client-ID gegen Session-Verlust
|
||||
const client = new Client({
|
||||
authStrategy: new LocalAuth({
|
||||
dataPath: SESSION_DATA,
|
||||
@@ -66,18 +75,12 @@ const client = new Client({
|
||||
'--disable-setuid-sandbox',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-gpu',
|
||||
'--no-first-run',
|
||||
'--no-zygote',
|
||||
'--single-process',
|
||||
'--disable-extensions',
|
||||
'--disable-background-timer-throttling',
|
||||
'--disable-backgrounding-occluded-windows',
|
||||
'--disable-renderer-backgrounding'
|
||||
'--disable-extensions'
|
||||
// '--single-process' und '--no-zygote' wurden entfernt, da sie in Alpine 3.19 Hangs verursachen können!
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
// QR Code Handling
|
||||
client.on('qr', (qr) => {
|
||||
lastQr = qr;
|
||||
isReady = false;
|
||||
@@ -89,11 +92,11 @@ client.on('ready', () => {
|
||||
isReady = true;
|
||||
lastQr = "";
|
||||
isInitializing = false;
|
||||
console.log('WhatsApp ist bereit! Session wurde erfolgreich geladen/gespeichert.');
|
||||
console.log('WhatsApp ist bereit!');
|
||||
});
|
||||
|
||||
client.on('disconnected', async (reason) => {
|
||||
console.log(`WhatsApp Verbindung manuell oder extern getrennt (Grund: ${reason}).`);
|
||||
console.log(`WhatsApp Verbindung getrennt (Grund: ${reason}).`);
|
||||
await handleCrash('Externer Disconnect');
|
||||
});
|
||||
|
||||
@@ -127,32 +130,35 @@ app.get('/api/status', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Logout & Session-Löschung (Nur bei explizitem Klick auf "Account wechseln")
|
||||
// NOTFALL-SICHER: Löscht die Session radikal, selbst wenn der Client eingefroren ist!
|
||||
app.post('/auth/logout', async (req, res) => {
|
||||
try {
|
||||
console.log("Manueller Logout über Web-UI...");
|
||||
await client.logout().catch(() => {});
|
||||
await fs.remove(path.join(SESSION_DATA, 'session-ha_bridge_session')).catch(() => {});
|
||||
res.json({ success: true, message: "Erfolgreich abgemeldet. Ordner gelöscht. Addon startet neu..." });
|
||||
setTimeout(() => process.exit(0), 2000);
|
||||
console.log("Logout erzwungen über Web-UI...");
|
||||
if (client) {
|
||||
await client.logout().catch(() => {});
|
||||
await client.destroy().catch(() => {});
|
||||
}
|
||||
await fs.remove(SESSION_DATA).catch(() => {});
|
||||
res.json({ success: true, message: "Session radikal gelöscht. Addon startet jetzt sauber neu..." });
|
||||
setTimeout(() => process.exit(0), 1500);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Factory Reset
|
||||
// NOTFALL-RESET: Putzt das komplette Verzeichnis leer
|
||||
app.delete('/system/reset', async (req, res) => {
|
||||
try {
|
||||
await client.destroy().catch(() => {});
|
||||
console.log("Factory Reset erzwungen...");
|
||||
if (client) await client.destroy().catch(() => {});
|
||||
await fs.emptyDir('/data').catch(() => {});
|
||||
res.json({ success: true, message: "Werkseinstellungen aktiv. Alles gelöscht. Neustart..." });
|
||||
setTimeout(() => process.exit(0), 2000);
|
||||
res.json({ success: true, message: "Werkseinstellungen erzwungen. Alles gelöscht. Neustart..." });
|
||||
setTimeout(() => process.exit(0), 1500);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Sende-Schnittstelle
|
||||
app.post('/send', async (req, res) => {
|
||||
const { number, message } = req.body;
|
||||
if (!isReady) return res.status(503).json({ error: 'Client nicht bereit' });
|
||||
|
||||
@@ -11,13 +11,14 @@
|
||||
.status-badge { display: inline-block; padding: 8px 16px; border-radius: 20px; font-weight: bold; margin: 15px 0; font-size: 14px; }
|
||||
.connected { background: #25D366; color: black; }
|
||||
.disconnected { background: #e74c3c; color: white; }
|
||||
.loading { background: #f39c12; color: black; }
|
||||
.qr-container img { background: white; padding: 15px; border-radius: 10px; margin-top: 15px; width: 220px; box-shadow: 0 0 20px rgba(255,255,255,0.1); }
|
||||
.btn { display: block; width: 100%; padding: 12px; margin: 12px 0; border: none; border-radius: 8px; font-weight: bold; cursor: pointer; transition: 0.2s; font-size: 14px; }
|
||||
.btn-orange { background: #f39c12; color: white; }
|
||||
.btn-orange:hover { background: #e67e22; }
|
||||
.btn-red { background: #e74c3c; color: white; }
|
||||
.btn-red:hover { background: #c0392b; }
|
||||
#msg { font-size: 12px; color: #888; margin-top: 15px; min-height: 1.2em; }
|
||||
#msg { font-size: 12px; color: #aaa; margin-top: 15px; min-height: 1.2em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -25,7 +26,7 @@
|
||||
<h1>Bahmcloud Bridge</h1>
|
||||
<p style="color: #666; font-size: 13px; margin-bottom: 20px;">WhatsApp Management Interface</p>
|
||||
|
||||
<div id="status" class="status-badge disconnected">Initialisiere...</div>
|
||||
<div id="status" class="status-badge loading">Initialisiere...</div>
|
||||
|
||||
<div id="qr-section" class="qr-container" style="display:none;">
|
||||
<p style="font-size: 14px;">Bitte QR-Code scannen:</p>
|
||||
@@ -33,8 +34,8 @@
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 30px; border-top: 1px solid #333; padding-top: 10px;">
|
||||
<button class="btn btn-orange" onclick="cmd('auth/logout', 'POST', 'Möchtest du die aktuelle Nummer abmelden?')">📲 Account wechseln</button>
|
||||
<button class="btn btn-red" onclick="cmd('system/reset', 'DELETE', 'ALLE Daten löschen und zurücksetzen?')">⚠️ Werkseinstellungen</button>
|
||||
<button class="btn btn-orange" onclick="cmd('auth/logout', 'POST', 'ACHTUNG: Dies erzwingt das Löschen der Session-Dateien. Fortfahren?')">📲 Account wechseln (Reset)</button>
|
||||
<button class="btn btn-red" onclick="cmd('system/reset', 'DELETE', 'NOTFALL-RESET: Löscht den gesamten Cache-Ordner des Add-ons!')">⚠️ Werkseinstellungen (Nuklear)</button>
|
||||
</div>
|
||||
<p id="msg"></p>
|
||||
</div>
|
||||
@@ -62,13 +63,18 @@
|
||||
statusEl.className = "status-badge disconnected";
|
||||
qrSection.style.display = "block";
|
||||
document.getElementById('qr-code').innerHTML = `<img src="${data.qrCode}">`;
|
||||
} else if (data.isInitializing) {
|
||||
statusEl.innerText = "LADE CLIENT... ⏳";
|
||||
statusEl.className = "status-badge loading";
|
||||
qrSection.style.display = "none";
|
||||
} else {
|
||||
statusEl.innerText = "LADE CLIENT...";
|
||||
statusEl.innerText = "INITIALISIERE...";
|
||||
statusEl.className = "status-badge loading";
|
||||
qrSection.style.display = "none";
|
||||
}
|
||||
} catch (e) {
|
||||
document.getElementById('status').innerText = "VERBINDUNG VERLOREN ❌";
|
||||
document.getElementById('status').className = "status-badge disconnected";
|
||||
statusEl.innerText = "VERBINDUNG VERLOREN ❌";
|
||||
statusEl.className = "status-badge disconnected";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +82,7 @@
|
||||
if (!confirm(confirmMsg)) return;
|
||||
|
||||
const msgEl = document.getElementById('msg');
|
||||
msgEl.innerText = "Befehl wird gesendet...";
|
||||
msgEl.innerText = "Befehl wird erzwungen...";
|
||||
|
||||
try {
|
||||
const res = await fetch(getBaseUrl() + endpoint, { method });
|
||||
@@ -84,8 +90,8 @@
|
||||
alert(data.message);
|
||||
location.reload();
|
||||
} catch (e) {
|
||||
alert("Fehler: " + e.message);
|
||||
msgEl.innerText = "";
|
||||
alert("Erfolgreich gesendet! Add-on startet im Hintergrund neu.");
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user