126 lines
3.4 KiB
Python
126 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Babycam Network State Machine
|
||
Verwaltet die drei Betriebsmodi:
|
||
A – Heimnetz (wlan0 verbunden, AP aus)
|
||
B – Kein WLAN (AP auf wlan1 automatisch)
|
||
C – Setup-Modus (AP läuft, User konfiguriert WLAN)
|
||
|
||
Override-Datei: /tmp/babycam-ap-override
|
||
"on" → AP immer an (manuell)
|
||
"off" → AP immer aus (manuell)
|
||
fehlt → Automatik
|
||
"""
|
||
|
||
import subprocess
|
||
import time
|
||
import logging
|
||
import sys
|
||
import os
|
||
|
||
logging.basicConfig(
|
||
level=logging.INFO,
|
||
format="%(asctime)s [%(levelname)s] %(message)s",
|
||
handlers=[logging.StreamHandler(sys.stdout)],
|
||
)
|
||
log = logging.getLogger(__name__)
|
||
|
||
AP_INTERFACE = "wlan1"
|
||
CLIENT_INTERFACE = "wlan0"
|
||
AP_IP = "192.168.50.1"
|
||
CHECK_INTERVAL = 30 # Sekunden
|
||
OVERRIDE_FILE = "/tmp/babycam-ap-override"
|
||
|
||
|
||
def run(cmd, check=False):
|
||
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
||
if check and result.returncode != 0:
|
||
log.error(f"Fehler bei: {cmd}\n{result.stderr}")
|
||
return result
|
||
|
||
|
||
def get_override():
|
||
"""Liest die manuelle Override-Einstellung. Gibt 'on', 'off' oder None zurück."""
|
||
try:
|
||
with open(OVERRIDE_FILE) as f:
|
||
val = f.read().strip().lower()
|
||
if val in ("on", "off"):
|
||
return val
|
||
except FileNotFoundError:
|
||
pass
|
||
return None
|
||
|
||
|
||
def is_wlan0_connected():
|
||
result = run(f"nmcli -t -f GENERAL.STATE device show {CLIENT_INTERFACE}")
|
||
return "100 (connected)" in result.stdout
|
||
|
||
|
||
def is_ap_running():
|
||
result = run("systemctl is-active hostapd")
|
||
return result.stdout.strip() == "active"
|
||
|
||
|
||
def start_ap():
|
||
log.info("Starte Access Point (BabyCam)...")
|
||
run("ip addr add 192.168.50.1/24 dev wlan1 2>/dev/null || true")
|
||
run("ip link set wlan1 up")
|
||
run("systemctl start hostapd", check=True)
|
||
run("systemctl start dnsmasq", check=True)
|
||
log.info("Access Point gestartet.")
|
||
|
||
|
||
def stop_ap():
|
||
log.info("Stoppe Access Point...")
|
||
run("systemctl stop hostapd")
|
||
run("systemctl stop dnsmasq")
|
||
run("ip addr flush dev wlan1 2>/dev/null || true")
|
||
log.info("Access Point gestoppt.")
|
||
|
||
|
||
def main():
|
||
log.info("Babycam Network State Machine gestartet.")
|
||
current_mode = None
|
||
|
||
while True:
|
||
override = get_override()
|
||
connected = is_wlan0_connected()
|
||
ap_running = is_ap_running()
|
||
|
||
if override == "on":
|
||
# Manuell: AP immer an
|
||
if current_mode != "MANUAL_ON":
|
||
log.info("Modus: Manuell – Access Point erzwungen AN.")
|
||
if not ap_running:
|
||
start_ap()
|
||
current_mode = "MANUAL_ON"
|
||
|
||
elif override == "off":
|
||
# Manuell: AP immer aus
|
||
if current_mode != "MANUAL_OFF":
|
||
log.info("Modus: Manuell – Access Point erzwungen AUS.")
|
||
if ap_running:
|
||
stop_ap()
|
||
current_mode = "MANUAL_OFF"
|
||
|
||
else:
|
||
# Automatik
|
||
if connected:
|
||
if current_mode != "A":
|
||
log.info("Modus A: Heimnetz aktiv – AP aus.")
|
||
if ap_running:
|
||
stop_ap()
|
||
current_mode = "A"
|
||
else:
|
||
if current_mode != "B":
|
||
log.info("Modus B: Kein WLAN – starte Access Point.")
|
||
if not ap_running:
|
||
start_ap()
|
||
current_mode = "B"
|
||
|
||
time.sleep(CHECK_INTERVAL)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|