diff --git a/homelab-ai-bot/monitor.py b/homelab-ai-bot/monitor.py index 02adf53f..6b5b8841 100644 --- a/homelab-ai-bot/monitor.py +++ b/homelab-ai-bot/monitor.py @@ -11,13 +11,12 @@ sys.path.insert(0, os.path.dirname(__file__)) from core import config, loki_client, proxmox_client, mail_client ALERT_STATE_FILE = os.path.join(os.path.dirname(__file__), ".alert_state.json") -ALERT_COOLDOWN_MINUTES = { - "mail": 120, - "container": 30, - "ram": 30, - "panic": 60, - "silence": 60, - "default": 60, +ALERT_COOLDOWN_SECONDS = { + "container": 1800, + "ram": 1800, + "panic": 3600, + "silence": 3600, + "default": 3600, } @@ -94,8 +93,26 @@ def check_all() -> list[str]: mail_client.init(cfg) important = mail_client.get_important_mails(hours=1) if important and "error" not in important[0]: - senders = [m["from"][:30] for m in important] - alerts.append(f"📧 {len(important)} wichtige Mail(s) (letzte Stunde): {', '.join(senders)}") + state = _load_alert_state() + seen = state.get("seen_mails", {}) + now = datetime.now(timezone.utc).timestamp() + + new_mails = [] + for m in important: + fp = hashlib.md5( + f"{m.get('date_str','')}|{m.get('from','')}|{m.get('subject','')}".encode() + ).hexdigest() + if fp not in seen: + new_mails.append(m) + seen[fp] = now + + seen = {k: v for k, v in seen.items() if now - v < 172800} + state["seen_mails"] = seen + _save_alert_state(state) + + if new_mails: + senders = [m["from"][:30] for m in new_mails] + alerts.append(f"📧 {len(new_mails)} neue wichtige Mail(s): {', '.join(senders)}") except Exception: pass @@ -160,8 +177,6 @@ def _alert_key(alert_text: str) -> str: def _alert_category(alert_text: str) -> str: - if "📧" in alert_text or "Mail" in alert_text: - return "mail" if "CT " in alert_text and "ist " in alert_text: return "container" if "RAM " in alert_text: @@ -174,24 +189,26 @@ def _alert_category(alert_text: str) -> str: def _filter_new_alerts(alerts: list[str]) -> list[str]: - """Filtert bereits gemeldete Alerts. Gibt nur neue/fällige zurück.""" + """Filtert bereits gemeldete Infra-Alerts per Cooldown. Mails werden separat in check_all() dedupliziert.""" state = _load_alert_state() now = datetime.now(timezone.utc).timestamp() + cooldowns = state.get("alert_cooldowns", {}) new_alerts = [] for alert in alerts: key = _alert_key(alert) cat = _alert_category(alert) - cooldown = ALERT_COOLDOWN_MINUTES.get(cat, 60) * 60 + cooldown = ALERT_COOLDOWN_SECONDS.get(cat, 3600) - last_sent = state.get(key, {}).get("ts", 0) + last_sent = cooldowns.get(key, {}).get("ts", 0) if now - last_sent > cooldown: new_alerts.append(alert) - state[key] = {"ts": now, "text": alert[:80], "cat": cat} + cooldowns[key] = {"ts": now, "text": alert[:80], "cat": cat} cutoff = now - 86400 - state = {k: v for k, v in state.items() if v.get("ts", 0) > cutoff} + cooldowns = {k: v for k, v in cooldowns.items() if v.get("ts", 0) > cutoff} + state["alert_cooldowns"] = cooldowns _save_alert_state(state) return new_alerts