Move the off.sh script to a pure Python implementation -- devices.py.
This commit is contained in:
95
server.py
95
server.py
@ -2,80 +2,9 @@
|
||||
"""Simple web server: one button to turn off all kids' devices."""
|
||||
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
|
||||
SCRIPT = Path(__file__).parent / "off.sh"
|
||||
|
||||
|
||||
def parse_output(text: str) -> list[dict]:
|
||||
"""Parse off.sh output into structured action items."""
|
||||
actions = []
|
||||
lines = text.strip().splitlines()
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
# Time window messages
|
||||
m = re.match(r"PRE:\s*(.+)seconds?\s*to\s*go\.", line)
|
||||
if m:
|
||||
actions.append({"icon": "⏳", "title": "Time Window", "detail": f"Before active hours — {m.group(1)}s until start"})
|
||||
continue
|
||||
|
||||
m = re.match(r"POST:\s*(.+)seconds?\s*passed\.", line)
|
||||
if m:
|
||||
actions.append({"icon": "⏳", "title": "Time Window", "detail": f"After active hours — {m.group(1)}s past end"})
|
||||
continue
|
||||
|
||||
m = re.match(r"ACTIVE:\s*(.+)", line)
|
||||
if m:
|
||||
actions.append({"icon": "🟢", "title": "Active Hours", "detail": m.group(1)})
|
||||
continue
|
||||
|
||||
# TV checks
|
||||
if "TV is unreachable" in line:
|
||||
actions.append({"icon": "❌", "title": "TV", "detail": "Unreachable (ping failed)"})
|
||||
continue
|
||||
|
||||
if "TV is turning OFF" in line:
|
||||
actions.append({"icon": "📺", "title": "TV", "detail": "Already off — no action needed"})
|
||||
continue
|
||||
|
||||
if "mWakefulness=Awake" in line:
|
||||
actions.append({"icon": "📺", "title": "TV", "detail": "Screen turned off (power key sent)"})
|
||||
continue
|
||||
|
||||
# User checks
|
||||
if "Gabi is not online" in line:
|
||||
actions.append({"icon": "💻", "title": "Gabi's PC", "detail": "Not logged in — no action needed"})
|
||||
continue
|
||||
|
||||
m = re.match(r"terminate-user gabi\b", line)
|
||||
if m or "session terminated" in line.lower():
|
||||
actions.append({"icon": "💻", "title": "Gabi's PC", "detail": "Session terminated"})
|
||||
continue
|
||||
|
||||
if "Gaja is not online" in line:
|
||||
actions.append({"icon": "💻", "title": "Gaja's PC", "detail": "Not logged in — no action needed"})
|
||||
continue
|
||||
|
||||
if "Gaja's PC is unreachable" in line:
|
||||
actions.append({"icon": "❌", "title": "Gaja's PC", "detail": "Unreachable (ping failed)"})
|
||||
continue
|
||||
|
||||
if "Gaja's PC: logged out" in line:
|
||||
actions.append({"icon": "💻", "title": "Gaja's PC", "detail": "Logged out"})
|
||||
continue
|
||||
|
||||
# If no structured items found, fallback to raw
|
||||
if not actions:
|
||||
actions.append({"icon": "📜", "title": "Output", "detail": text.strip() or "(empty)"})
|
||||
|
||||
return actions
|
||||
from devices import shutdown_all
|
||||
|
||||
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
@ -91,26 +20,12 @@ class Handler(BaseHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
if self.path == "/run":
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["bash", str(SCRIPT)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30,
|
||||
)
|
||||
raw_output = (result.stdout + result.stderr).strip() or "Script executed (no output)."
|
||||
status = "ok" if result.returncode == 0 else f"exit {result.returncode}"
|
||||
except FileNotFoundError:
|
||||
raw_output = f"Script not found at {SCRIPT}"
|
||||
status = "error"
|
||||
except subprocess.TimeoutExpired:
|
||||
raw_output = "Script timed out after 30 seconds."
|
||||
status = "error"
|
||||
actions = shutdown_all()
|
||||
status = "ok"
|
||||
except Exception as e:
|
||||
raw_output = str(e)
|
||||
actions = [{"icon": "❌", "title": "Error", "detail": str(e)}]
|
||||
status = "error"
|
||||
|
||||
actions = parse_output(raw_output) if status == "ok" else [{"icon": "❌", "title": "Error", "detail": raw_output}]
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "application/json")
|
||||
self.end_headers()
|
||||
@ -167,7 +82,7 @@ HTML = """\
|
||||
<body>
|
||||
<div class="card">
|
||||
<h1>📺 Kids Devices</h1>
|
||||
<p>TV + Gabi's computer</p>
|
||||
<p>TV + Gabi's computer + Gaja's computer</p>
|
||||
<button id="btn" onclick="run()">TURN OFF</button>
|
||||
<div id="output"></div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user