feat: Fehlerbehandlung für WiFi-Verbindungen verbessert und Fallback-AP-Start optimiert; Versionsnummer auf 1.0.77 erhöht

This commit is contained in:
2026-05-17 18:02:13 +02:00
parent a507d153ee
commit fa8124f2d7
3 changed files with 50 additions and 16 deletions

25
app.py
View File

@@ -1,14 +1,24 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""PiCopy v2 - USB Copy Service mit WiFi-Fallback AP""" """PiCopy v2 - USB Copy Service mit WiFi-Fallback AP"""
import traceback
import urllib.request as _urlreq import urllib.request as _urlreq
from pathlib import Path from pathlib import Path
from flask import Flask, render_template, send_file from flask import Flask, render_template, send_file, jsonify
from picopy.config import VERSION, BASE_DIR, RAW_BASE from picopy.config import VERSION, BASE_DIR, RAW_BASE, log
# Absoluter Pfad zum templates/-Verzeichnis, unabhängig vom Arbeitsverzeichnis
_HERE = Path(__file__).parent
app = Flask(__name__, template_folder=str(_HERE / 'templates'))
@app.errorhandler(Exception)
def _handle_exception(e):
log.error('Unbehandelter Fehler:\n' + traceback.format_exc())
return jsonify(error=str(e)), 500
app = Flask(__name__, template_folder='templates')
from routes import register_routes from routes import register_routes
register_routes(app) register_routes(app)
@@ -49,7 +59,14 @@ if __name__ == '__main__':
from picopy.wifi import wifi_monitor from picopy.wifi import wifi_monitor
from picopy.wireguard import wg_monitor from picopy.wireguard import wg_monitor
from picopy.system import update_check_loop from picopy.system import update_check_loop
from picopy.config import log, load_cfg from picopy.config import load_cfg
# Startprüfung: Template vorhanden?
tmpl = _HERE / 'templates' / 'index.html'
if not tmpl.exists():
log.error(f'FEHLER: Template nicht gefunden: {tmpl}')
else:
log.info(f'Template gefunden: {tmpl}')
cleanup_stale_mounts() cleanup_stale_mounts()
load_state() load_state()

View File

@@ -95,12 +95,18 @@ def connect_client_wifi(ssid, password):
log.info(f'Verbinde mit WiFi: {ssid}') log.info(f'Verbinde mit WiFi: {ssid}')
nm('con', 'delete', NM_CLIENT_CON) nm('con', 'delete', NM_CLIENT_CON)
time.sleep(1) time.sleep(1)
# Scan erzwingen sonst findet nmcli das Netz nach dem Boot nicht im Cache
log.info('WiFi-Scan läuft...')
nm('dev', 'wifi', 'rescan')
time.sleep(4)
try: try:
# --wait 15: nmcli gibt nach 15 s auf; subprocess-Timeout als Sicherheitsnetz # --wait 45: genug Zeit für Scan + WPA-Handshake + DHCP
r = subprocess.run( r = subprocess.run(
['nmcli', '--wait', '15', 'dev', 'wifi', 'connect', ssid, ['nmcli', '--wait', '45', 'dev', 'wifi', 'connect', ssid,
'password', password, 'name', NM_CLIENT_CON, 'ifname', 'wlan0'], 'password', password, 'name', NM_CLIENT_CON, 'ifname', 'wlan0'],
capture_output=True, text=True, timeout=25, capture_output=True, text=True, timeout=55,
) )
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
log.warning(f'WiFi-Verbindung Timeout (SSID: {ssid})') log.warning(f'WiFi-Verbindung Timeout (SSID: {ssid})')
@@ -166,6 +172,8 @@ def wifi_monitor():
_wait_for_nm() _wait_for_nm()
_purge_foreign_wifi_profiles() _purge_foreign_wifi_profiles()
connect_failures = 0
while True: while True:
try: try:
update_wifi_state() update_wifi_state()
@@ -173,22 +181,31 @@ def wifi_monitor():
mode = wifi_state['mode'] mode = wifi_state['mode']
cfg = load_cfg() cfg = load_cfg()
if mode == 'disconnected':
ssid = cfg.get('wifi_ssid', '') ssid = cfg.get('wifi_ssid', '')
pw = cfg.get('wifi_password', '') pw = cfg.get('wifi_password', '')
if mode == 'client':
connect_failures = 0 # Verbindung OK Zähler zurücksetzen
elif mode == 'disconnected':
connected = False connected = False
if ssid: if ssid:
log.info(f'Verbindungsversuch {connect_failures + 1}: {ssid}')
connected = connect_client_wifi(ssid, pw) connected = connect_client_wifi(ssid, pw)
if connected: if connected:
connect_failures = 0
time.sleep(5) time.sleep(5)
update_wifi_state() update_wifi_state()
else:
connect_failures += 1
if not connected: # AP erst starten wenn kein SSID konfiguriert ODER nach 2 Fehlversuchen
if not connected and (not ssid or connect_failures >= 2):
ap_ssid = cfg.get('ap_ssid', 'PiCopy') ap_ssid = cfg.get('ap_ssid', 'PiCopy')
ap_pw = cfg.get('ap_password', 'PiCopy123') ap_pw = cfg.get('ap_password', 'PiCopy123')
log.info(f'Starte Fallback-AP nach {connect_failures} Fehlversuchen')
if start_ap(ap_ssid, ap_pw): if start_ap(ap_ssid, ap_pw):
connect_failures = 0
time.sleep(3) time.sleep(3)
with wifi_lock: with wifi_lock:
wifi_state.update(mode='ap', ssid=ap_ssid, ip='10.42.0.1') wifi_state.update(mode='ap', ssid=ap_ssid, ip='10.42.0.1')

View File

@@ -45,7 +45,7 @@ def r_wifi_connect():
update_wifi_state() update_wifi_state()
else: else:
if ap_was_active: if ap_was_active:
start_ap(cfg.get('ap_ssid', 'PiCopy'), cfg.get('ap_password', 'PiCopy,')) start_ap(cfg.get('ap_ssid', 'PiCopy'), cfg.get('ap_password', 'PiCopy123'))
update_wifi_state() update_wifi_state()
threading.Thread(target=_connect, daemon=True).start() threading.Thread(target=_connect, daemon=True).start()