jueves, 23 de julio de 2026

Cómo configurar un screensaver/apagado de pantalla en Raspberry Pi 4 con labwc (kiosko)

Si tienes una Raspberry Pi 4 configurada como kiosko con labwc (Wayland) y necesitas que la pantalla se apague tras 10 minutos de inactividad, pero usas wtype para simular pulsaciones de teclado (por ejemplo, para rotar tabs en Chromium), te habrás encontrado con un problema: swayidle nunca detecta inactividad porque wtype genera eventos de entrada constantemente.

En esta guía explico la solución que me ha funcionado: eliminar wtype y usar una extensión nativa de Chrome para rotar tabs, liberando el idle monitor para que funcione correctamente.


1. El problema: wtype vs. swayidle

Mi configuración original usaba un script switchtab.sh con wtype para enviar Ctrl+Tab cada 10 segundos:

#!/bin/bash

chromium_pid=$(pgrep chromium | head -1)

while [[ -z $chromium_pid ]]; do
  sleep 5
  chromium_pid=$(pgrep chromium | head -1)
done

while true; do
  wtype -M ctrl -P Tab -p Tab
  sleep 10
done

Esto funciona para rotar tabs, pero swayidle detecta cada pulsación de wtype como actividad del usuario, por lo que el timeout de 10 minutos nunca se cumple.

swayidle -w timeout 600 'wlopm --off HDMI-A-1' resume 'wlopm --on HDMI-A-1' &

Resultado: la pantalla nunca se apaga.


2. La solución: Extensión de Chrome para rotar tabs

En lugar de simular teclado desde fuera, hacemos que Chromium gestione la rotación internamente mediante una extensión. Así no hay eventos de entrada falsos y swayidle puede medir la inactividad real del usuario.

2.1. Crear la extensión

Crea la carpeta y los archivos:

mkdir -p ~/chrome-rotator

Archivo ~/chrome-rotator/manifest.json:

{
  "manifest_version": 3,
  "name": "Tab Rotator",
  "version": "1.0",
  "permissions": ["tabs"],
  "background": {
    "service_worker": "background.js"
  }
}

Archivo ~/chrome-rotator/background.js:

setInterval(() => {
  chrome.tabs.query({currentWindow: true}, (tabs) => {
    if (tabs.length > 1) {
      let current = tabs.findIndex(t => t.active);
      let next = (current + 1) % tabs.length;
      chrome.tabs.update(tabs[next].id, {active: true});
    }
  });
}, 10000);

2.2. Lanzar Chromium con la extensión

En tu ~/.config/labwc/autostart, lanza Chromium así:

chromium 'https://btc-clock.com' \
    --kiosk \
    --noerrdialogs \
    --disable-infobars \
    --no-first-run \
    --enable-features=OverlayScrollbar \
    --start-maximized \
    --load-extension=/home/pi/chrome-rotator &

Nota: Cambia /home/pi por tu usuario real (por ejemplo, /home/user).


3. Configurar swayidle en labwc

Ahora que no hay eventos de teclado falsos, swayidle funciona correctamente. Añade al final de tu ~/.config/labwc/autostart:

export WAYLAND_DISPLAY="${WAYLAND_DISPLAY:-wayland-1}"
swayidle -w timeout 600 'wlopm --off HDMI-A-1' resume 'wlopm --on HDMI-A-1' &

Explicación de los parámetros:

  • timeout 600: 600 segundos = 10 minutos de inactividad real.
  • wlopm --off HDMI-A-1: Apaga la salida HDMI-A-1.
  • resume 'wlopm --on HDMI-A-1': Enciende la pantalla al detectar cualquier evento de ratón o teclado.

4. Archivo autostart completo

Así queda mi ~/.config/labwc/autostart completo:

# Asegurar entorno Wayland
export WAYLAND_DISPLAY="${WAYLAND_DISPLAY:-wayland-1}"

# Chromium en modo kiosko con rotador de tabs nativo
chromium 'https://btc-clock.com' \
    --kiosk \
    --noerrdialogs \
    --disable-infobars \
    --no-first-run \
    --enable-features=OverlayScrollbar \
    --start-maximized \
    --load-extension=/home/pi/chrome-rotator &

# Screensaver: apagar pantalla a los 10 min de inactividad real
swayidle -w timeout 600 'wlopm --off HDMI-A-1' resume 'wlopm --on HDMI-A-1' &

5. Dependencias necesarias

Asegúrate de tener instalados los paquetes:

sudo apt install swayidle wlopm

Verifica tu salida de video con:

wlopm

Si tu salida no es HDMI-A-1, sustitúyela en los comandos anteriores.


6. Resultado

✅ La Raspberry Pi muestra el kiosko rotando tabs cada 10 segundos.
✅ Si nadie toca la pantalla durante 10 minutos, se apaga automáticamente.
✅ Al tocar el ratón o pantalla táctil, se enciende de nuevo.
✅ No más conflictos entre wtype y swayidle.


Referencias

sábado, 11 de julio de 2026

Guía paso a paso: Repara la conexión SSH bloqueada en tu Raspberry Pi sin usar contraseñas

Configurar una conexión SSH mediante llaves con una Raspberry Pi es ideal para automatizar tareas, pero a veces el comando se queda congelado sin dar ninguna explicación. Si te ha pasado que al ejecutar tu comando ssh -i la terminal se congela por completo, en esta guía te muestro paso a paso cómo diagnosticamos y solucionamos este problema definitivamente.

1. El Síntoma: SSH congelado

El problema inicial comenzó al intentar conectar a la Raspberry Pi con el siguiente comando, el cual se quedaba colgado indefinidamente:

ssh -i ~/.ssh/id_ed25519_rpi pi@mi-raspberry.local

2. El Diagnóstico con el Modo Verboso

Para averiguar qué estaba pasando, activamos el modo de depuración máxima añadiendo la opción -vvv:

ssh -vvv -i ~/.ssh/id_ed25519_rpi pi@mi-raspberry.local

El registro de la terminal mostró que la red funcionaba y el servidor aceptaba la llave, pero se colgaba exactamente en este punto:

debug1: Server accepts key: rpi-sync ED25519 SHA256:...
debug3: sign_and_send_pubkey: signing using ssh-ed25519...

Esto nos indicó que el agente SSH local (ssh-agent) se había quedado colgado o corrupto en segundo plano al intentar firmar digitalmente el desafío de autenticación.

3. La Solución: Matar el proceso y reiniciar el Agente

Para solucionar el bloqueo de raíz, tuvimos que limpiar las llaves conflictivas de la memoria y reiniciar el proceso del agente SSH en la máquina local ejecutando estos comandos:

# Vacía todas las llaves cargadas en el agente corrupto
ssh-add -D

# Mata el proceso anterior e inicia una nueva instancia limpia del agente
eval "$(ssh-agent -s)"

Para verificar la conexión de forma inmediata sin interferencias del agente antiguo, también se puede forzar temporalmente a SSH a leer el archivo físico de la llave ignorando el agente con el parámetro IdentitiesOnly=yes:

ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519_rpi pi@mi-raspberry.local

4. Automatización con el archivo SSH Config

Escribir un comando tan largo cada vez es molesto. Para solucionarlo de forma permanente y evitar que el agente vuelva a intentar usar llaves incorrectas, editamos el archivo de configuración SSH de nuestro usuario:

nano ~/.ssh/config

Añadimos el siguiente bloque para crear un alias y automatizar los parámetros correctos:

Host rpi-servidor
    HostName mi-raspberry.local
    User pi
    IdentityFile ~/.ssh/id_ed25519_rpi
    IdentitiesOnly yes
    PubkeyAuthentication yes

Para garantizar que el sistema respete este archivo por motivos de seguridad, ajustamos sus permisos:

chmod 600 ~/.ssh/config

¡Listo! Con esto, ahora podemos conectarnos a la Raspberry Pi usando simplemente un comando muy corto:

ssh rpi-servidor

5. Paso Final: Eliminar o Gestionar la Contraseña de la Llave

Al simplificar el comando, el sistema comenzó a solicitar la frase de paso (passphrase) local de la llave: Enter passphrase for key....

Si prefieres una conexión 100% directa y automática sin introducir contraseñas, puedes remover la protección de la clave privada con el siguiente comando (dejando la nueva contraseña en blanco cuando lo solicite):

ssh-keygen -p -f ~/.ssh/id_ed25519_rpi

¡Y eso es todo! Ahora la conexión es instantánea, segura y súper cómoda gracias a que limpiamos el agente corrupto y estructuramos el archivo de configuración.