LEDs de terraza reactivos a la música con Home Assistant y Python

Terraza nocturna con tira LED cálida iluminando la barandilla, gente disfrutando de la noche

Llevaba tiempo pensando en sincronizar los LEDs del perfil de la terraza con la música. No como una discoteca, sino como un ambiente: una cena de verano, música sonando por el altavoz Bluetooth, y las luces pulsando suavemente al ritmo. Esta semana lo monté — y de paso sobreviví a un ban de IP, un modo de recuperación de HA y un Python 3.14 con ganas de fastidiar.

Una mención especial para Claude.ai (para los amigos, Claudie), sin el cual este proyecto habría llevado el doble de tiempo. Tener un asistente que entiende el contexto del homelab, recuerda la arquitectura y ayuda a depurar en tiempo real es una ventaja enorme para este tipo de proyectos nocturnos.


El setup

Antes de entrar en materia, el contexto físico:

  • Tira LED SMD 5050 RGB en el perfil interior de la terraza, controlada por un Gledopto Zigbee RGB controller integrado en Zigbee2MQTT como light.leds_terraza
  • Behringer UMC404HD como interfaz de audio central en el despacho (mi equipo de sobremesa, Arch Linux)
  • 1Mii ML302+ (transmisor Bluetooth) conectado a los outputs 3/4 del Behringer → altavoz BT en la terraza
  • Home Assistant corriendo en una VM (HAOS, IP 192.168.1.20) sobre Proxmox en el homelab

El flujo de audio es: PC → Behringer → ML302+ → altavoz BT terraza. La música nunca toca HA. Eso es clave para entender la arquitectura.


La arquitectura

Behringer UMC404HD (En mi equipo de sobremesa)
    ↓ monitor de salida (PipeWire)
Script Python → API REST → HA → Z2M → Gledopto → LEDs terraza

El script corre en mi equipo de sobremesa, captura el audio directamente del monitor de salida del Behringer via PipeWire, analiza las frecuencias en tiempo real y envía comandos a HA por la API REST local.

Por qué no WLED ni controlador con micrófono: los LEDs están en la terraza y el Behringer en el despacho. No hay cable de audio entre ellos. Capturar desde PipeWire en origen es la solución más limpia.


El problema de sounddevice con Python 3.14

El primer intento fue con sounddevice, la librería habitual para captura de audio en Python. En Arch con Python 3.14 — crash inmediato con segfault o error de sample rate. No es un bug mío, es una incompatibilidad conocida.

La solución fue usar parec (PulseAudio/PipeWire) directamente via subprocess, pasando el audio por pipe a Python:

parec --device=alsa_output.usb-BEHRINGER_UMC404HD_192k-00.HiFi__Line1__sink.monitor \
      --format=s16le --rate=48000 --channels=2

Esto funciona perfectamente y es más estable que sounddevice en este entorno.


Detección de beats

El primer enfoque — calcular energía de frecuencias y normalizarla contra un valor fijo — no funcionó bien. La música tiene un nivel medio bastante constante y los LEDs se quedaban en un brillo fijo sin apenas variación.

La solución real es detección de onset: comparar el nivel actual de bajos con el promedio de las últimas N muestras. Si el valor actual supera 1.3x la media, es un beat.

def detect_beat(bass_n):
    bass_history.append(bass_n)
    if len(bass_history) > HISTORY_SIZE:
        bass_history.pop(0)
    promedio = sum(bass_history) / len(bass_history)
    if bass_n / promedio > BEAT_THRESHOLD:
        return BEAT_BRIGHTNESS  # pico → brillo máximo
    else:
        return max(BASE_BRIGHTNESS, (bass_n / promedio) * 0.3)

Así el sistema se adapta automáticamente al volumen y al tipo de música.


Control desde Home Assistant

Para no tener el script machacando los LEDs constantemente, el sistema tiene tres estados:

  • Boolean OFF: el script no toca los LEDs, HA los controla con normalidad
  • Boolean ON: el script activa el modo reactivo, guardando previamente el estado de los LEDs
  • Al desactivar: restaura automáticamente el color y brillo anteriores

Los parámetros de ajuste son input_number helpers en HA, que el script lee cada 2 segundos. Así se pueden tocar en tiempo real desde un dashboard sin reiniciar nada:

input_number:
  music_bass_norm:
    name: "Sensibilidad bajos"
    min: 50
    max: 500
    step: 10
    initial: 200
  music_beat_threshold:
    name: "Umbral de beat"
    min: 1.0
    max: 3.0
    step: 0.1
    initial: 1.3
  # ... etc

El dashboard

Una vista dedicada en HA con estética oscura, sliders para cada parámetro, botón de activar/desactivar y botón de restablecer valores por defecto. Todo en YAML, con mushroom cards y card-mod para el estilo.

Setup LEDs Música


Lo que salió mal (y cómo se arregló)

Autenticación con la API de HA: durante las pruebas tuve problemas con el token de acceso — hasta que no lo regeneré correctamente desde el perfil de usuario en HA, la API rechazaba las peticiones. Tres intentos fallidos son suficientes para que HA banee la IP, y con login_attempts_threshold: 3 en la config, es muy fácil llegar ahí. Solución definitiva: borrar /config/ip_bans.yaml y cambiar ip_ban_enabled: false — el ban solo tiene sentido para IPs externas, no para dispositivos de la LAN.

Modo de recuperación de HA: un slug con guión bajo (lovelace-leds_music-setup) en configuration.yaml es inválido. HA lo rechaza y arranca en modo recuperación. Los slugs solo admiten guiones normales.

Python 3.14 + sounddevice: incompatibilidad conocida. Solución: parec via subprocess.


Estado actual y próximos pasos

El sistema funciona, pero el script aún está en fase de ajuste. La latencia Zigbee (300-500ms) es el límite real del sistema — para house music a 128bpm el efecto se nota pero la sincronización no es perfecta. Los parámetros de detección de beats necesitan más tiempo de prueba en condiciones reales (de noche, con música, en la terraza) antes de dar el proyecto por cerrado.

Cuando el script esté más pulido, lo publicaré en el repositorio con la configuración completa de HA.

El siguiente paso natural sería sustituir el Gledopto por un ESP32 con WLED y entrada de línea directa — sin pasar por HA, sin latencia Zigbee. Pero eso es para otro post.

Jaume Ferré

Jaume Ferré

Tengo un trabajo que no tiene nada que ver con esto. Pero me gusta cacharrear con webs, Linux y el homelab. De vez en cuando alguien me paga por ello, lo cual siempre sorprende. Canon R7 en mano y Arch Linux de fondo.

¿Te ha sido útil?

Ayúdame a mejorar con tu puntuación.

0.0 (0 votos)
Comentarios