Compare commits

...

2 Commits

Author SHA1 Message Date
19df6ca479 Backup automatico script del 2025-12-02 21:49 2025-12-02 21:49:25 +01:00
658b7c13cb Backup automatico script del 2025-12-02 21:39 2025-12-02 21:39:13 +01:00
3 changed files with 277 additions and 15 deletions

View File

@@ -1,26 +1,61 @@
import requests import requests
import datetime import datetime
import time import time
import json
import os
from dateutil import parser from dateutil import parser
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
# --- CONFIGURAZIONE UTENTE --- # --- CONFIGURAZIONE UTENTE ---
# 👇👇 INSERISCI QUI I TUOI DATI 👇👇 # 👇👇 INSERISCI QUI I TUOI DATI 👇👇
TELEGRAM_BOT_TOKEN = "8155587974:AAF9OekvBpixtk8ZH6KoIc0L8edbhdXt7A4" TELEGRAM_BOT_TOKEN = "8155587974:AAF9OekvBpixtk8ZH6KoIc0L8edbhdXt7A4"
TELEGRAM_CHAT_IDS = ["64463169", "132455422"] TELEGRAM_CHAT_IDS = ["64463169", "24827341", "132455422", "5405962012"]
# --- PUNTI DI MONITORAGGIO --- # --- PUNTI DI MONITORAGGIO ---
# Il primo punto DEVE essere Casa tua # Sostituito San Leo con Carpegna
POINTS = [ POINTS = [
{"name": "🏠 Casa", "lat": 43.9356, "lon": 12.4296}, {"name": "🏠 Casa", "lat": 43.9356, "lon": 12.4296},
{"name": "⛰️ Titano", "lat": 43.9360, "lon": 12.4460}, {"name": "⛰️ Titano", "lat": 43.9360, "lon": 12.4460},
{"name": "🏢 Dogana", "lat": 43.9800, "lon": 12.4900}, {"name": "🏢 Dogana", "lat": 43.9800, "lon": 12.4900},
{"name": "🏰 San Leo", "lat": 43.8900, "lon": 12.3400} {"name": "🏔️ Carpegna", "lat": 43.7819, "lon": 12.3346}
] ]
# Soglia notifica (cm) # Soglia notifica (cm)
SOGLIA_NOTIFICA = 0.0 SOGLIA_NOTIFICA = 0.0
# File di stato per ricordare l'ultima allerta
STATE_FILE = "/home/daniely/docker/telegram-bot/snow_state.json"
# --- FUNZIONI DI UTILITÀ ---
def is_winter_season():
"""Ritorna True se oggi è tra il 1 Novembre e il 15 Aprile"""
now = datetime.datetime.now()
month = now.month
day = now.day
if month >= 11: return True # Nov, Dic
if month <= 3: return True # Gen, Feb, Mar
if month == 4 and day <= 15: return True # Fino al 15 Apr
return False
def load_last_state():
"""Legge se c'era un allerta attiva"""
if not os.path.exists(STATE_FILE): return False
try:
with open(STATE_FILE, 'r') as f:
data = json.load(f)
return data.get("alert_active", False)
except: return False
def save_current_state(is_active):
"""Salva lo stato corrente"""
try:
with open(STATE_FILE, 'w') as f:
json.dump({"alert_active": is_active, "updated": str(datetime.datetime.now())}, f)
except Exception as e:
print(f"Errore salvataggio stato: {e}")
def send_telegram_message(message): def send_telegram_message(message):
if not TELEGRAM_BOT_TOKEN or "INSERISCI" in TELEGRAM_BOT_TOKEN: if not TELEGRAM_BOT_TOKEN or "INSERISCI" in TELEGRAM_BOT_TOKEN:
print(f"[TEST OUT] {message}") print(f"[TEST OUT] {message}")
@@ -38,8 +73,7 @@ def send_telegram_message(message):
def get_forecast(lat, lon): def get_forecast(lat, lon):
url = "https://api.open-meteo.com/v1/forecast" url = "https://api.open-meteo.com/v1/forecast"
params = { params = {
"latitude": lat, "latitude": lat, "longitude": lon,
"longitude": lon,
"hourly": "snowfall", "hourly": "snowfall",
"models": "arome_france_hd", "models": "arome_france_hd",
"timezone": "Europe/Rome", "timezone": "Europe/Rome",
@@ -75,14 +109,25 @@ def calculate_sums(data):
if start_idx == -1: return None if start_idx == -1: return None
end = len(snow) end = len(snow)
s3 = sum(x for x in snow[start_idx:min(start_idx+3, end)] if x) # Calcola somme sugli orizzonti temporali
s6 = sum(x for x in snow[start_idx:min(start_idx+6, end)] if x) def get_sum(hours):
s12 = sum(x for x in snow[start_idx:min(start_idx+12, end)] if x) return sum(x for x in snow[start_idx:min(start_idx+hours, end)] if x)
s24 = sum(x for x in snow[start_idx:min(start_idx+24, end)] if x)
return {
return {"3h": s3, "6h": s6, "12h": s12, "24h": s24} "3h": get_sum(3),
"6h": get_sum(6),
"12h": get_sum(12),
"24h": get_sum(24)
}
# --- LOGICA PRINCIPALE ---
def analyze_snow(): def analyze_snow():
# 1. Controllo Stagionale
if not is_winter_season():
print("Stagione estiva. Script in pausa.")
return
now_str = datetime.datetime.now(ZoneInfo("Europe/Rome")).strftime('%H:%M') now_str = datetime.datetime.now(ZoneInfo("Europe/Rome")).strftime('%H:%M')
print(f"--- Check Meteo {now_str} ---") print(f"--- Check Meteo {now_str} ---")
@@ -90,6 +135,7 @@ def analyze_snow():
max_area_snow = 0.0 max_area_snow = 0.0
area_details = "" area_details = ""
# 2. Raccolta Dati
for p in POINTS: for p in POINTS:
data = get_forecast(p["lat"], p["lon"]) data = get_forecast(p["lat"], p["lon"])
stats = calculate_sums(data) stats = calculate_sums(data)
@@ -99,18 +145,26 @@ def analyze_snow():
if p["name"] == "🏠 Casa": if p["name"] == "🏠 Casa":
home_stats = stats home_stats = stats
# Aggiorna il massimo rilevato in zona
if stats["24h"] > max_area_snow: if stats["24h"] > max_area_snow:
max_area_snow = stats["24h"] max_area_snow = stats["24h"]
# Aggiungi ai dettagli area se c'è neve (>0) # Costruisci dettaglio se c'è neve
if stats["24h"] > 0: if stats["24h"] > 0:
area_details += f"{p['name']}: {stats['24h']:.1f}cm (12h: {stats['12h']:.1f})\n" area_details += f"{p['name']}: {stats['24h']:.1f}cm (12h: {stats['12h']:.1f})\n"
time.sleep(1) time.sleep(1)
# 3. Decisione Alert
# C'è neve se a casa o nei dintorni l'accumulo è > soglia
home_max = home_stats["24h"] if home_stats else 0.0 home_max = home_stats["24h"] if home_stats else 0.0
SNOW_DETECTED = (home_max > SOGLIA_NOTIFICA or max_area_snow > SOGLIA_NOTIFICA)
if home_max > SOGLIA_NOTIFICA or max_area_snow > SOGLIA_NOTIFICA: # Leggi stato precedente
WAS_ACTIVE = load_last_state()
# --- SCENARIO A: C'È NEVE (Nuova o Continua) ---
if SNOW_DETECTED:
def f(v): return f"**{v:.1f}**" if v > 0 else f"{v:.1f}" def f(v): return f"**{v:.1f}**" if v > 0 else f"{v:.1f}"
@@ -130,9 +184,26 @@ def analyze_snow():
msg += "🌍 Nessuna neve rilevante nei dintorni." msg += "🌍 Nessuna neve rilevante nei dintorni."
send_telegram_message(msg) send_telegram_message(msg)
save_current_state(True) # Salva che l'allerta è attiva
print("Neve rilevata. Notifica inviata.") print("Neve rilevata. Notifica inviata.")
# --- SCENARIO B: ALLARME RIENTRATO (Neve 0, ma prima c'era) ---
elif not SNOW_DETECTED and WAS_ACTIVE:
msg = (
f"🟢 **PREVISIONE NEVE ANNULLATA**\n"
f"📅 _Aggiornamento ore {now_str}_\n\n"
f"Le ultime previsioni AROME non indicano più accumuli nevosi rilevanti nelle prossime 24 ore.\n"
f"Situazione tornata alla normalità."
)
send_telegram_message(msg)
save_current_state(False) # Resetta lo stato
print("Allarme rientrato. Notifica inviata.")
# --- SCENARIO C: TUTTO TRANQUILLO (E lo era anche prima) ---
else: else:
print(f"Nessuna neve. Casa: {home_max}cm, Area Max: {max_area_snow}cm") # Aggiorna timestamp ma mantieni false
save_current_state(False)
print(f"Nessuna neve. Casa: {home_max}cm, Area: {max_area_snow}cm")
if __name__ == "__main__": if __name__ == "__main__":
analyze_snow() analyze_snow()

View File

@@ -8,7 +8,7 @@ from zoneinfo import ZoneInfo
# --- CONFIGURAZIONE --- # --- CONFIGURAZIONE ---
TELEGRAM_BOT_TOKEN = "8155587974:AAF9OekvBpixtk8ZH6KoIc0L8edbhdXt7A4" TELEGRAM_BOT_TOKEN = "8155587974:AAF9OekvBpixtk8ZH6KoIc0L8edbhdXt7A4"
TELEGRAM_CHAT_IDS = ["64463169", "132455422"] TELEGRAM_CHAT_IDS = ["64463169", "24827341", "132455422", "5405962012"]
# Coordinate (San Marino) # Coordinate (San Marino)
LAT = 43.9356 LAT = 43.9356

View File

@@ -0,0 +1,191 @@
import requests
import datetime
import time
import json
import os
from dateutil import parser
from zoneinfo import ZoneInfo
# --- CONFIGURAZIONE UTENTE ---
# 👇👇 INSERISCI QUI I TUOI DATI 👇👇
TELEGRAM_BOT_TOKEN = "8155587974:AAF9OekvBpixtk8ZH6KoIc0L8edbhdXt7A4"
TELEGRAM_CHAT_IDS = ["64463169", "24827341", "132455422", "5405962012"]
# --- SOGLIE DI ALLARME (Bologna) ---
SOGLIA_NEVE = 0.0 # cm (Basta neve per attivare)
SOGLIA_PIOGGIA_3H = 15.0 # mm in 3 ore (Pioggia molto forte)
# File di stato per la memoria
STATE_FILE = "/home/daniely/docker/telegram-bot/student_state.json"
# --- PUNTI DEL PERCORSO (Caselli A14) ---
POINTS = [
{"name": "🎓 Bologna (V. Regnoli)", "lat": 44.4930, "lon": 11.3690, "type": "trigger"},
{"name": "🛣️ Casello Imola", "lat": 44.3798, "lon": 11.7397, "type": "route"},
{"name": "🛣️ Casello Faenza", "lat": 44.3223, "lon": 11.9040, "type": "route"},
{"name": "🛣️ Casello Forlì", "lat": 44.2502, "lon": 12.0910, "type": "route"},
{"name": "🛣️ Casello Cesena", "lat": 44.1675, "lon": 12.2835, "type": "route"},
{"name": "🛣️ Casello Rimini", "lat": 44.0362, "lon": 12.5659, "type": "route"},
{"name": "🏠 San Marino", "lat": 43.9356, "lon": 12.4296, "type": "end"}
]
# --- FUNZIONI DI UTILITÀ ---
def load_last_state():
"""Legge se c'era un allerta attiva"""
if not os.path.exists(STATE_FILE): return False
try:
with open(STATE_FILE, 'r') as f:
data = json.load(f)
return data.get("alert_active", False)
except: return False
def save_current_state(is_active):
"""Salva lo stato corrente"""
try:
with open(STATE_FILE, 'w') as f:
json.dump({"alert_active": is_active, "updated": str(datetime.datetime.now())}, f)
except Exception as e:
print(f"Errore salvataggio stato: {e}")
def send_telegram_message(message):
if not TELEGRAM_BOT_TOKEN or "INSERISCI" in TELEGRAM_BOT_TOKEN:
print(f"[TEST OUT] {message}")
return
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
for chat_id in TELEGRAM_CHAT_IDS:
try:
requests.post(url, json={"chat_id": chat_id, "text": message, "parse_mode": "Markdown"}, timeout=10)
time.sleep(0.2)
except: pass
def get_forecast(lat, lon):
url = "https://api.open-meteo.com/v1/forecast"
params = {
"latitude": lat, "longitude": lon,
"hourly": "precipitation,snowfall",
"models": "arome_france_hd",
"timezone": "Europe/Rome",
"forecast_days": 2
}
try:
res = requests.get(url, params=params, timeout=5)
res.raise_for_status()
return res.json()
except: return None
def get_stats(data):
if not data: return None
hourly = data.get("hourly", {})
times = hourly.get("time", [])
snow = hourly.get("snowfall", [])
rain = hourly.get("precipitation", [])
now = datetime.datetime.now(ZoneInfo("Europe/Rome"))
start_idx = -1
for i, t in enumerate(times):
if parser.isoparse(t).replace(tzinfo=ZoneInfo("Europe/Rome")) >= now.replace(minute=0,second=0,microsecond=0):
start_idx = i
break
if start_idx == -1: return None
limit = min(start_idx + 24, len(times))
def sum_slice(arr, hours):
return sum(x for x in arr[start_idx:min(start_idx+hours, limit)] if x)
return {
"snow_3h": sum_slice(snow, 3),
"snow_6h": sum_slice(snow, 6),
"snow_12h": sum_slice(snow, 12),
"snow_24h": sum_slice(snow, 24),
"rain_3h": sum_slice(rain, 3),
"rain_max": max(rain[start_idx:limit]) if rain else 0
}
# --- LOGICA PRINCIPALE ---
def main():
print("--- Analisi Studente Bologna ---")
now_str = datetime.datetime.now(ZoneInfo("Europe/Rome")).strftime('%H:%M')
# 1. ANALISI BOLOGNA (Il Trigger)
bo_point = POINTS[0]
bo_data = get_forecast(bo_point["lat"], bo_point["lon"])
bo_stats = get_stats(bo_data)
if not bo_stats: return
# Controlla se scatta l'allarme
alarm_snow = bo_stats["snow_24h"] > SOGLIA_NEVE
alarm_rain = bo_stats["rain_3h"] > SOGLIA_PIOGGIA_3H
# Carica stato precedente
WAS_ACTIVE = load_last_state()
# --- SCENARIO A: C'È ALLERTA ---
if alarm_snow or alarm_rain:
icon_main = "❄️" if alarm_snow else "🌧️"
msg = f"{icon_main} **ALLERTA METEO BOLOGNA**\n"
msg += f"📅 _Aggiornamento ore {now_str}_\n\n"
# Dettaglio Bologna
msg += f"🎓 **A BOLOGNA:**\n"
if alarm_snow:
msg += f"• Neve 3h: **{bo_stats['snow_3h']:.1f}** cm\n"
msg += f"• Neve 6h: **{bo_stats['snow_6h']:.1f}** cm\n"
msg += f"• Neve 12h: **{bo_stats['snow_12h']:.1f}** cm\n"
msg += f"• Neve 24h: **{bo_stats['snow_24h']:.1f}** cm\n"
if alarm_rain:
msg += f"• Pioggia 3h: **{bo_stats['rain_3h']:.1f}** mm (Intensa!)\n"
msg += "\n🚗 **SITUAZIONE AI CASELLI (A14):**\n"
# 2. ANALISI PERCORSO (Solo se c'è allerta)
route_issues = False
for p in POINTS[1:]:
stats = get_stats(get_forecast(p["lat"], p["lon"]))
if not stats: continue
has_snow = stats["snow_24h"] > 0
has_rain = stats["rain_3h"] > 5.0
if has_snow or has_rain:
route_issues = True
line = f"**{p['name']}**: "
if has_snow: line += f"❄️ {stats['snow_12h']:.1f}cm (12h) "
if has_rain: line += f"🌧️ {stats['rain_3h']:.1f}mm "
msg += f"{line}\n"
if not route_issues:
msg += "✅ I caselli autostradali sembrano puliti."
send_telegram_message(msg)
save_current_state(True)
print("Allerta inviata.")
# --- SCENARIO B: ALLARME RIENTRATO ---
elif not (alarm_snow or alarm_rain) and WAS_ACTIVE:
msg = (
f"🟢 **ALLARME RIENTRATO (Bologna)**\n"
f"📅 _Aggiornamento ore {now_str}_\n\n"
f"Le previsioni non indicano più neve o piogge critiche per le prossime 24 ore.\n"
f"Situazione tornata alla normalità."
)
send_telegram_message(msg)
save_current_state(False)
print("Allarme rientrato. Notifica inviata.")
# --- SCENARIO C: TRANQUILLO ---
else:
save_current_state(False)
print("Nessuna allerta.")
if __name__ == "__main__":
main()