Files
speed-logger/measurement/control.py
2026-07-09 19:40:33 +02:00

97 lines
3.3 KiB
Python

import os
from http.server import HTTPServer, BaseHTTPRequestHandler
from db import init_settings_db, get_setting, set_setting
from config import SPEEDTEST_ENABLED
GRAFANA_PORT = os.getenv("GRAFANA_PORT", "3000")
PAGE = """<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Network Monitor</title>
<style>
body {{ font-family: sans-serif; max-width: 26rem; margin: 4rem auto; padding: 0 1rem; text-align: center; }}
.state {{ font-size: 1.4rem; margin: 1.5rem 0; }}
.on {{ color: #1a7f37; }}
.off {{ color: #b35900; }}
button {{ font-size: 1.3rem; padding: 1rem 2.5rem; border-radius: 0.5rem; border: none; color: white; cursor: pointer; }}
.turn-off {{ background: #b35900; }}
.turn-on {{ background: #1a7f37; }}
.hint {{ color: #666; margin-top: 1.5rem; }}
a {{ color: #3274d9; }}
</style>
</head>
<body>
<h1>Network Monitor</h1>
<p class="state">Speedtests are <strong class="{cls}">{state}</strong></p>
<form method="post" action="/toggle">
<button class="{btn_cls}" type="submit">{btn_label}</button>
</form>
<p class="hint">A speedtest briefly uses the full connection about every 15 minutes.
Turn them off while gaming or in calls, and back on afterwards.</p>
<p><a href="{grafana_url}">Open the dashboard</a></p>
</body>
</html>
"""
def speedtests_on() -> bool:
return get_setting("speedtest_enabled") == "1"
class Handler(BaseHTTPRequestHandler):
def grafana_url(self) -> str:
host = self.headers.get("Host", "localhost")
if host.startswith("["): # IPv6 literal like [::1]:80
host = host.split("]")[0] + "]"
else:
host = host.split(":")[0]
# kiosk mode shows just the dashboard without the Grafana UI around it;
# Escape exits it for anyone who wants the full interface
return f"http://{host}:{GRAFANA_PORT}/d/speed-tests-v2?kiosk"
def do_GET(self):
if self.path != "/":
self.send_error(404)
return
on = speedtests_on()
body = PAGE.format(
cls="on" if on else "off",
state="ON" if on else "OFF",
btn_cls="turn-off" if on else "turn-on",
btn_label="Turn off" if on else "Turn on",
grafana_url=self.grafana_url(),
).encode()
self.send_response(200)
self.send_header("Content-Type", "text/html; charset=utf-8")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def do_POST(self):
if self.path != "/toggle":
self.send_error(404)
return
set_setting("speedtest_enabled", "0" if speedtests_on() else "1")
self.send_response(303)
self.send_header("Location", "/")
self.end_headers()
def run(port: int = 80):
init_settings_db()
# Seed the toggle from the env var on first start; after that the DB row
# written by the toggle button is the single source of truth.
if get_setting("speedtest_enabled") is None:
set_setting("speedtest_enabled", "1" if SPEEDTEST_ENABLED else "0")
server = HTTPServer(("", port), Handler)
print(f"Control page listening on :{port}", flush=True)
server.serve_forever()
if __name__ == "__main__":
run()