Backup automatico script del 2026-02-15 07:00

This commit is contained in:
2026-02-15 07:00:02 +01:00
parent 812bcd002c
commit 11b6768fa3
@@ -1828,12 +1828,11 @@ def analyze_irrigation(
if rain_veto: if rain_veto:
veto_lines.append(f"🌧️ **VETO PIOGGIA**: Ultime 24h ≥ {PRECIP_VETO_MM_24H:.0f} mm — non avviare irrigazione.") veto_lines.append(f"🌧️ **VETO PIOGGIA**: Ultime 24h ≥ {PRECIP_VETO_MM_24H:.0f} mm — non avviare irrigazione.")
# Colpo d'occhio (box informazioni chiave) # Colpo d'occhio
glance = [ glance = [
status.strip(), status.strip(),
f"📍 {location_name} · {now.strftime('%d/%m/%Y %H:%M')}", f"📍 {location_name} · {now.strftime('%d/%m/%Y %H:%M')}",
"", "",
"**Umidità (layer irrigazione)**",
moisture_summary_line.strip(), moisture_summary_line.strip(),
"", "",
] ]
@@ -1848,123 +1847,72 @@ def analyze_irrigation(
# Costruisci report completo (strutturato) # Costruisci report completo (strutturato)
report_parts = [ report_parts = [
"\n".join(glance), "\n".join(glance),
""*30, ""*24,
"", "**Consiglio**",
"**📋 CONSIGLIO**",
"",
advice, advice,
"", "",
] ]
if timing_advice: if timing_advice:
report_parts.append("**Orario / Radiazione**\n") report_parts.append("**Orario** " + " · ".join(timing_advice))
report_parts.append("\n".join("" + t for t in timing_advice))
report_parts.append("") report_parts.append("")
if planning_8d_line: if planning_8d_line:
report_parts.append(planning_8d_line) report_parts.append(planning_8d_line.strip())
report_parts.append("")
report_parts.append(""*24)
# Dettagli tecnici (organizzati) # Dettagli tecnici (compatti, at a glance)
details = [] details = []
# Temperatura suolo: 0, 6, 18, 54 cm (ICON Seamless / EU)
soil_temp_0cm = _at(current_idx, soil_temp_0cm_list) soil_temp_0cm = _at(current_idx, soil_temp_0cm_list)
soil_temp_54cm = _at(current_idx, soil_temp_54cm_list) soil_temp_54cm = _at(current_idx, soil_temp_54cm_list)
temp_found = False temp_parts = []
for label, val in [ for label, val in [("0cm", soil_temp_0cm), ("6cm", soil_temp_6cm), ("18cm", soil_temp_18cm), ("54cm", soil_temp_54cm)]:
("0cm", soil_temp_0cm),
("6cm", soil_temp_6cm),
("18cm", soil_temp_18cm),
("54cm", soil_temp_54cm),
]:
if val is not None: if val is not None:
temp_class = classify_soil_temp(val) temp_parts.append(f"{label} {val:.1f}°C")
trend_str = f" | trend 7gg: {temp_trend}" if (temp_trend and label == "6cm") else "" if temp_parts:
details.append(f"🌡️ T° suolo ({label}): {val:.1f}°C ({temp_class}){trend_str}") trend_str = f" · trend 7gg: {temp_trend}" if temp_trend else ""
temp_found = True details.append("🌡️ T° suolo: " + " · ".join(temp_parts) + trend_str)
if not temp_found: elif soil_temp_0cm_list and current_idx < len(soil_temp_0cm_list) and soil_temp_0cm_list[current_idx] is not None:
for i in range(current_idx, min(current_idx + 48, len(soil_temp_0cm_list or []))): details.append(f"🌡️ T° suolo 0cm: {float(soil_temp_0cm_list[current_idx]):.1f}°C")
if i < len(soil_temp_0cm_list) and soil_temp_0cm_list[i] is not None:
details.append(f"🌡️ T° suolo (0cm): {float(soil_temp_0cm_list[i]):.1f}°C (prossime ore)")
temp_found = True
break
# Umidità suolo: 0-1, 3-9, 9-27, 27-81 cm (ICON Seamless / EU). Mostriamo sempre tutti i layer. moist_parts = []
moisture_found = False any_at_fc = False
for label, val in [ for label, val in [("0-1", soil_moisture_0_1cm), ("3-9", soil_moisture_3_9cm), ("9-27", soil_moisture_9_27cm), ("27-81", soil_moisture_27_81cm)]:
("0-1cm", soil_moisture_0_1cm),
("3-9cm", soil_moisture_3_9cm),
("9-27cm", soil_moisture_9_27cm),
("27-81cm", soil_moisture_27_81cm),
]:
if val is not None: if val is not None:
moisture_class = classify_soil_moisture(val) moist_parts.append(f"{label} {val*100:.0f}%")
line = f"💧 Umidità ({label}): {val*100:.0f}% ({moisture_class})"
if val >= SOIL_MOISTURE_FIELD_CAPACITY: if val >= SOIL_MOISTURE_FIELD_CAPACITY:
line += " — terreno pieno, possibile fanghiglia/ristagno" any_at_fc = True
details.append(line)
moisture_found = True
else: else:
details.append(f"💧 Umidità ({label}): — (non disponibile)") moist_parts.append(f"{label}")
if not moisture_found: if moist_parts:
for i in range(current_idx, min(current_idx + 48, len(soil_moisture_0_1_list or []))): line = "💧 Umidità: " + " · ".join(moist_parts)
if i < len(soil_moisture_0_1_list) and soil_moisture_0_1_list[i] is not None: if any_at_fc:
v = float(soil_moisture_0_1_list[i]) line += " — terreno pieno"
details.append(f"💧 Umidità (0-1cm): {v*100:.0f}% (prossime ore)") details.append(line)
moisture_found = True if not details:
break details.append("️ Dati suolo non disponibili")
if not temp_found and not moisture_found: # Una riga: ET₀, VPD, sole, umidità aria
details.append("️ Dati suolo non disponibili per questa località") meteo_parts = []
# ET₀ e parametri evapotraspirazione
if et0_avg is not None: if et0_avg is not None:
et0_class = classify_et0(et0_avg) meteo_parts.append(f"ET₀ {et0_avg:.1f} mm/d")
details.append(f"☀️ ET₀ medio (24h): {et0_avg:.1f} mm/d ({et0_class})")
# Vapour Pressure Deficit (stress idrico)
if vpd_avg is not None: if vpd_avg is not None:
vpd_class = classify_vpd(vpd_avg) meteo_parts.append(f"VPD {vpd_avg:.2f} kPa")
# VPD alto = stress idrico alto
vpd_status = ""
if vpd_avg > 1.5:
vpd_status = " (stress idrico elevato)"
elif vpd_avg > 1.0:
vpd_status = " (stress moderato)"
details.append(f"💨 VPD medio (24h): {vpd_avg:.2f} kPa ({vpd_class}){vpd_status}")
# Ore di sole previste
if sunshine_hours is not None: if sunshine_hours is not None:
sunshine_class = classify_sunshine(sunshine_hours) meteo_parts.append(f"Sole {sunshine_hours:.1f}h")
details.append(f"☀️ Ore sole previste (24h): {sunshine_hours:.1f}h ({sunshine_class})")
# Umidità relativa aria
if humidity_avg is not None: if humidity_avg is not None:
# Classifica umidità relativa (bassa < 40%, media 40-70%, alta > 70%) meteo_parts.append(f"UR {humidity_avg:.0f}%")
if humidity_avg < 40: if meteo_parts:
humidity_class = "basso (secco)" details.append("☀️ " + " · ".join(meteo_parts))
elif humidity_avg < 70:
humidity_class = "medio"
else:
humidity_class = "alto (umido)"
details.append(f"💨 Umidità relativa aria (24h): {humidity_avg:.0f}% ({humidity_class})")
# Precipitazioni previste (include neve) # Precipitazioni: una riga
if future_rain_total > 0: if future_rain_total > 0:
# Classifica come totale su 5 giorni (media giornaliera approssimativa) days_short = ", ".join(rainy_days[:3]) if rainy_days else ""
avg_daily = future_rain_total / 5.0 details.append(f"🌧️ Precip 5gg: {future_rain_total:.1f} mm — {days_short}")
precip_class = classify_precip_daily(avg_daily) else:
precip_str = f"🌧️ Precipitazioni previste (5gg): {future_rain_total:.1f}mm ({precip_class}, media ~{avg_daily:.1f}mm/giorno)" details.append("🌧️ Precip 5gg: 0 mm")
if rainy_days:
precip_str += f"\n Giorni: {', '.join(rainy_days[:3])}" # Primi 3 giorni
if len(rainy_days) > 3:
precip_str += f" +{len(rainy_days)-3} altri"
details.append(precip_str)
elif len(rainy_days) == 0:
details.append("🌧️ Precipitazioni previste (5gg): 0mm (basso)")
if details: if details:
report_parts.append(""*30) report_parts.append("**Dettagli**")
report_parts.append("**📊 Dettagli tecnici**")
report_parts.append("")
report_parts.append("\n".join(details)) report_parts.append("\n".join(details))
# Salva stato # Salva stato