Backup automatico script del 2026-04-05 07:00

This commit is contained in:
2026-04-05 07:00:02 +02:00
parent c25c309a15
commit 7594a42875
3 changed files with 108 additions and 53 deletions
+34 -23
View File
@@ -90,14 +90,17 @@ def telegram_send_markdown(message_md: str, chat_ids: Optional[List[str]] = None
def now_local() -> datetime.datetime:
return datetime.datetime.now(TZINFO)
def parse_time(t: str) -> datetime.datetime:
def parse_time(t: str, tz: Optional[ZoneInfo] = None) -> datetime.datetime:
"""Interpreta un timestamp ISO dell'API nel fuso richiesto (default: Casa / Europe/Berlin)."""
target = tz if tz is not None else TZINFO
try:
dt = date_parser.isoparse(t)
if dt.tzinfo is None: return dt.replace(tzinfo=TZINFO)
return dt.astimezone(TZINFO)
if dt.tzinfo is None:
return dt.replace(tzinfo=target)
return dt.astimezone(target)
except Exception as e:
logger.error(f"Time parse error: {e}")
return now_local()
return datetime.datetime.now(target)
def degrees_to_cardinal(d: int) -> str:
dirs = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]
@@ -164,7 +167,8 @@ def get_coordinates(city_name: str):
res = data["results"][0]
cc = res.get("country_code", "IT").upper()
name = f"{res.get('name')} ({cc})"
return res["latitude"], res["longitude"], name, cc
geo_tz = res.get("timezone")
return res["latitude"], res["longitude"], name, cc, geo_tz
except Exception as e:
logger.error(f"Geocoding error: {e}")
return None
@@ -301,23 +305,23 @@ def generate_weather_report(lat, lon, location_name, debug_mode=False, cc="IT",
# Determina se è Casa
is_home = (abs(lat - HOME_LAT) < 0.01 and abs(lon - HOME_LON) < 0.01)
# Usa timezone personalizzata se fornita, altrimenti default
tz_to_use = timezone if timezone else TZ
# Fuso per l'API: Casa = TZ; località = timezone esplicito/geocoding, altrimenti "auto" (Open-Meteo risolve da lat/lon)
tz_for_api = timezone if timezone else (TZ if is_home else "auto")
model_id, model_name = choose_best_model(lat, lon, cc, is_home=is_home)
# Tentativo 1: Richiesta iniziale
data_list, error_details = get_forecast(lat, lon, model_id, is_home=is_home, timezone=tz_to_use, retry_after_60s=False)
data_list, error_details = get_forecast(lat, lon, model_id, is_home=is_home, timezone=tz_for_api, retry_after_60s=False)
# Se fallisce e siamo a Casa con ICON Italia, prova retry dopo 10 secondi
if not data_list and is_home and model_id == "italia_meteo_arpae_icon_2i":
logger.warning(f"Primo tentativo ICON Italia fallito: {error_details}. Retry dopo 10 secondi...")
data_list, error_details = get_forecast(lat, lon, model_id, is_home=is_home, timezone=tz_to_use, retry_after_60s=True)
data_list, error_details = get_forecast(lat, lon, model_id, is_home=is_home, timezone=tz_for_api, retry_after_60s=True)
# Se ancora fallisce e siamo a Casa, fallback a best match
if not data_list and is_home:
logger.warning(f"ICON Italia fallito anche dopo retry: {error_details}. Fallback a best match...")
data_list, error_details = get_forecast(lat, lon, None, is_home=False, timezone=tz_to_use, retry_after_60s=False)
data_list, error_details = get_forecast(lat, lon, None, is_home=False, timezone=tz_for_api, retry_after_60s=False)
if data_list:
model_name = "Best Match (fallback)"
logger.info("Fallback a best match riuscito")
@@ -332,6 +336,19 @@ def generate_weather_report(lat, lon, location_name, debug_mode=False, cc="IT",
if not isinstance(data_list, list): data_list = [data_list]
data_center = data_list[0]
# Ora e giorno LT: fuso della località (non San Marino se non è Casa)
if timezone is not None:
tz_to_use = timezone
elif is_home:
tz_to_use = TZ
else:
tz_to_use = data_center.get("timezone") or TZ
try:
tz_to_use_info = ZoneInfo(tz_to_use)
except Exception:
tz_to_use_info = TZINFO
tz_to_use = TZ
hourly_c = data_center.get("hourly", {})
times = hourly_c.get("time", [])
if not times: return "❌ Dati orari mancanti."
@@ -381,10 +398,10 @@ def generate_weather_report(lat, lon, location_name, debug_mode=False, cc="IT",
# --- DEBUG MODE ---
if debug_mode:
output = f"🔍 **DEBUG METEO (v10.5)**\n"
now_h = now_local().replace(minute=0, second=0, microsecond=0)
now_h = datetime.datetime.now(tz_to_use_info).replace(minute=0, second=0, microsecond=0)
idx = 0
for i, t_str in enumerate(times):
if parse_time(t_str) >= now_h:
if parse_time(t_str, tz_to_use_info) >= now_h:
idx = i
break
@@ -393,7 +410,7 @@ def generate_weather_report(lat, lon, location_name, debug_mode=False, cc="IT",
loc_H = get_val(l_cl_hig_loc[idx])
code_now = int(get_val(l_code[idx]))
output += f"Ora: {parse_time(times[idx]).strftime('%H:%M')}\n"
output += f"Ora: {parse_time(times[idx], tz_to_use_info).strftime('%H:%M')} (LT)\n"
output += f"📍 **LOCALE**: L:{int(loc_L)}% | H:{int(loc_H)}%\n"
output += f"☁️ **Nv%**: {int(avg_cl_tot[idx])}%\n"
output += f"❄️ **NEVE**: Codice={code_now}, Accumulo={get_val(l_snow[idx])}cm\n"
@@ -404,8 +421,6 @@ def generate_weather_report(lat, lon, location_name, debug_mode=False, cc="IT",
return output
# --- GENERAZIONE TABELLA ---
# Usa timezone personalizzata se fornita
tz_to_use_info = ZoneInfo(tz_to_use) if tz_to_use else TZINFO
now_local_tz = datetime.datetime.now(tz_to_use_info)
# Inizia dall'ora corrente (arrotondata all'ora)
@@ -418,12 +433,7 @@ def generate_weather_report(lat, lon, location_name, debug_mode=False, cc="IT",
valid_indices = []
for i, t_str in enumerate(times):
try:
dt = parse_time(t_str)
if dt.tzinfo is None:
dt = dt.replace(tzinfo=tz_to_use_info)
else:
dt = dt.astimezone(tz_to_use_info)
dt = parse_time(t_str, tz_to_use_info)
# Include solo timestamp >= current_hour e < end_hour
if current_hour <= dt < end_hour:
valid_indices.append((i, dt))
@@ -608,8 +618,9 @@ if __name__ == "__main__":
elif args.query:
coords = get_coordinates(args.query)
if coords:
lat, lon, name, cc = coords
report = generate_weather_report(lat, lon, name, args.debug, cc)
lat, lon, name, cc, geo_tz = coords
tz = args.timezone or geo_tz
report = generate_weather_report(lat, lon, name, args.debug, cc, timezone=tz)
else:
error_msg = f"❌ Città '{args.query}' non trovata."
if chat_ids: