diff --git a/vigilancia/.env.example b/vigilancia/.env.example index 00c36c0..1ea1e80 100644 --- a/vigilancia/.env.example +++ b/vigilancia/.env.example @@ -30,3 +30,11 @@ SNAPSHOT_DIR=snapshots # Zonas autorizadas (nombres de camara separados por coma). # Si una camara esta aqui, sus presencias se marcan como "zona autorizada". ZONAS_AUTORIZADAS= + +# Destinatarios del mensaje personalizado cuando se identifica a una persona +# conocida (separados por coma). Cada uno debe haber hablado con el bot antes. +TELEGRAM_RECIPIENTES= + +# Discord: bot + usuarios a los que se envia el aviso personalizado (TTS). +DISCORD_TOKEN= +DISCORD_IDS= diff --git a/vigilancia/config.py b/vigilancia/config.py index d049695..abebc44 100644 --- a/vigilancia/config.py +++ b/vigilancia/config.py @@ -35,3 +35,10 @@ SNAPSHOT_DIR = os.getenv("SNAPSHOT_DIR", "snapshots") ZONAS_AUTORIZADAS = { n.strip() for n in os.getenv("ZONAS_AUTORIZADAS", "").split(",") if n.strip() } +RECIPIENTES = [ + x.strip() for x in os.getenv("TELEGRAM_RECIPIENTES", "").split(",") if x.strip() +] +DISCORD_TOKEN = os.getenv("DISCORD_TOKEN", "").strip() +DISCORD_IDS = [ + x.strip() for x in os.getenv("DISCORD_IDS", "").split(",") if x.strip() +] diff --git a/vigilancia/discord_notif.py b/vigilancia/discord_notif.py new file mode 100644 index 0000000..dbf0ead --- /dev/null +++ b/vigilancia/discord_notif.py @@ -0,0 +1,55 @@ +import config + +import requests +from datetime import datetime + +URL = "https://discord.com/api/v10" +_dm_cache = {} + + +def _headers(): + return {"Authorization": f"Bot {config.DISCORD_TOKEN}"} + + +def _dm_channel(user_id): + if user_id in _dm_cache: + return _dm_cache[user_id] + r = requests.post( + f"{URL}/users/@me/channels", + headers=_headers(), + json={"recipient_id": user_id}, + timeout=10, + ) + r.raise_for_status() + ch = r.json()["id"] + _dm_cache[user_id] = ch + return ch + + +def enviar_discord(texto, user_id, tts=True): + if not config.DISCORD_TOKEN or not user_id: + return + try: + ch = _dm_channel(user_id) + r = requests.post( + f"{URL}/channels/{ch}/messages", + headers=_headers(), + json={"content": texto, "tts": tts}, + timeout=10, + ) + if r.status_code not in (200, 201): + print(f"[Discord] Error {r.status_code}: {r.text[:200]}") + except Exception as e: + print(f"[Discord] Excepción: {e}") + + +def notificar_discord_personales(resultados, cam_nombre): + conocidas = {r["nombre"] for r in resultados if "nombre" in r} + if not conocidas or not config.DISCORD_IDS: + return + ts = datetime.now().strftime("%H:%M:%S") + for uid in config.DISCORD_IDS: + for nombre in sorted(conocidas): + texto = (f"🚨 {nombre}, ¿qué estás haciendo? " + f"(vista en {cam_nombre} a las {ts})") + enviar_discord(texto, uid) diff --git a/vigilancia/main.py b/vigilancia/main.py index 67ae00f..4a5017f 100644 --- a/vigilancia/main.py +++ b/vigilancia/main.py @@ -7,12 +7,35 @@ import cv2 import config from camara import CamaraRTSP from detector_movimiento import DetectorMovimiento -from notificador import disparar_webhook_alexa, enviar_telegram +from notificador import (disparar_webhook_alexa, enviar_telegram, + enviar_texto_telegram) USAR_YOLO = True identificador = None +def notificar_personales(resultados, cam_nombre): + """Mensaje personalizado por Telegram a cada destinatario segun la persona.""" + conocidas = {r["nombre"] for r in resultados if "nombre" in r} + if not conocidas or not config.RECIPIENTES: + return + nombres = ", ".join(sorted(conocidas)) + ts = datetime.now().strftime("%H:%M:%S") + for chat in config.RECIPIENTES: + for nombre in sorted(conocidas): + texto = (f"📢 {nombre}, ¿qué estás haciendo? " + f"(vista en {cam_nombre} a las {ts})") + enviar_texto_telegram(texto, chat_id=chat) + + +def notificar_discord(resultados, cam_nombre): + try: + from discord_notif import notificar_discord_personales + notificar_discord_personales(resultados, cam_nombre) + except Exception as e: + print(f"[Discord] Error: {e}") + + def cargar_identificador(): global identificador if identificador is None: @@ -129,9 +152,9 @@ def main(): ) texto = f"🚨 Presencia en {cam.nombre} - {ts}" + resultados = [] if ident is not None: try: - resultados = [] for _ in range(3): f2 = cam.leer_frame() if f2 is None: @@ -155,6 +178,12 @@ def main(): if cv2_ok: enviar_telegram(ruta, texto) + if resultados: + try: + notificar_personales(resultados, cam.nombre) + notificar_discord(resultados, cam.nombre) + except Exception as e: + print(f"[{cam.nombre}] Error notificando personales: {e}") disparar_webhook_alexa(texto) ultima_alerta[i] = ahora print(texto) diff --git a/vigilancia/notificador.py b/vigilancia/notificador.py index 3d87d1d..32c5e92 100644 --- a/vigilancia/notificador.py +++ b/vigilancia/notificador.py @@ -6,9 +6,10 @@ import requests import config -def enviar_telegram(ruta_imagen: str, texto: str): - if not config.TELEGRAM_TOKEN or not config.TELEGRAM_CHAT_ID: - print("[Telegram] Falta TELEGRAM_TOKEN o TELEGRAM_CHAT_ID") +def enviar_telegram(ruta_imagen: str, texto: str, chat_id=None): + chat_id = chat_id or config.TELEGRAM_CHAT_ID + if not config.TELEGRAM_TOKEN or not chat_id: + print("[Telegram] Falta TELEGRAM_TOKEN o chat_id") return url = f"https://api.telegram.org/bot{config.TELEGRAM_TOKEN}/sendPhoto" @@ -16,12 +17,31 @@ def enviar_telegram(ruta_imagen: str, texto: str): with open(ruta_imagen, "rb") as f: r = requests.post( url, - data={"chat_id": config.TELEGRAM_CHAT_ID, "caption": texto}, + data={"chat_id": chat_id, "caption": texto}, files={"photo": f}, timeout=10, ) if not r.ok: - print(f"[Telegram] Error {r.status_code}: {r.text}") + print(f"[Telegram] Error {r.status_code}: {r.text[:200]}") + except Exception as e: + print(f"[Telegram] Excepción al enviar: {e}") + + +def enviar_texto_telegram(texto: str, chat_id=None): + chat_id = chat_id or config.TELEGRAM_CHAT_ID + if not config.TELEGRAM_TOKEN or not chat_id: + print("[Telegram] Falta TELEGRAM_TOKEN o chat_id") + return + + url = f"https://api.telegram.org/bot{config.TELEGRAM_TOKEN}/sendMessage" + try: + r = requests.post( + url, + data={"chat_id": chat_id, "text": texto, "parse_mode": "HTML"}, + timeout=10, + ) + if not r.ok: + print(f"[Telegram] Error {r.status_code}: {r.text[:200]}") except Exception as e: print(f"[Telegram] Excepción al enviar: {e}")