02-ago: [proyecto] vigilancia - integra middleware Alexa (alexa_notify.js/VoiceMonkey) + .env con credenciales de Telegram y VoiceMonkey + tests 18/18

This commit is contained in:
minguezsanzjuanjose
2026-08-02 13:17:45 +02:00
parent e75649f7e6
commit 75de5c613f
4 changed files with 71 additions and 0 deletions

View File

@@ -18,5 +18,11 @@ COOLDOWN=45
# Webhook Alexa/Node-RED (opcional, dejar vacío si no se usa) # Webhook Alexa/Node-RED (opcional, dejar vacío si no se usa)
WEBHOOK_ALEXA= WEBHOOK_ALEXA=
# Middleware VoiceMonkey (reutiliza scripts/alexa_notify.js de biblioteca_negocio_prolongo)
VOICEMONKEY_TOKEN=
VOICEMONKEY_DEVICE=
ALEXA_NODE=node
ALEXA_NOTIFY_SCRIPT=C:\Users\juanm\Documents\GitHub\biblioteca_negocio_prolongo\scripts\alexa_notify.js
# Directorio de snapshots # Directorio de snapshots
SNAPSHOT_DIR=snapshots SNAPSHOT_DIR=snapshots

View File

@@ -27,4 +27,8 @@ HORA_INICIO = int(os.getenv("HORA_INICIO", 0))
HORA_FIN = int(os.getenv("HORA_FIN", 23)) HORA_FIN = int(os.getenv("HORA_FIN", 23))
COOLDOWN = int(os.getenv("COOLDOWN", 30)) COOLDOWN = int(os.getenv("COOLDOWN", 30))
WEBHOOK_ALEXA = os.getenv("WEBHOOK_ALEXA", "").strip() WEBHOOK_ALEXA = os.getenv("WEBHOOK_ALEXA", "").strip()
VOICEMONKEY_TOKEN = os.getenv("VOICEMONKEY_TOKEN", "").strip()
VOICEMONKEY_DEVICE = os.getenv("VOICEMONKEY_DEVICE", "").strip()
ALEXA_NODE = os.getenv("ALEXA_NODE", "node")
ALEXA_NOTIFY_SCRIPT = os.getenv("ALEXA_NOTIFY_SCRIPT", "").strip()
SNAPSHOT_DIR = os.getenv("SNAPSHOT_DIR", "snapshots") SNAPSHOT_DIR = os.getenv("SNAPSHOT_DIR", "snapshots")

View File

@@ -1,3 +1,6 @@
import os
import subprocess
import requests import requests
import config import config
@@ -24,6 +27,23 @@ def enviar_telegram(ruta_imagen: str, texto: str):
def disparar_webhook_alexa(texto: str): def disparar_webhook_alexa(texto: str):
if config.ALEXA_NOTIFY_SCRIPT:
env = os.environ.copy()
if config.VOICEMONKEY_TOKEN:
env["VOICEMONKEY_TOKEN"] = config.VOICEMONKEY_TOKEN
if config.VOICEMONKEY_DEVICE:
env["VOICEMONKEY_DEVICE"] = config.VOICEMONKEY_DEVICE
try:
r = subprocess.run(
[config.ALEXA_NODE, config.ALEXA_NOTIFY_SCRIPT, texto],
env=env, timeout=15, capture_output=True, text=True,
)
if r.returncode != 0:
print(f"[Alexa] Error middleware: {r.stderr[:200]}")
except Exception as e:
print(f"[Alexa] Excepción lanzando middleware: {e}")
return
if not config.WEBHOOK_ALEXA: if not config.WEBHOOK_ALEXA:
return return

View File

@@ -142,12 +142,15 @@ def test_webhook_mock():
real = notificador.requests real = notificador.requests
notificador.requests = FakeRequests() notificador.requests = FakeRequests()
orig = config.WEBHOOK_ALEXA orig = config.WEBHOOK_ALEXA
orig_script = config.ALEXA_NOTIFY_SCRIPT
config.WEBHOOK_ALEXA = "http://localhost:1880/alexa" config.WEBHOOK_ALEXA = "http://localhost:1880/alexa"
config.ALEXA_NOTIFY_SCRIPT = ""
try: try:
disparar_webhook_alexa("PRUEBA") disparar_webhook_alexa("PRUEBA")
check("Webhook disparado cuando configurado", len(llamadas) == 1) check("Webhook disparado cuando configurado", len(llamadas) == 1)
finally: finally:
config.WEBHOOK_ALEXA = orig config.WEBHOOK_ALEXA = orig
config.ALEXA_NOTIFY_SCRIPT = orig_script
notificador.requests = real notificador.requests = real
llamadas.clear() llamadas.clear()
@@ -172,6 +175,43 @@ def test_yolo():
res is False) res is False)
def test_alexa_middleware():
print("\n--- RF-08: Middleware alexa_notify.js (mock subprocess) ---")
llamadas = {}
def fake_run(cmd, **kwargs):
llamadas["cmd"] = cmd
llamadas["env_token"] = kwargs.get("env", {}).get("VOICEMONKEY_TOKEN", "")
class R:
returncode = 0
stderr = ""
return R()
import notificador
real_run = notificador.subprocess.run
notificador.subprocess.run = fake_run
orig_script = config.ALEXA_NOTIFY_SCRIPT
orig_token = config.VOICEMONKEY_TOKEN
orig_dev = config.VOICEMONKEY_DEVICE
orig_node = config.ALEXA_NODE
config.ALEXA_NOTIFY_SCRIPT = "alexa_notify.js"
config.VOICEMONKEY_TOKEN = "VM_TOKEN_FAKE"
config.VOICEMONKEY_DEVICE = "echo-salon"
config.ALEXA_NODE = "node"
try:
disparar_webhook_alexa("PRUEBA movimiento")
check("Ejecuta node + script + texto",
llamadas.get("cmd") == ["node", "alexa_notify.js", "PRUEBA movimiento"])
check("Inyecta VOICEMONKEY_TOKEN al proceso",
llamadas.get("env_token") == "VM_TOKEN_FAKE")
finally:
notificador.subprocess.run = real_run
config.ALEXA_NOTIFY_SCRIPT = orig_script
config.VOICEMONKEY_TOKEN = orig_token
config.VOICEMONKEY_DEVICE = orig_dev
config.ALEXA_NODE = orig_node
def test_flujo_completo(): def test_flujo_completo():
print("\n--- RF-03/RF-04/RF-05: Flujo completo snapshot+cooldown (mock) ---") print("\n--- RF-03/RF-04/RF-05: Flujo completo snapshot+cooldown (mock) ---")
os.makedirs(config.SNAPSHOT_DIR, exist_ok=True) os.makedirs(config.SNAPSHOT_DIR, exist_ok=True)
@@ -202,6 +242,7 @@ if __name__ == "__main__":
test_franja_horaria() test_franja_horaria()
test_telegram_mock() test_telegram_mock()
test_webhook_mock() test_webhook_mock()
test_alexa_middleware()
test_yolo() test_yolo()
test_flujo_completo() test_flujo_completo()
print(f"\n=== RESULTADO: {APROBADOS} OK, {FALLIDOS} FALLO ===") print(f"\n=== RESULTADO: {APROBADOS} OK, {FALLIDOS} FALLO ===")