El problema
El interfono Fermax VDS con un relé Zigbee soldado al botón de abrir (no se modifica el cableado original, solo añado un puente para poder activarlo desde HA), y un Ring Intercom Video que me da notificación remota con video cuando llaman.
El Ring funciona bien pero dependes 100% de la nube de Ring para todo. Y peor todavía: solo puedes contestar desde la app móvil. La integración oficial de Ring en HA no expone la cámara ni permite hablar al portero ni abrir la puerta de forma cómoda desde un dashboard, son funcionalidades exclusivas desde la app de Ring.
Llevaba meses pensando en cómo integrarlo del todo. Al final me he liado la manta a la cabeza y he creado dos piezas open source que sí cubren todo el flujo:
- Una custom integration en Python que expone el WebRTC del Ring Intercom como entidades nativas de HA
- Una Lovelace card con UI completa: video + audio bidireccional push-to-talk + abrir puerta + colgar
Las dos publicadas en GitHub bajo Apache 2.0 e instalables desde HACS. Aquí cuento el viaje entero.
Qué quería conseguir
- Ver video del portero en el dashboard (wallpanel)
- Hablar al portero desde HA, no solo escuchar
- Abrir la puerta con un botón
- Popup automático en el wallpanel cuando alguien llame
- Todo dentro de HA, sin usar app de Ring
La arquitectura final
El flujo es: alguien llama al portero Ring, el event ding del Ring se actualiza en HA, se enciende la pantalla del wallpanel, aparece el popup con la card del intercom, pulso "Descolgar", el micrófono se activa, video del portero + audio bidireccional via WebRTC P2P, y finalmente abro puerta o cuelgo.
El stack final tiene tres piezas mías + dos de terceros:
- ring-intercom-video — custom integration en Python (mía)
- ring-intercom-video-card — Lovelace card frontend (mía)
- Automation
popup_intercom_llamada_wallpanel— el cerebro del popup automático (mía) - browser_mod — para lanzar el popup
- HA Companion app en una tablet Android montada en pared
Parte 1: la custom integration en Python
La integración oficial de Ring en HA usa python-ring-doorbell por debajo, pero limita el WebRTC a recvonly desde la perspectiva del navegador. Mi integración hace algo parecido pero exponiendo el peer connection al frontend con la dirección correcta, y añade entidades específicas del intercom (lock, event del timbre, etc).
El descubrimiento que lo cambió todo
La pieza clave: el Ring Intercom acepta audio bidireccional WebRTC sin trucos raros. Y nadie lo había documentado.
La integración oficial de Ring en HA negocia con la nube de Ring en modo audio: recvonly (el browser solo recibe). Pero si fuerzas el offer SDP a audio: sendrecv y añades una pista real de micrófono via getUserMedia, Ring responde con sendrecv también, sin protestar.
Lo confirmé mirando los SDPs en DevTools de Firefox: con la integración oficial sola, el browser usa a=recvonly y Ring responde a=sendonly. Con mi integración + card forzando sendrecv y enviando audio real, ambos lados usan a=sendrecv y Ring lo acepta sin problemas.
Esto lo cambió todo. Sin esto, el proyecto no tendría sentido.
Qué expone
La integración registra varias entidades en HA al añadir el Ring Intercom:
camera.intercom_video_camera— video WebRTC en directolock.intercom_video_lock— abrir la puerta vía API de Ringevent.intercom_video_timbre_de_la_puerta— evento ding cuando llamanevent.intercom_video_movimiento— evento de detección de movimiento- Sensores de batería, conectividad, etc.
Y por debajo, usa las APIs WebSocket estándar de HA (camera/webrtc/offer, camera/webrtc/candidate) para que cualquier cliente WebRTC pueda conectarse. Esto es importante porque significa que la card (parte 2) no tiene acoplamiento fuerte con la integración: usa interfaces estándar de HA.
Parte 2: la Lovelace card en JavaScript
He hecho la card en vanilla JS, sin frameworks ni build tools. Un solo archivo ring-intercom-video-card.js para que HACS lo sirva directo.
Las partes clave
Negociación WebRTC: creo un RTCPeerConnection con bundlePolicy: 'max-bundle', añado el transceiver de audio con dirección sendrecv pasándole la pista del localStream, y añado el transceiver de video con dirección recvonly.
Push-to-talk: el micro va muteado por defecto y solo se activa mientras mantengo pulsado el botón verde. Así evito enviar audio constantemente y reduzco el riesgo de eco/feedback con el altavoz del portero. La implementación es simple: al pulsar el botón pongo enabled = true en los audio tracks del localStream, y al soltarlo lo pongo a false.
Integración con HA: usa la API WebSocket estándar de HA, camera/webrtc/offer y camera/webrtc/candidate. Me suscribo al mensaje pasando el tipo, el entity_id de la cámara y el localDescription.sdp del peer connection. Esto es lo que mencionaba antes: la card no sabe nada de mi integración Python, podría funcionar con cualquier backend que respete la interfaz WebRTC estándar de HA.
El editor visual y las sorpresas
Quería un editor visual decente con dropdowns para no tener que escribir YAML a mano. Total, eso me trajo varias sorpresas que merecen mención porque otros que hagan cards seguro se topan con lo mismo.
i18n
Como pensaba publicar la card para la comunidad y hay mucha gente catalana/española usando HA, añadí internacionalización desde el principio: español, inglés y catalán.
Implementación simple: un objeto TRANSLATIONS con keys por idioma y una función detectLanguage(hass, configLang) que primero mira si el usuario fuerza language: es en el YAML, después lee hass.locale.language, y si el idioma no está soportado hace fallback a inglés.
Parte 3: popup automático con browser_mod
Con la integración y la card funcionando, el siguiente paso lógico: que apareciera sola cuando alguien llamara, sin tener que navegar al dashboard del intercom.
Combinando dos automatizaciones: una para encender la pantalla del wallpanel cuando se actualiza el evento del timbre del Ring (vía notify.mobile_app_wallpanel con command_screen_on), y otra para lanzar el popup browser_mod con la card embebida dentro, configurado con mode: restart, dismissable: true y un timeout de 60 segundos.
El timeout de 60s asegura que si no contesto, el popup se cierra solo y libera recursos.
El detalle del HTTPS (el más doloroso)
Aquí venía el problema grande: los navegadores no permiten acceder al micrófono (getUserMedia) si la página se sirve por HTTP plano. Es una restricción de seguridad y no hay manera elegante de saltársela, hay que implementar HTTPS si no lo tienes.
Publicación: HACS-ready desde el día uno
Las dos piezas están empaquetadas para HACS como "custom repository" (de momento, ya solicitaré inclusión en el default cuando lleve unas semanas estable en uso por más gente).
Integration (ring-intercom-video): estructura estándar de custom_components con manifest.json, hacs.json, archivos Python organizados por entidad (camera.py, lock.py, etc), y traducciones en translations/.
Card (ring-intercom-video-card): estructura mínima con LICENSE (Apache-2.0), README.md, hacs.json con el manifest, info.md con la descripción para HACS UI, y el archivo principal ring-intercom-video-card.js.
El hacs.json de la card es muy simple: solo necesita name, filename, render_readme a true y la versión mínima de homeassistant.
Resultado final
Veo el video del interfono desde cualquier dispositivo con HA, hablo con quien llama sin necesidad de descolgar el telefonillo físico, abro la puerta con un botón, cuando llaman aparece el popup solo en el wall panel, la UI se adapta al idioma de HA, y todo está publicado en GitHub bajo Apache 2.0 e instalable desde HACS.
Enlaces
- Custom integration (backend): github.com/cmos486/ring-intercom-video
- Lovelace card (frontend): github.com/cmos486/ring-intercom-video-card
- Hilo en el foro de HA (card): community.home-assistant.io