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