"Después del juego es antes del juego"
Sepp Herberger

jueves, 1 de diciembre de 2022

Interruptor casero USB.

Vamos a ver como construir un interruptor casero que se conecta por USB y que al pulsarse permite lanzar un evento en el ordenador, ejecutando un script.

Lo primero es construir el interruptor: ¿que usar si no tenemos ni idea de electrónica?. Pues no hace falta nada especial ya que con un ratón de ordenador es suficiente. Todos tenemos ratones USB rotos o antiguos que podemos reciclar. La idea es desmontar el ratón, sacar la placa, arrancar la luz led y verificar que el botón central (el asociado al click de la rueda) funciona y manda señal por el cable USB. Da igual el estado del resto de mecanismos.

Cogemos el ratón, lo metemos dentro de una cajita del tamaño adecuado y lo pegamos usando la pistola térmica de silicona que tenemos todos para las manualidades. En mi caso tenía una cajita que venía perfecta:
Nótese como buscamos que el interruptor del botón quede justo en el centro (marcado con el círculo amarillo). Luego he puesto una tapa de plástico agujereada para permitir llegar al interruptor y forrada con goma eva. Por último hago un interruptor externo con un tapón y un poco de espuma de embalaje. La idea es que el interruptor externo presione al interruptor interno del ratón.
Una vez pegado y montado todo:
Creo que es resultón para lo que yo quiero, pero si queremos hacerlo mas formal siempre podemos usar la impresora 3D para generar una cajita y botón con aspecto mas profesional.

Ya tenemos el hardware, vamos al software. Pinchamos el cable en un puerto USB y el Linux lo detecta como un ratón, pero como esta casi todo inutilizado tan solo recibirá eventos del botón central. Lo primero es encontrar el generador de eventos asociado al nuevo ratón:
# ls -l /dev/input/by-id
total 0
lrwxrwxrwx 1 root root  9 oct 27 09:34 usb-0461_USB_Optical_Mouse-event-mouse -> ../event2
lrwxrwxrwx 1 root root  9 oct 27 09:34 usb-0461_USB_Optical_Mouse-mouse -> ../mouse0
lrwxrwxrwx 1 root root  9 oct 27 09:34 usb-CHICONY_HP_Basic_USB_Keyboard-event-kbd -> ../event3
lrwxrwxrwx 1 root root 10 nov 29 13:32 usb-Logitech_USB-PS_2_Optical_Mouse-event-mouse -> ../event14
lrwxrwxrwx 1 root root  9 nov 29 13:32 usb-Logitech_USB-PS_2_Optical_Mouse-mouse -> ../mouse1
En nuestro caso sería /dev/input/event14. El paso siguiente es verificar que se detectan los eventos de pulsación. Para ello usamos triggerhappy:
# apt-get install triggerhappy
# thd --dump /dev/input/event14
Y pulsamos varias veces el interruptor para ver si se detecta. En consola debería mostrarse:
EV_KEY	BTN_MIDDLE	1	/dev/input/event14
# BTN_MIDDLE	1	command
EV_KEY	BTN_MIDDLE	0	/dev/input/event14
# BTN_MIDDLE	0	command
EV_KEY	BTN_MIDDLE	1	/dev/input/event14
# BTN_MIDDLE	1	command
thd --dump /dev/input/event14
EV_KEY	BTN_MIDDLE	0	/dev/input/event14
# BTN_MIDDLE	0	command
Perfecto: el evento generado por la pulsación del botón es "BTN_MIDDLE 1". Conviene recalcar en este momento que la pulsación del botón central del ratón puede ser también interceptado por nuestro entorno de escritorio Linux y provocar algún efecto asociado (por ejemplo, pegar el texto que hay en el portapapeles). Para evitar efectos colaterales recomendamos desactivar ese ratón en la configuración del entorno de escritorio:

Una vez tenemos el evento localizado, creamos la configuración que asocia dicho evento al lanzamiento de un script:
# cat /etc/triggerhappy/triggers.d/redbutton.conf
BTN_MIDDLE    1       /root/scripts/redbutton.sh
Después de este cambio de configuración se debe reiniciar el servicio triggerhappy, pero antes debemos configurarlo para que se ejecute como root (normalmente lo hace como nobody) y escuche solo los eventos que vengan de /dev/input/event14.

Inocente de mi, probé a modificar tanto /etc/default/triggerhappy como /etc/init.d/triggerhappy sin éxito. Seguia ejecutándose con el usario nobody y escuchando en /dev/input/event*. Esto lo podemos verificar haciendo:
# ps aux | grep thd
nobody   12523  0.1  0.0  43844  2852 ?        Ss   21:32   0:00 /usr/sbin/thd --triggers /etc/triggerhappy/triggers.d/ --socket /run/thd.socket --user nobody --deviceglob /dev/input/event*
La causa de esto es que en Ubuntu 18 el demonio triggerhappy se lanza realmente desde /lib/systemd/system/triggerhappy.service. Los otros dos ficheros están de adorno. No entiendo esta manía de tener servicios que están init.d y en systemd a la vez, es como si hubiesen quedado el trabajo a medias y se hubiesen ido de cañas.

Editamos /lib/systemd/system/triggerhappy.service y lo quedamos:
[Unit]
Description=triggerhappy global hotkey daemon
After=local-fs.target

[Service]
Type=notify
ExecStart=/usr/sbin/thd --triggers /etc/triggerhappy/triggers.d/ --socket /run/thd.socket --user root --deviceglob /dev/input/event14

[Install]
WantedBy=multi-user.target
Luego reiniciamos el servicio:
# service triggerhappy restart
Y bueno ahora nos falta escribir el script. Aqui podemos poner cualquier cosa, yo simplemente voy a hacer que se oiga un audio (descargado de Internet o generado con pico2wave) en el escritorio:
# cat /root/scripts/redbutton.sh 
#!/bin/bash

#Subimos el volumen al máximo en el alsamixer
amixer set Master unmute
amixer set Master 100%

#Si hay un usuario logado, conectamos con su pulseaudio para subir el volumen al máximo
user=$(who | grep "(:0)" | head -1 | cut -f1 -d" "); 
if  [ -n "$user" ]
then
  su $user -c "DISPLAY=:0 pactl set-sink-volume 0 150%"
  su $user -c "DISPLAY=:0 pactl set-sink-mute 0 0"
  cp -f /root/scripts/no.wav /tmp/no.wav
  su $user -c  "DISPLAY=:0 aplay /tmp/no.wav"
else
  cp -f /root/scripts/no.wav /tmp/no.wav
  DISPLAY=:0 aplay /tmp/no.wav
fi

exit 0
Con esto ya tenemos todo funcionando. Bien, y ahora la pregunta: ¿Para qué carajos quiero esto?. Bueno, pues aparte de para enredar, para conectarlo a una Raspberry Pi o un OpenWRT sin teclado/ratón y poder lanzar eventos sobre ellos: apagar/encender la wifi, hacer una foto con la webcam, reiniciar un servicio o una aplicación, etc.

En mi caso tengo una Rasbperry Pi mostrando una página web en modo kiosko con información en tiempo real. A veces el navegador se bloquea y hay que cerrarlo y abrirlo de nuevo, teniendo que conectarme por VNC y hacer el proceso a mano. Con un botón de este tipo puedo lanzar un script que permite a cualquiera reiniciar el navegador en todo momento.

Out!

Directorio home de usuarios + nfs4: lentitud en el escritorio.

Una de las cosas que mas me gustan de Linux en un entorno de red es la capacidad de que los homes de los usuarios estén centralizados en un servidor de red común, de tal forma que siempre tenemos el mismo escritorio independientemente de la máquina usada. Esto facilita al usuario trabajar sin tener que andar subiendo ficheros a una nube o carpeta concreta de red, y a nosotros hacer copias de seguridad de sus datos y no preocuparnos de recuperar datos del usuario cuando falle físicamente el disco del equipo donde ha estado trabajando.

En nuestro caso siempre hemos usado NFS para montar estos homes, aunque hay mas alternativas. Nunca había habido problema pero cuando cambiamos hace unos años a usar Ubuntu 18 empezaron a aparecer problemas aleatorios de lentitud extrema en los escritorios/navegadores web. Una explicación común es que el aumento de complejidad de los navegadores en los últimos años (y eso es algo de lo que habrá que hablar algún día martillo en mano) los ha convertido en unos artefactos que con sus operaciones de entrada/salida acaban saturando el servidor NFS. Una pista en contra de esta hipótesis es que la lentitud va y viene sin correlación aparente con el número de usuarios instantáneos en la red del centro y que cuando una máquina va lenta, la de al lado no tiene por qué hacer lo mismo. Tenía que haber alguna explicación adicional.

Después de muchas pruebas hemos establecido que cambiar el sistema de montaje de los homes de los clientes de nfs4 a nfs3 mejora enormemente el problema, haciéndolo desaparecer en muchos casos. Vamos a ver las pruebas a realizar cuando tenemos un escritorio/navegador ralentizado para determinar si este cambio en el nfs solucionaría el problema.

Las pruebas que podemos realizar son las siguientes:
  • Entrar por ssh como root a un puesto donde el escritorio vaya lento y hacer el comando "time su <usuario>", siendo "usuario" un usuario que monta su home por NFS, claro está. Hacer lo mismo en un equipo no afectado por el problema. Si en el primero tarda 5 o mas veces que el segundo es un síntoma de que está afectado.
  • Entrar por ssh como root a un puesto donde el escritorio vaya lento y hacer "wget https://speed.hetzner.de/1GB.bin". Hacer lo mismo en un equipo no afectado por el problema. Es un fichero de prueba de 1Gb para hacer tests de velocidad desde consola. Si la velocidad es similar en ambos puestos podemos descartar que sea un problema de red (bucles de red, problemas de cableado, de switchs, de salida a Internet) y centrarnos en que es un problema de NFS.
  • Entrar por ssh como root a un puesto donde el escritorio vaya lento y mirar en el syslog buscando errores como:
    NFS: nfs4_reclaim_open_state: Lock reclaim failed!
    NFS: nfs4_reclaim_open_state: unhandled error -10026
    nfs4_reclaim_open_state: 3 callbacks suppressed
        
    Estos errores son síntomas de bloqueos y otros problemas en el montaje NFS.
  • Entrar en el servidor NFS y testear la carga con los comandos:
    # atop
    # iotop
    # nfsstat
      
    Buscando sobrecargas en el disco, red o en los procesos nfs.
  • Entrar por ssh como root a un puesto donde el escritorio vaya lento y hacer
    # nfsiostat
      
    Comparar el resultado con un equipo no afectado por el problema.
Después de todas estas pruebas, si sospechamos que las causas de la lentitud están relacionadas con el servidor NFS, el siguiente paso es verificar que tipo de montaje usamos en nuestros puestos. Para ello entramos por ssh como root en un equipo de usario y hacemos:
# automount -m

global options: none configured

  Mount point: /home

  source(s):

   type: ldap
   map: ldap:ou=auto.home,ou=Automount,dc=instituto,dc=extremadura,dc=es
   ....
   ....
   * | -fstype=nfs4,rw,hard,intr,nodev,nosuid,nolock,rsize=16384,wsize=16384 servidor:/&
La última línea nos dice que el montaje del home esta siendo realizado mediante nfs4. No tiene porque ser igual a la indicada, pero el "nfs4" es revelador. La idea es cambiarla por:
   * | -fstype=nfs,rw,fg,hard,intr,nodev,nosuid,async,ac,vers=3,fsc servidor:/home/&
que cambia el montaje del home para que se haga usando nfs3. Esta línea si que debemos ponerla de forma literal, tal cual aparece aquí.

El lugar donde se hace este cambio dependerá de donde configuremos el montaje en nuestro entorno. Para el caso de nuestros centros esto se hace en el directorio ldap, al que accedemos mediante phpldapadmin en el nodo:
cn=/,ou=auto.home,ou=Automount,dc=instituto,dc=extremadura,dc=es
Una vez allí localizamos el atributo "automountInformation", hacemos una copia de su contenido por si las moscas y lo sustitumos por:
* | -fstype=nfs,rw,fg,hard,intr,nodev,nosuid,async,ac,vers=3,fsc servidor:/home/&
Después de esto recargamos el servicio nfs en el servidor principal:
/etc/init.d/nfs-kernel-server reload
Y por último reiniciamos los clientes, dejando que trabajen durante varios días a ver si desaparecen los problemas. En bastantes casos con este sencillo cambio ha sido suficiente.