From 4401b88726cd87c874734ee9a4542e61919b217f Mon Sep 17 00:00:00 2001 From: Mitja Horvat Date: Wed, 17 Jun 2026 22:23:18 +0200 Subject: [PATCH] feat: parallelize device shutdown with common _shutdown_devices function - 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 --- config.py | 2 +- devices.py | 27 ++++++++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/config.py b/config.py index 84a25e0..27bf3d1 100644 --- a/config.py +++ b/config.py @@ -6,7 +6,7 @@ BUDGET_S = 3600 # default 60 min per device (in seconds) TICK_INTERVAL = 10 # seconds between budget check cycles -ALLOWED_WEEKDAY = "7:00-23:30" # Mon-Fri allowed hours +ALLOWED_WEEKDAY = "7:00-20:30" # Mon-Fri allowed hours ALLOWED_WEEKEND = "7:00-20:30" # Sat-Sun allowed hours # ═══════════════════════════════════════════════════════════════════════ diff --git a/devices.py b/devices.py index e73eed4..5521388 100644 --- a/devices.py +++ b/devices.py @@ -258,7 +258,15 @@ def curfew_status() -> dict: } -# ── Budget timer (runs every 60s in background) ────────────────────── +def _shutdown_devices(device_ids: list[str]): + """Shut down a list of devices in parallel.""" + if not device_ids: + return + with ThreadPoolExecutor(max_workers=len(device_ids)) as executor: + list(executor.submit(DEVICES[dev_id]["turnoff"]) for dev_id in device_ids) + + +# ── Budget timer (runs every 10s in background) ────────────────────── _timer_running = False _timer_lock = threading.Lock() @@ -292,13 +300,14 @@ def _budget_tick(): # Process results sequentially (budget operations need to be thread-safe) with _timer_lock: if not is_curfew_allowed(): - # Curfew in effect — turn off all online devices - for dev_id, online in online_status.items(): - if online: - DEVICES[dev_id]["turnoff"]() + # Curfew in effect — turn off all online devices in parallel + online_devices = [dev_id for dev_id, online in online_status.items() if online] + _shutdown_devices(online_devices) return current_time = time.time() # float timestamp for precise elapsed calculation + devices_to_shutdown = [] + for dev_id, online in online_status.items(): dev_info = DEVICES[dev_id] state = _load_state() @@ -307,7 +316,7 @@ def _budget_tick(): # Expired budget + device back online → shut it down if current_budget <= 0 and online: - dev_info["turnoff"]() + devices_to_shutdown.append(dev_id) _set_budget(dev_id, 0.0) continue @@ -320,11 +329,15 @@ def _budget_tick(): _set_budget(dev_id, new_budget) if new_budget <= 0: - dev_info["turnoff"]() + devices_to_shutdown.append(dev_id) else: # Always update last_check even when offline _set_budget(dev_id, current_budget) + # Shutdown all devices that hit zero budget in parallel + if devices_to_shutdown: + _shutdown_devices(devices_to_shutdown) + def start_timer(): """Start the background budget timer (runs every 10s)."""