Files
off/tui.py
2026-06-09 09:45:55 +02:00

121 lines
3.0 KiB
Python

"""Terminal TUI for device status monitoring."""
import os
import sys
import threading
import time
from devices import status_all, is_curfew_allowed
# ANSI escape codes
CLEAR = "\033[2J\033[H"
BOLD = "\033[1m"
RESET = "\033[0m"
GREEN = "\033[92m"
RED = "\033[91m"
YELLOW = "\033[93m"
CYAN = "\033[96m"
GRAY = "\033[90m"
def _get_terminal_size():
"""Get terminal width and height."""
try:
return os.get_terminal_size()
except OSError:
return (80, 24)
def _color(text: str, color_code: str) -> str:
"""Wrap text in ANSI color code."""
return f"{color_code}{text}{RESET}"
def _separator(width: int = 60) -> str:
"""Create a separator line."""
return "" * width
def render(devices_status, curfew, refresh_interval: int = 10):
"""Render the TUI screen."""
width, height = _get_terminal_size()
lines = []
# Header
lines.append(_color("⚡ KIDS DEVICES — STATUS", BOLD))
lines.append("")
# Curfew status
if curfew["in_curfew"]:
curfew_icon = _color("🔴 BLOCKED", RED)
else:
curfew_icon = _color("🟢 ALLOWED", GREEN)
lines.append(f" Curfew: {curfew_icon} | {curfew['message']}")
lines.append("")
# Device list
for device in devices_status:
icon = device["icon"]
name = device["title"]
detail = device["detail"]
# Parse budget from detail
parts = detail.split(" · ")
status_text = parts[0] if parts else "Unknown"
budget_text = parts[1] if len(parts) > 1 else ""
# Color the status
if "Online" in status_text:
status_color = GREEN
elif "Offline" in status_text:
status_color = GRAY
else:
status_color = YELLOW
status_colored = _color(status_text, status_color)
# Color the budget
if "🔴" in device["icon"]:
budget_color = RED
elif "🟠" in device["icon"]:
budget_color = YELLOW
else:
budget_color = CYAN
budget_colored = _color(budget_text, budget_color) if budget_text else ""
lines.append(f" {icon} {name:<12} {status_colored} · {budget_colored}")
# Footer with timestamp
now = time.strftime("%H:%M:%S")
lines.append(f" {_color('Last update:', GRAY)} {now} | Refresh: {refresh_interval}s")
return "\n".join(lines)
def run_tui(refresh_interval: int = 10):
"""Run the TUI in a loop."""
# Run in a separate thread to not block the server
while True:
try:
devices_status, curfew = status_all()
screen = render(devices_status, curfew, refresh_interval)
sys.stdout.write(CLEAR + screen)
sys.stdout.flush()
except Exception:
pass # Don't crash TUI on errors
time.sleep(refresh_interval)
def start_tui(refresh_interval: int = 10):
"""Start the TUI in a background thread."""
tui_thread = threading.Thread(
target=run_tui,
args=(refresh_interval,),
daemon=True,
)
tui_thread.start()
return tui_thread