Make checking parallel (faster).

This commit is contained in:
2026-06-09 09:36:10 +02:00
parent 438836913a
commit d25104b8a1

View File

@ -3,6 +3,7 @@
import json
import subprocess
import threading
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime, timedelta
from pathlib import Path
@ -274,17 +275,28 @@ def _budget_tick():
if not is_curfew_allowed():
return
# Check all devices in parallel
online_status = {}
with ThreadPoolExecutor(max_workers=3) as executor:
futures = {
executor.submit(dev_info["check"]): dev_id
for dev_id, dev_info in DEVICES.items()
}
for future in as_completed(futures):
dev_id = futures[future]
result = future.result()
if isinstance(result, dict):
online_status[dev_id] = result.get("online", False)
else:
online_status[dev_id] = bool(result)
# Process results sequentially (budget operations need to be thread-safe)
with _timer_lock:
for dev_id, dev_info in DEVICES.items():
for dev_id, online in online_status.items():
dev_info = DEVICES[dev_id]
state = _load_state()
current_budget = state.get(dev_id, {}).get("budget", BUDGET_S)
is_online = dev_info["check"]()
if isinstance(is_online, dict):
online = is_online.get("online", False)
else:
online = bool(is_online)
# Expired budget + device back online → shut it down
if current_budget <= 0 and online:
dev_info["turnoff"]()
@ -342,35 +354,58 @@ def shutdown_all() -> list[dict]:
return actions
def _check_device(dev_id: str, dev_info: dict) -> dict:
"""Check a single device and return its status dict."""
is_online = dev_info["check"]()
if isinstance(is_online, dict):
online = is_online.get("online", False)
detail = is_online.get("detail", "")
else:
online = bool(is_online)
detail = "Online" if online else "Offline"
state = _load_state()
budget_seconds = state.get(dev_id, {}).get("budget", BUDGET_S)
budget_minutes = _budget_to_minutes(budget_seconds)
# Budget warning
if budget_minutes <= 0:
icon = "🔴"
elif budget_minutes < 5:
icon = "🟠"
else:
icon = dev_info["icon"]
return {
"icon": icon,
"title": dev_info["name"],
"detail": f"{detail} · {budget_minutes} min left",
"online": online,
}
def status_all() -> list[dict]:
"""Get current status + budget for all devices. Returns ordered list."""
curfew = curfew_status()
actions = []
for dev_id, dev_info in DEVICES.items():
state = _load_state()
budget_seconds = state.get(dev_id, {}).get("budget", BUDGET_S)
is_online = dev_info["check"]()
if isinstance(is_online, dict):
online = is_online.get("online", False)
detail = is_online.get("detail", "")
else:
online = bool(is_online)
detail = "Online" if online else "Offline"
# Check all devices in parallel
results = {}
with ThreadPoolExecutor(max_workers=3) as executor:
futures = {
executor.submit(_check_device, dev_id, dev_info): dev_id
for dev_id, dev_info in DEVICES.items()
}
for future in as_completed(futures):
dev_id = futures[future]
results[dev_id] = future.result()
budget_minutes = _budget_to_minutes(budget_seconds)
# Budget warning
if budget_minutes <= 0:
icon = "🔴"
elif budget_minutes < 5:
icon = "🟠"
else:
icon = dev_info["icon"]
actions.append({
"icon": icon,
"title": dev_info["name"],
"detail": f"{detail} · {budget_minutes} min left",
})
# Return in ordered list (DEVICES preserves insertion order)
actions = [
{
"icon": results[dev_id]["icon"],
"title": results[dev_id]["title"],
"detail": results[dev_id]["detail"],
}
for dev_id in DEVICES
]
return actions, curfew