shutdown_all() was the only remaining sequential shutdown path (TV, then
Gabi, then Gaja — 10+s with SSH timeouts). It now uses the same parallel
_shutdown_devices() as the budget tick, which gained a {dev_id: result}
return value so the button response keeps per-device details and
registry ordering. Per-device failures are isolated instead of being
silently swallowed.
loginctl list-users columns are 'UID USER LINGER STATE' — taking the
first field compared 'gabi' against UIDs, so the check always returned
False. Match the second field (the username) instead.
Every ssh client call on this box fails with 'Bad owner or permissions'
on /etc/ssh/ssh_config.d (owned by nobody), which silently broke Gaja's
online check on every tick. Pass -F /dev/null so the checks use no
system/user ssh config at all; host key verification via known_hosts is
unaffected.
- curfew_status: rewrite next-transition calculation to scan up to 7 days
ahead; old branching showed wrong 'blocked until' for Friday nights
(assumed next day = weekday schedule) and Sunday nights (off by 2 days).
Verified against a minute-by-minute reference for a full week: 10080/10080.
- server: ThreadingHTTPServer so slow /status (pings/ssh) no longer blocks
the TURN OFF button and /budget requests.
- devices: atomic state file writes (tmp + os.replace) and tolerant
_load_state so a crash mid-write can't silently kill the whole system.
- server: /budget takes _timer_lock (no lost updates vs the budget tick)
and rejects unknown device ids instead of creating junk state entries.
- status: devices carry an explicit id; web UI keys off it instead of
parsing titles.
- gabi_check: exact username match (no more 'gabriel' false positives).
- gaja: password readable from GAJA_PASSWORD env var (hardcoded value
remains as fallback).
- tui: drop unused import.
The old per-device last_check timestamp was only persisted while a
device was consuming budget, so a stop/restart across days left stale
budgets. Check the state file mtime instead: if it predates today's 7 AM
and we're past 7 AM, the server was offline during the daily reset, so
give every device a fresh budget. Also drops the redundant 2-minute
reset window and the persisted last_check field.
- Curfew and budget exhaustion now use shared _shutdown_devices()
- All device turnoffs run in parallel via ThreadPoolExecutor
- Faster shutdown when multiple devices need to be turned off
- Float-based budget tracking with precise elapsed time calculation
- Curfew enforcement (devices turn off when blocked)
- Terminal TUI with live status refresh
- Parallel device checks using ThreadPoolExecutor
- Simplified config with time range format (e.g. '15:00-20:30')
- Optimistic UI updates for budget buttons
- Bug fixes: curfew shutdown, last_check reset on offline