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