Setup-Button pro Kamera: Relay ruft SETUP_<name>-URL auf
This commit is contained in:
1 parent
146ba6c399
commit
70b63cb215
4 files changed
+50
-7
No files matched your search
@@ -8,11 +8,14 @@ Endpunkte:
|
||||
/status.json Status aller Kameras (vom Frontend abgefragt)
|
||||
/<name>/stream.mjpg Livestream (multipart/x-mixed-replace)
|
||||
/<name>/snapshot.jpg aktuelles Einzelbild
|
||||
POST /<name>/setup ruft die in SETUP_<name> hinterlegte Kamera-URL auf
|
||||
/stream.mjpg Alias für die erste Kamera (Abwärtskompatibilität)
|
||||
/health Status aller Kameras
|
||||
|
||||
Konfiguration über die Datei .env (neben relay.py) oder Umgebungsvariablen:
|
||||
CAMERA_<name>=<url> eine Zeile pro Kamera, z.B. CAMERA_cam1=http://...
|
||||
SETUP_<name>=<url> optional: Konfigurations-URL der Kamera (Button "Setup" im Frontend),
|
||||
z.B. http://IP/control?var=framesize&val=11
|
||||
PORT (default 8000)
|
||||
AUTH_USER / AUTH_PASS optional: Basic-Auth (nur sinnvoll mit HTTPS in Zoraxy)
|
||||
"""
|
||||
@@ -45,6 +48,8 @@ load_env(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env"))
|
||||
CAMERAS = {k[7:].lower(): v for k, v in os.environ.items() if k.startswith("CAMERA_") and v}
|
||||
if not CAMERAS:
|
||||
raise SystemExit("Keine Kameras konfiguriert: CAMERA_<name>=<url> in .env eintragen")
|
||||
SETUPS = {k[6:].lower(): v for k, v in os.environ.items()
|
||||
if k.startswith("SETUP_") and v and k[6:].lower() in CAMERAS}
|
||||
PORT = int(os.environ.get("PORT", "8000"))
|
||||
AUTH_USER = os.environ.get("AUTH_USER", "")
|
||||
AUTH_PASS = os.environ.get("AUTH_PASS", "")
|
||||
@@ -148,7 +153,7 @@ class Handler(BaseHTTPRequestHandler):
|
||||
if not parts:
|
||||
return self.send_bytes(200, "text/html; charset=utf-8", page("", ""))
|
||||
if parts == ["status.json"]:
|
||||
body = json.dumps({"cameras": [{"name": n, "online": is_online(h)}
|
||||
body = json.dumps({"cameras": [{"name": n, "online": is_online(h), "setup": n in SETUPS}
|
||||
for n, h in hubs.items()]}).encode()
|
||||
return self.send_bytes(200, "application/json", body)
|
||||
if parts == ["stream.mjpg"] or parts == ["snapshot.jpg"]:
|
||||
@@ -170,6 +175,21 @@ class Handler(BaseHTTPRequestHandler):
|
||||
return self.stream(hub)
|
||||
self.send_bytes(404, "text/plain", b"Nicht gefunden")
|
||||
|
||||
def do_POST(self):
|
||||
if not self.authorized():
|
||||
return self.send_bytes(401, "text/plain", b"Login erforderlich",
|
||||
{"WWW-Authenticate": 'Basic realm="Webcam"'})
|
||||
parts = [p for p in self.path.split("?")[0].split("/") if p]
|
||||
if len(parts) != 2 or parts[1] != "setup" or parts[0] not in SETUPS:
|
||||
return self.send_bytes(404, "text/plain", b"Nicht gefunden")
|
||||
try:
|
||||
r = requests.get(SETUPS[parts[0]], timeout=5)
|
||||
r.raise_for_status()
|
||||
except requests.RequestException as ex:
|
||||
print(f"{parts[0]}: Setup fehlgeschlagen: {ex}", flush=True)
|
||||
return self.send_bytes(502, "text/plain", b"Kamera nicht erreichbar")
|
||||
self.send_bytes(200, "text/plain", b"ok")
|
||||
|
||||
def stream(self, hub):
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", f"multipart/x-mixed-replace; boundary={BOUNDARY}")
|
||||
|
||||
Reference in new issue
Block a user