Backup automatico script del 2026-02-01 07:00
This commit is contained in:
@@ -201,11 +201,11 @@ def get_weather_data(lat, lon, model_slug, include_past_days=1):
|
|||||||
# Modificati per ridurre falsi positivi mantenendo alta sensibilità
|
# Modificati per ridurre falsi positivi mantenendo alta sensibilità
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
H_COLD_THR = 69.0 # hPa (Profondità minima strato freddo)
|
H_COLD_THR = 69.0 # hPa (Profondità minima strato freddo)
|
||||||
T_COLD_THR = 0.09 # °C (Temp max al suolo considerata 'fredda') - mantenuta bassa per evitare falsi negativi
|
T_COLD_THR = -0.5 # °C (Temp max al suolo considerata 'fredda') - abbassata da 0.09 per meno falsi positivi (solo quando è più gelido)
|
||||||
T_MELT_THR = 0.0 # °C (Temp min per considerare uno strato 'in fusione') - aumentata da -0.64°C a 0.0°C per ridurre falsi positivi mantenendo sensibilità
|
T_MELT_THR = 0.0 # °C (Temp min per considerare uno strato 'in fusione') - aumentata da -0.64°C a 0.0°C per ridurre falsi positivi mantenendo sensibilità
|
||||||
RH_MELT_THR = 89.0 # % (Umidità relativa minima nello strato di fusione)
|
RH_MELT_THR = 89.0 # % (Umidità relativa minima nello strato di fusione)
|
||||||
PR_THR_6H = 0.39 # mm/6h
|
PR_THR_6H = 0.39 # mm/6h
|
||||||
PR_THR_1H = 0.1 # mm/h - aumentata da 0.065 per richiedere precipitazione più significativa
|
PR_THR_1H = 0.25 # mm/h - alzata da 0.1 per richiedere precipitazione più significativa (meno allerte gelicidio)
|
||||||
# Differenza minima temperatura tra strato di fusione e suolo (per ridurre falsi positivi)
|
# Differenza minima temperatura tra strato di fusione e suolo (per ridurre falsi positivi)
|
||||||
T_MELT_SURFACE_DIFF = 1.0 # °C - lo strato di fusione deve essere almeno 1°C più caldo del suolo (bilanciato tra riduzione falsi positivi e mantenimento sensibilità)
|
T_MELT_SURFACE_DIFF = 1.0 # °C - lo strato di fusione deve essere almeno 1°C più caldo del suolo (bilanciato tra riduzione falsi positivi e mantenimento sensibilità)
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ TOKEN_FILE_ETC = "/etc/telegram_dpc_bot_token"
|
|||||||
# Zone target (come compaiono tipicamente nel testo del bollettino)
|
# Zone target (come compaiono tipicamente nel testo del bollettino)
|
||||||
TARGET_ZONES = {
|
TARGET_ZONES = {
|
||||||
"EMR-B2": "Costa romagnola",
|
"EMR-B2": "Costa romagnola",
|
||||||
|
"EMR-B1": "Pianura romagnola",
|
||||||
"EMR-A2": "Alta collina romagnola",
|
"EMR-A2": "Alta collina romagnola",
|
||||||
"EMR-D1": "Pianura bolognese",
|
"EMR-D1": "Pianura bolognese",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ import requests
|
|||||||
|
|
||||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
DEFAULT_PATTERNS = ["*.log", "*_log.txt"]
|
DEFAULT_PATTERNS = ["*.log", "*_log.txt"]
|
||||||
|
EXCLUDED_FILES = {
|
||||||
|
"circondario_log.txt",
|
||||||
|
"road_weather.log",
|
||||||
|
"snow_radar.log",
|
||||||
|
}
|
||||||
TOKEN_FILE_HOME = os.path.expanduser("~/.telegram_dpc_bot_token")
|
TOKEN_FILE_HOME = os.path.expanduser("~/.telegram_dpc_bot_token")
|
||||||
TOKEN_FILE_ETC = "/etc/telegram_dpc_bot_token"
|
TOKEN_FILE_ETC = "/etc/telegram_dpc_bot_token"
|
||||||
|
|
||||||
@@ -21,7 +26,8 @@ TS_RE = re.compile(r"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})")
|
|||||||
|
|
||||||
CATEGORIES = {
|
CATEGORIES = {
|
||||||
"open_meteo_timeout": re.compile(
|
"open_meteo_timeout": re.compile(
|
||||||
r"timeout|timed out|Read timed out|Gateway Time-out|504", re.IGNORECASE
|
r"timeout|timed out|Read timed out|Gateway Time-out|HTTP\s*504|status\s*504|\b504\b",
|
||||||
|
re.IGNORECASE,
|
||||||
),
|
),
|
||||||
"ssl_handshake": re.compile(r"handshake", re.IGNORECASE),
|
"ssl_handshake": re.compile(r"handshake", re.IGNORECASE),
|
||||||
"permission_error": re.compile(r"PermissionError|permesso negato|Errno 13", re.IGNORECASE),
|
"permission_error": re.compile(r"PermissionError|permesso negato|Errno 13", re.IGNORECASE),
|
||||||
@@ -207,6 +213,9 @@ def main():
|
|||||||
parser.add_argument("--log", action="append", help="Aggiungi un file log specifico")
|
parser.add_argument("--log", action="append", help="Aggiungi un file log specifico")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
run_ts = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
print(f"--- Log Monitor run {run_ts} ---")
|
||||||
|
|
||||||
if args.log:
|
if args.log:
|
||||||
files = [p for p in args.log if os.path.exists(p)]
|
files = [p for p in args.log if os.path.exists(p)]
|
||||||
else:
|
else:
|
||||||
@@ -215,6 +224,7 @@ def main():
|
|||||||
for pat in DEFAULT_PATTERNS:
|
for pat in DEFAULT_PATTERNS:
|
||||||
files.extend(sorted([str(p) for p in Path(BASE_DIR).glob(pat)]))
|
files.extend(sorted([str(p) for p in Path(BASE_DIR).glob(pat)]))
|
||||||
files = sorted(set(files))
|
files = sorted(set(files))
|
||||||
|
files = [p for p in files if os.path.basename(p) not in EXCLUDED_FILES]
|
||||||
|
|
||||||
since = datetime.datetime.now() - datetime.timedelta(days=args.days)
|
since = datetime.datetime.now() - datetime.timedelta(days=args.days)
|
||||||
category_hits, per_file_counts, timeout_minutes, stale_logs = analyze_logs(files, since, args.max_lines)
|
category_hits, per_file_counts, timeout_minutes, stale_logs = analyze_logs(files, since, args.max_lines)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from typing import List, Optional
|
|||||||
|
|
||||||
# --- CONFIGURAZIONE ---
|
# --- CONFIGURAZIONE ---
|
||||||
BOT_TOKEN="8155587974:AAF9OekvBpixtk8ZH6KoIc0L8edbhdXt7A4"
|
BOT_TOKEN="8155587974:AAF9OekvBpixtk8ZH6KoIc0L8edbhdXt7A4"
|
||||||
TELEGRAM_CHAT_IDS = ["64463169", "24827341", "132455422", "5405962012"]
|
TELEGRAM_CHAT_IDS = ["64463169"]
|
||||||
|
|
||||||
# BERSAGLIO (Cloudflare è solitamente il più stabile per i ping)
|
# BERSAGLIO (Cloudflare è solitamente il più stabile per i ping)
|
||||||
TARGET_HOST = "1.1.1.1"
|
TARGET_HOST = "1.1.1.1"
|
||||||
@@ -86,8 +86,20 @@ def measure_quality(chat_ids: Optional[List[str]] = None):
|
|||||||
|
|
||||||
# Parsing Packet Loss
|
# Parsing Packet Loss
|
||||||
# Cerca pattern: "X% packet loss"
|
# Cerca pattern: "X% packet loss"
|
||||||
loss_match = re.search(r'(\d+)% packet loss', output)
|
loss_match = re.search(r'([0-9]+(?:[\\.,][0-9]+)?)% packet loss', output)
|
||||||
loss = int(loss_match.group(1)) if loss_match else 100
|
if loss_match:
|
||||||
|
loss_raw = loss_match.group(1).replace(",", ".")
|
||||||
|
try:
|
||||||
|
loss = float(loss_raw)
|
||||||
|
except Exception:
|
||||||
|
loss = 100.0
|
||||||
|
else:
|
||||||
|
loss = 100.0
|
||||||
|
# Clamp to avoid parsing artifacts (e.g., "0.96078%" -> 0.96078, not 96078).
|
||||||
|
if loss < 0:
|
||||||
|
loss = 0.0
|
||||||
|
if loss > 100:
|
||||||
|
loss = 100.0
|
||||||
|
|
||||||
# Parsing Jitter (mdev)
|
# Parsing Jitter (mdev)
|
||||||
# Output tipico: rtt min/avg/max/mdev = 10.1/12.5/40.2/5.1 ms
|
# Output tipico: rtt min/avg/max/mdev = 10.1/12.5/40.2/5.1 ms
|
||||||
@@ -101,7 +113,7 @@ def measure_quality(chat_ids: Optional[List[str]] = None):
|
|||||||
else:
|
else:
|
||||||
avg_ping = 0.0
|
avg_ping = 0.0
|
||||||
|
|
||||||
result_line = f"Risultati: Loss={loss}% | Jitter={jitter}ms | AvgPing={avg_ping}ms"
|
result_line = f"Risultati: Loss={loss:.2f}% | Jitter={jitter}ms | AvgPing={avg_ping}ms"
|
||||||
print(result_line)
|
print(result_line)
|
||||||
log_line(f"INFO {result_line}")
|
log_line(f"INFO {result_line}")
|
||||||
|
|
||||||
@@ -116,7 +128,7 @@ def measure_quality(chat_ids: Optional[List[str]] = None):
|
|||||||
# NUOVO ALLARME
|
# NUOVO ALLARME
|
||||||
msg = f"📉 **DEGRADO QUALITÀ LINEA**\n\n"
|
msg = f"📉 **DEGRADO QUALITÀ LINEA**\n\n"
|
||||||
if loss >= LIMIT_LOSS:
|
if loss >= LIMIT_LOSS:
|
||||||
msg += f"🔴 **Packet Loss:** `{loss}%` (Soglia {LIMIT_LOSS}%)\n"
|
msg += f"🔴 **Packet Loss:** `{loss:.2f}%` (Soglia {LIMIT_LOSS}%)\n"
|
||||||
if jitter >= LIMIT_JITTER:
|
if jitter >= LIMIT_JITTER:
|
||||||
msg += f"⚠️ **Jitter (Instabilità):** `{jitter}ms` (Soglia {LIMIT_JITTER}ms)\n"
|
msg += f"⚠️ **Jitter (Instabilità):** `{jitter}ms` (Soglia {LIMIT_JITTER}ms)\n"
|
||||||
|
|
||||||
@@ -133,7 +145,7 @@ def measure_quality(chat_ids: Optional[List[str]] = None):
|
|||||||
# RECOVERY
|
# RECOVERY
|
||||||
msg = f"✅ **QUALITÀ LINEA RIPRISTINATA**\n\n"
|
msg = f"✅ **QUALITÀ LINEA RIPRISTINATA**\n\n"
|
||||||
msg += f"I parametri sono rientrati nella norma.\n"
|
msg += f"I parametri sono rientrati nella norma.\n"
|
||||||
msg += f"Ping: `{avg_ping}ms` | Jitter: `{jitter}ms` | Loss: `{loss}%`"
|
msg += f"Ping: `{avg_ping}ms` | Jitter: `{jitter}ms` | Loss: `{loss:.2f}%`"
|
||||||
send_telegram(msg, chat_ids=chat_ids)
|
send_telegram(msg, chat_ids=chat_ids)
|
||||||
save_state(False)
|
save_state(False)
|
||||||
print("Recovery inviata.")
|
print("Recovery inviata.")
|
||||||
|
|||||||
Reference in New Issue
Block a user