#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Scheduler dinamico per viaggi attivi - Lancia meteo.py alle 8:00 AM local time per ogni viaggio attivo - Lancia previsione7.py alle 7:30 AM local time per ogni viaggio attivo - Gestisce fusi orari diversi per ogni località """ import os import json import subprocess import datetime from zoneinfo import ZoneInfo from typing import Dict, List, Tuple # PERCORSI SCRIPT SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) METEO_SCRIPT = os.path.join(SCRIPT_DIR, "meteo.py") METEO7_SCRIPT = os.path.join(SCRIPT_DIR, "previsione7.py") VIAGGI_STATE_FILE = os.path.join(SCRIPT_DIR, "viaggi_attivi.json") def load_viaggi_state() -> Dict: """Carica lo stato dei viaggi attivi da file JSON""" if os.path.exists(VIAGGI_STATE_FILE): try: with open(VIAGGI_STATE_FILE, "r", encoding="utf-8") as f: return json.load(f) or {} except Exception as e: print(f"Errore lettura viaggi state: {e}") return {} return {} def get_next_scheduled_time(target_hour: int, target_minute: int, timezone_str: str) -> Tuple[datetime.datetime, bool]: """ Calcola il prossimo orario schedulato in UTC per un target locale. Args: target_hour: Ora target (0-23) target_minute: Minuto target (0-59) timezone_str: Timezone IANA (es: "Europe/Rome") Returns: (datetime UTC, should_run_now): True se dovrebbe essere eseguito ora """ try: tz = ZoneInfo(timezone_str) now_utc = datetime.datetime.now(datetime.timezone.utc) now_local = now_utc.astimezone(tz) # Crea datetime target per oggi target_local = now_local.replace(hour=target_hour, minute=target_minute, second=0, microsecond=0) # Se l'orario è già passato oggi, programma per domani if now_local >= target_local: target_local += datetime.timedelta(days=1) # Converti in UTC target_utc = target_local.astimezone(datetime.timezone.utc) # Verifica se dovrebbe essere eseguito ora (entro 5 minuti) time_diff = (target_utc - now_utc).total_seconds() should_run_now = 0 <= time_diff <= 300 # Entro 5 minuti return target_utc, should_run_now except Exception as e: print(f"Errore calcolo orario per {timezone_str}: {e}") return None, False def launch_meteo_viaggio(chat_id: str, viaggio: Dict, script_type: str = "meteo") -> None: """Lancia meteo.py o previsione7.py per un viaggio attivo""" lat = viaggio.get("lat") lon = viaggio.get("lon") location = viaggio.get("location") name = viaggio.get("name") timezone = viaggio.get("timezone", "Europe/Rome") if script_type == "meteo": script = METEO_SCRIPT args = ["--query", location, "--chat_id", chat_id, "--timezone", timezone] elif script_type == "meteo7": script = METEO7_SCRIPT args = [location, "--chat_id", chat_id, "--timezone", timezone] else: return try: subprocess.Popen(["python3", script] + args) print(f"✅ Lanciato {script_type} per chat_id={chat_id}, località={name}, timezone={timezone}") except Exception as e: print(f"❌ Errore lancio {script_type} per chat_id={chat_id}: {e}") def check_and_launch_scheduled() -> None: """Controlla e lancia gli script schedulati per tutti i viaggi attivi""" viaggi = load_viaggi_state() if not viaggi: return now_utc = datetime.datetime.now(datetime.timezone.utc) for chat_id, viaggio in viaggi.items(): timezone = viaggio.get("timezone", "Europe/Rome") name = viaggio.get("name", "Unknown") # Controlla meteo.py (8:00 AM local time) target_utc_meteo, should_run_meteo = get_next_scheduled_time(8, 0, timezone) if should_run_meteo: print(f"🕐 Eseguendo meteo.py per {name} (chat_id={chat_id}) alle 8:00 {timezone}") launch_meteo_viaggio(chat_id, viaggio, "meteo") # Controlla previsione7.py (7:30 AM local time) target_utc_meteo7, should_run_meteo7 = get_next_scheduled_time(7, 30, timezone) if should_run_meteo7: print(f"🕐 Eseguendo previsione7.py per {name} (chat_id={chat_id}) alle 7:30 {timezone}") launch_meteo_viaggio(chat_id, viaggio, "meteo7") if __name__ == "__main__": # Questo script dovrebbe essere eseguito periodicamente (es. ogni 5 minuti) da Portainer # Controlla se ci sono viaggi attivi che devono essere eseguiti ora check_and_launch_scheduled()