mirror of
https://github.com/MarekWo/mc-webui.git
synced 2026-05-17 23:05:47 +02:00
f352ccd968
BLE connections can enter a "zombie" state where notifications (reads) still arrive but writes silently fail. This went undetected until the user tried to send a message, at which point the connection was already dead. Additionally, after an abnormal BLE disconnect, BlueZ retains stale GATT notification handles, causing reconnection to fail with "[org.bluez.Error.NotPermitted] Notify acquired". Changes: - Add BLE keepalive loop (60s interval) that sends get_bat() to detect zombie connections proactively and trigger reconnection automatically - Add adapter power-cycle (hci0 off/on via D-Bus) during BLE reconnection to clear stale GATT notification state - Dedicated _ble_reconnect() with 5 attempts + adapter reset between each - Health endpoint returns 503 when BLE permanently fails, triggering Docker container restart via healthcheck - Guard against concurrent reconnection attempts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
117 lines
2.8 KiB
Python
117 lines
2.8 KiB
Python
"""
|
|
HTML views for mc-webui
|
|
"""
|
|
|
|
import logging
|
|
from flask import Blueprint, render_template, request
|
|
from app.config import config, runtime_config
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
views_bp = Blueprint('views', __name__)
|
|
|
|
|
|
@views_bp.route('/')
|
|
def index():
|
|
"""
|
|
Main chat view - displays message list and send form.
|
|
"""
|
|
return render_template(
|
|
'index.html',
|
|
device_name=runtime_config.get_device_name()
|
|
)
|
|
|
|
|
|
@views_bp.route('/dm')
|
|
def direct_messages():
|
|
"""
|
|
Direct Messages view - full-page DM interface.
|
|
|
|
Query params:
|
|
conversation: Optional conversation ID to open initially
|
|
"""
|
|
initial_conversation = request.args.get('conversation', '')
|
|
|
|
return render_template(
|
|
'dm.html',
|
|
device_name=runtime_config.get_device_name(),
|
|
initial_conversation=initial_conversation
|
|
)
|
|
|
|
|
|
@views_bp.route('/contacts/manage')
|
|
def contact_management():
|
|
"""
|
|
Contact Management Settings - manual approval + cleanup + navigation.
|
|
"""
|
|
return render_template(
|
|
'contacts-manage.html',
|
|
device_name=runtime_config.get_device_name()
|
|
)
|
|
|
|
|
|
@views_bp.route('/contacts/add')
|
|
def contact_add():
|
|
"""
|
|
Add Contact page - URI paste, QR scan, manual fields.
|
|
"""
|
|
return render_template(
|
|
'contacts-add.html',
|
|
device_name=runtime_config.get_device_name()
|
|
)
|
|
|
|
|
|
@views_bp.route('/contacts/pending')
|
|
def contact_pending_list():
|
|
"""
|
|
Full-screen pending contacts list.
|
|
"""
|
|
return render_template(
|
|
'contacts-pending.html',
|
|
device_name=runtime_config.get_device_name()
|
|
)
|
|
|
|
|
|
@views_bp.route('/contacts/existing')
|
|
def contact_existing_list():
|
|
"""
|
|
Full-screen existing contacts list with search, filter, sort.
|
|
"""
|
|
return render_template(
|
|
'contacts-existing.html',
|
|
device_name=runtime_config.get_device_name()
|
|
)
|
|
|
|
|
|
@views_bp.route('/console')
|
|
def console():
|
|
"""
|
|
Interactive meshcli console - chat-style command interface.
|
|
|
|
WebSocket connection is handled by the main Flask app and proxied to bridge.
|
|
"""
|
|
return render_template(
|
|
'console.html',
|
|
device_name=runtime_config.get_device_name()
|
|
)
|
|
|
|
|
|
@views_bp.route('/logs')
|
|
def logs():
|
|
"""System log viewer - real-time log streaming with filters."""
|
|
return render_template('logs.html')
|
|
|
|
|
|
@views_bp.route('/health')
|
|
def health():
|
|
"""Health check endpoint for monitoring.
|
|
|
|
Returns 503 when BLE reconnection has permanently failed so Docker's
|
|
healthcheck triggers a container restart (which clears all BLE state).
|
|
"""
|
|
from flask import current_app
|
|
dm = getattr(current_app, 'device_manager', None)
|
|
if dm and getattr(dm, '_ble_permanently_failed', False):
|
|
return 'BLE connection permanently failed', 503
|
|
return 'OK', 200
|