Aggiorna script backup e bot meteo Telegram.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
danieleandCursor committed 2026-08-21 11:57:29 +02:00
1 parent 3a7b867e83
commit beb790ed7e
6 files changed
+350 -102

No files matched your search

+69 -80
View File
@@ -18,7 +18,7 @@ from open_meteo_precip import (
CASA_LAT,
CASA_LON,
CASA_TZ,
daily_precip_from_hourly,
apply_hourly_daily_precip,
fetch_icon_italia,
hourly_precip_at_index,
hourly_precip_series,
@@ -560,6 +560,7 @@ def merge_multi_model_forecast(models_data, forecast_days=10):
"snowfall": [],
"snow_depth": [],
"rain": [],
"showers": [],
"weathercode": [],
"windspeed_10m": [],
"winddirection_10m": [],
@@ -1055,67 +1056,55 @@ def analyze_daily_events(times, codes, probs, precip, winds, temps, dewpoints, s
start_ice = i
ice_type = current_ice_condition
# 2. PRECIPITAZIONI
# 2. PRECIPITAZIONI — tot_mm è sempre la somma del solo blocco orario (mai il totale giorno)
def _precip_type_at(idx):
code_val = codes[idx] if idx < len(codes) and codes[idx] is not None else 0
t_val = temps[idx] if idx < len(temps) and temps[idx] is not None else None
try:
code_val = int(code_val) if code_val is not None else 0
except (ValueError, TypeError):
code_val = 0
return get_precip_type(code_val, temp=t_val)
def _emit_rain(start, end_inclusive, rain_type):
if end_inclusive < start:
return
block_precip = precip[start:end_inclusive + 1]
block_precip_clean = [p for p in block_precip if p is not None]
tot_mm = sum(float(p) for p in block_precip_clean)
if tot_mm <= 0:
return
hours_str = _format_event_hours(times, start, end_inclusive)
avg_intensity = tot_mm / len(block_precip) if block_precip else 0
events.append(
f"{rain_type} ({get_intensity_label(avg_intensity)}):\n"
f" 🕒 {hours_str} | 💧 {tot_mm:.1f}mm"
)
in_rain = False
start_idx = 0
current_rain_type = ""
for i in range(len(times)):
p_val = precip[i] if i < len(precip) and precip[i] is not None else 0
is_raining = p_val >= MIN_MM_PER_EVENTO
is_last = i == len(times) - 1
if is_raining and not in_rain:
in_rain = True
start_idx = i
code_val = codes[i] if i < len(codes) and codes[i] is not None else 0
t_val = temps[i] if i < len(temps) and temps[i] is not None else None
try:
code_val = int(code_val) if code_val is not None else 0
except (ValueError, TypeError):
code_val = 0
current_rain_type = get_precip_type(code_val, temp=t_val)
elif in_rain and is_raining and i < len(codes):
code_val = codes[i] if codes[i] is not None else 0
t_val = temps[i] if i < len(temps) and temps[i] is not None else None
try:
code_val = int(code_val) if code_val is not None else 0
except (ValueError, TypeError):
code_val = 0
new_type = get_precip_type(code_val, temp=t_val)
current_rain_type = _precip_type_at(i)
elif in_rain and is_raining:
new_type = _precip_type_at(i)
if new_type != current_rain_type:
end_inclusive = i - 1
block_precip = precip[start_idx:i] if i <= len(precip) else precip[start_idx:]
block_precip_clean = [p for p in block_precip if p is not None]
tot_mm = sum(block_precip_clean)
hours_str = _format_event_hours(times, start_idx, end_inclusive)
avg_intensity = tot_mm / len(block_precip) if block_precip else 0
events.append(
f"{current_rain_type} ({get_intensity_label(avg_intensity)}):\n"
f" 🕒 {hours_str} | 💧 {tot_mm:.1f}mm"
)
_emit_rain(start_idx, i - 1, current_rain_type)
start_idx = i
current_rain_type = new_type
elif (not is_raining and in_rain) or (in_rain and i == len(times)-1):
if in_rain and (not is_raining or is_last):
end_inclusive = i if is_raining else i - 1
_emit_rain(start_idx, end_inclusive, current_rain_type)
in_rain = False
if not is_raining:
end_inclusive = i - 1
end_slice = i
else:
end_inclusive = i
end_slice = i + 1
block_precip = precip[start_idx:end_slice] if end_slice <= len(precip) else precip[start_idx:]
block_precip_clean = [p for p in block_precip if p is not None]
tot_mm = sum(block_precip_clean)
if tot_mm > 0 and end_inclusive >= start_idx:
hours_str = _format_event_hours(times, start_idx, end_inclusive)
avg_intensity = tot_mm / len(block_precip) if block_precip else 0
events.append(
f"{current_rain_type} ({get_intensity_label(avg_intensity)}):\n"
f" 🕒 {hours_str} | 💧 {tot_mm:.1f}mm"
)
# 3. VENTO
if winds:
@@ -1249,16 +1238,7 @@ def _apply_unified_precip(hourly: Dict, daily: Dict, casa: bool) -> Tuple[Dict,
if icon_d.get("time"):
daily = overlay_icon_precip_on_daily(daily, icon_d)
hourly["precipitation"] = hourly_precip_series(hourly)
totals = daily_precip_from_hourly(hourly)
times = daily.get("time") or []
psum = list(daily.get("precipitation_sum") or [])
while len(psum) < len(times):
psum.append(None)
for i, t in enumerate(times):
d = str(t)[:10]
if d in totals:
psum[i] = round(totals[d], 2)
daily["precipitation_sum"] = psum
daily = apply_hourly_daily_precip(daily, hourly)
return hourly, daily
@@ -1806,27 +1786,36 @@ def format_weather_context_report(models_data, location_name, country_code, as_j
if day_info['precip_sum'] > 0.1:
# Caratterizza usando dati daily se disponibili
precip_parts = []
# Neve (solo con aria abbastanza fredda: evita cm spurii in estate)
if day_info.get('snowfall_sum', 0) > 0.1 and day_info['t_min'] <= ICE_EVENT_MAX_AIR_TEMP:
precip_parts.append(f"❄️ {day_info['snowfall_sum']:.1f}cm")
# Pioggia
if day_info.get('rain_sum', 0) > 0.1:
precip_parts.append(f"🌧️ {day_info['rain_sum']:.1f}mm")
# Temporali (showers)
if day_info.get('showers_sum', 0) > 0.1:
precip_parts.append(f"⛈️ {day_info['showers_sum']:.1f}mm")
# Se non abbiamo dati daily dettagliati, usa il tipo generale
if not precip_parts:
precip_symbol = "❄️" if day_info['precip_type'] == "snow" else "⛈️" if day_info['precip_type'] in ("hail", "thunderstorms") else "🌨️" if day_info['precip_type'] == "mixed" else "🌧️"
precip_parts.append(f"{precip_symbol} {day_info['precip_sum']:.1f}mm")
elif day_info['precip_sum'] > 0.1 and day_info.get('snowfall_sum', 0) > 0.1 and day_info['t_min'] > ICE_EVENT_MAX_AIR_TEMP:
# snowfall spurio a caldo: assicurati che l'accumulo pioggia totale sia visibile
if not any("🌧" in p or "⛈️" in p for p in precip_parts):
precip_parts.append(f"🌧️ {day_info['precip_sum']:.1f}mm")
snow_sum = day_info.get("snowfall_sum", 0) or 0
rain_sum = day_info.get("rain_sum", 0) or 0
showers_sum = day_info.get("showers_sum", 0) or 0
precip_sum = day_info.get("precip_sum", 0) or 0
if snow_sum > 0.1 and day_info["t_min"] <= ICE_EVENT_MAX_AIR_TEMP:
precip_parts.append(f"❄️ {snow_sum:.1f}cm")
overlapping = (
rain_sum > 0.1 and showers_sum > 0.1 and (
abs(rain_sum - precip_sum) < 0.25
or abs(showers_sum - precip_sum) < 0.25
or (rain_sum + showers_sum) > precip_sum + 0.3
)
)
if overlapping or (rain_sum <= 0.1 and showers_sum <= 0.1):
if precip_sum > 0.1:
precip_symbol = (
"❄️" if day_info["precip_type"] == "snow"
else "" if day_info["precip_type"] in ("hail", "thunderstorms")
else "🌨️" if day_info["precip_type"] == "mixed"
else "🌧️"
)
if not (day_info["precip_type"] == "snow" and snow_sum > 0.1 and day_info["t_min"] <= ICE_EVENT_MAX_AIR_TEMP):
precip_parts.append(f"{precip_symbol} {precip_sum:.1f}mm")
else:
if rain_sum > 0.1:
precip_parts.append(f"🌧️ {rain_sum:.1f}mm")
if showers_sum > 0.1:
precip_parts.append(f"⛈️ {showers_sum:.1f}mm")
line += f" | {' + '.join(precip_parts)}"