Saltar a contenido

Raspberry Pi

Enlaces

Distribuciones

Software

  • Pi-Hole: DNS que filtra dominios marcados por la comunidad como "molestos" y conseguiremos una navegación mas limpia y rápida.
  • PiVPN

Hardware

Comandos útiles

Comprobar asignaciones de cliente No-IP

Las asignaciones dejan marca en el log syslog:

1
2
3
4
5
6
7
edumoreno@raspi-git /var/log $ sudo fgrep noip syslog
Oct 16 12:18:57 raspi-git noip2[2165]: v2.1.9 daemon ended.
Oct 16 12:19:19 raspi-git noip2[2186]: v2.1.9 daemon started with NAT enabled
Oct 16 12:19:35 raspi-git noip2[2186]: eduardofilo.no-ip.biz set to 88.19.216.95
Oct 16 12:53:06 raspi-git noip2[2186]: v2.1.9 daemon ended.
Oct 16 13:15:23 raspi-git noip2[2217]: v2.1.9 daemon started with NAT enabled
Oct 16 13:15:25 raspi-git noip2[2217]: eduardofilo.no-ip.biz was already set to 88.19.216.95.

Utilidad de configuración

1
$ sudo raspi-config

Backup de la SD (comprimiendo al vuelo)

Los siguientes comandos se ejecutan con dcfldd, pero es equivalente al tradicional dd.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ #Backup:
$ sudo dcfldd if=/dev/mmcblk0 bs=2M | pv | gzip -9 - > Rpi_8gb_backup.img.gz
$ #Backup sólo de 4GB (si por ejemplo la tarjeta es más grande pero no aprovecha toda la superficie)
$ sudo dcfldd if=/dev/mmcblk0 bs=2M count=2048 | pv -s 4g | gzip -9 - > Rpi_4gb_backup.img.gz
$ #Restauración (comprimido con gzip):
$ gunzip Rpi_8gb_backup.img.gz -c | pv | sudo dcfldd of=/dev/mmcblk0 bs=2M
$ #Restauración (comprimido con xz):
$ xzcat Rpi_8gb_backup.img.xz | pv | sudo dcfldd of=/dev/mmcblk0 bs=2M
$ #Restauración (comprimido con zip):
$ unzip -p Rpi_8gb_backup.zip | pv | sudo dcfldd of=/dev/mmcblk0 bs=2M

Para hacer un backup parcial los cálculos se harían así. Primero sacamos los datos de la estructura de la tarjeta con fdisk:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ sudo fdisk -l /dev/mmcblk0
Disco /dev/mmcblk0: 14,4 GiB, 15502147584 bytes, 30277632 sectores
Unidades: sectores de 1 * 512 = 512 bytes
Tamaño de sector (lógico/físico): 512 bytes / 512 bytes
Tamaño de E/S (mínimo/óptimo): 512 bytes / 512 bytes
Tipo de etiqueta de disco: dos
Identificador del disco: 0xa125a0dc

Dispositivo    Inicio Comienzo    Final Sectores Tamaño Id Tipo
/dev/mmcblk0p1            8192    96663    88472  43,2M  c W95 FAT32 (LBA)
/dev/mmcblk0p2           98304 15550463 15452160   7,4G 83 Linux

Aquí vemos que cada sector ocupa 512 bytes. Nos fijamos en el último sector utilizado que en este caso es 15550463. Multiplicando este sector por el tamaño del sector (y sumando 1 al número de sectores por si empiezan a contar en 0) obtendremos el número de bytes que tendremos que copiar. Como el block size que vamos a utilizar es 2MB tendremos que truncar por lo alto (también servirá de medida de seguidad). Los cálculos en este caso resultarían:

1
(15550463 + 1) (sector) * 512 (Byte/sector) / 1024 (Byte/KB) / 1024 (KB/MB) / 2 (MB/bloque) = 3796,5 bloques

Por tanto en este caso copiaremos 3797 bloques para cubrir esos 15550464 sectores.

Backup de la SD (comprimiendo al vuelo con gzip y diviendo en trozos el fichero resultante)

1
2
3
4
$ #Backup:
$ sudo dcfldd if=/dev/mmcblk0 bs=2M | pv | gzip -9 - | split --bytes=2G - Rpi_8gb_backup.img.gz.part_
$ #Restauración:
$ cat Rpi_8gb_backup.img.gz.part_* | gunzip -c | pv | sudo dcfldd of=/dev/mmcblk0 bs=2M

Backup de la SD (comprimiendo al vuelo con 7z y diviendo en trozos el fichero resultante)

1
2
3
4
$ #Backup:
$ sudo dcfldd if=/dev/mmcblk0 bs=2M count=7350 | 7z -si -v1400m a rg350_es.img.7z
$ #Restauración:
$ 7z e -so rg350_es.7z.001 | sudo dcfldd of=/dev/mmcblk0 bs=2M

Control de progreso durante flasheo

1
$ sudo pkill -USR1 -n -x dd

Como alternativa se puede instalar el comando dcfldd para sustituir a dd, con lo que obtendremos una indicación del progreso de la copia. dcfldd informa cada 256 bloques escritos por defecto. Para que lo haga con más frecuencia hay que pasarle la opción statusinterval de esta forma:

1
2
$ #Backup:
$ sudo dcfldd statusinterval=10 if=/dev/mmcblk0 bs=2M | gzip -9 - > Rpi_8gb_backup.img.gz

Redimensionar particiones en imagen

Fuente: Apartado Resizing a partition within an image file en Shrinking Raspberry Pi SD Card Images.

  1. Obtenemos los parámetros de las particiones de la imagen:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    $ sudo fdisk -l Octoprint_niubit.img
    Disco Octoprint_niubit.img: 7,5 GiB, 8010072064 bytes, 15644672 sectores
    Unidades: sectores de 1 * 512 = 512 bytes
    Tamaño de sector (lógico/físico): 512 bytes / 512 bytes
    Tamaño de E/S (mínimo/óptimo): 512 bytes / 512 bytes
    Tipo de etiqueta de disco: dos
    Identificador del disco: 0x15f1d664
    
    Dispositivo           Inicio Comienzo    Final Sectores Tamaño Id Tipo
    Octoprint_niubit.img1            8192    98045    89854  43,9M  c W95 FAT32 (LBA)
    Octoprint_niubit.img2           98304 15644671 15546368   7,4G 83 Linux
    
  2. Localizamos el primer dispositivo loop libre:

    1
    $ ls -l /dev/loop*
    
  3. Conectamos la partición que queremos redimensionar con el primer dispositivo loop libre aplicando un offset en base al sector de comienzo de la partición que queremos encoger (98304 en este ejemplo):

    1
    $ sudo losetup /dev/loop12 Octoprint_niubit.img -o $((98304*512))
    
  4. Montamos la partición en el sistema de archivos para hacer limpieza (por ejemplo /var/cache/apt/archives) y desmontamos al final.

  5. Editamos la partición con gparted y la encogemos todo lo posible:

    1
    $ sudo gparted /dev/loop12
    
  6. Aunque hemos encogido la partición, en la tabla de asignación de la imagen continuará con el antiguo tamaño, motivo por el que gparted muestra un icono de aviso. Lo solucionaremos a continuación. Tomamos nota del tamaño final en KB que se ha dado a la partición fijándonos en el comando resize2fs que gparted ha ejecutado mirando los detalles al finalizar la operación anterior. Por ejemplo:

    1
    resize2fs -p '/dev/loop12' 3250176K
    
  7. Eliminar el dispositivo loop que hemos estado utilizando:

    1
    $ sudo losetup -d /dev/loop12
    
  8. Conectar ahora la imagen completa de nuevo al dispositivo loop:

    1
    $ sudo losetup /dev/loop12 Octoprint_niubit.img
    
  9. Editamos con fdisk la imagen:

    1
    sudo fdisk /dev/loop12
    
  10. Borramos la partición que hemos redimensionado pulsando d 2.

  11. Creamos de nuevo la partición pulsando n p 2. Nos pedirá el primer sector. Introduciremos el obtenido en el paso 1 (98304 en este ejemplo). A continuación nos pedirá el tamaño. Introduciremos el obtenido en el paso 6 con un + delante (+3250176K en este ejemplo). Si nos pregunta en ese momento ¿Desea eliminar la firma? respondemos No. Finalmente pulsamos w para registrar los cambios.
  12. Volvemos a obtener los parámetros de las particiones de la imagen:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    $ sudo fdisk -l Octoprint_niubit.img
    Disco Octoprint_niubit.img: 7,5 GiB, 8010072064 bytes, 15644672 sectores
    Unidades: sectores de 1 * 512 = 512 bytes
    Tamaño de sector (lógico/físico): 512 bytes / 512 bytes
    Tamaño de E/S (mínimo/óptimo): 512 bytes / 512 bytes
    Tipo de etiqueta de disco: dos
    Identificador del disco: 0x15f1d664
    
    Dispositivo           Inicio Comienzo   Final Sectores Tamaño Id Tipo
    Octoprint_niubit.img1            8192   98045    89854  43,9M  c W95 FAT32 (LBA)
    Octoprint_niubit.img2           98304 6598655  6500352   3,1G 83 Linux
    
  13. Tomamos nota del sector final de la segunda partición (6598655 en este ejemplo).

  14. Eliminamos el dispositivo loop que hemos utilizado:

    1
    $ sudo losetup -d /dev/loop12
    
  15. Truncamos la imagen para retirar la parte que ya no está cubierta por la partición que hemos encogido:

    1
    $ truncate -s $(((6598655+1)*512)) Octoprint_niubit.img
    
  16. Ya habríamos terminado, pero todavía se puede mejorar la imagen rellenando con ceros los sectores no utilizados. Para ello proceder como sigue (sustituyendo el sector de comienzo 98304 del ejemplo por el que corresponda):

    1
    2
    3
    4
    5
    6
    7
    8
    $ sudo losetup /dev/loop12 Octoprint_niubit.img -o $((98304*512))
    $ sudo mkdir -p /mnt/imageroot
    $ sudo mount /dev/loop12 /mnt/imageroot
    $ sudo dcfldd if=/dev/zero of=/mnt/imageroot/zero.txt
    $ sudo rm /mnt/imageroot/zero.txt
    $ sudo umount /mnt/imageroot
    $ sudo rmdir /mnt/imageroot
    $ sudo losetup -d /dev/loop12
    

Ya tenemos lista la imagen para poderla flashear sobre tarjetas. Si la comprimimos con gzip se comprimirá mejor si hemos realizado el paso final.

Existen estas dos utilidades para automatizar este proceso:

Gestión de la SWAP

Para redimensionar la Swap predeterminada (fichero de 100MB en /var/swap):

1
2
3
$ sudo nano /etc/dphys-swapfile
$ sudo dphys-swapfile setup
$ sudo dphys-swapfile swapon

Para consultar el estado de la swap:

1
$ swapon -s

Para dejar de usar swap:

1
$ sudo swapoff -a

Para activar la swap tal y como está definida en ''/etc/fstab'':

1
$ sudo swapon -a

Para activar swap con un fichero en concreto:

1
$ sudo swapon /var/swap

Escaneo de Raspberry Pi's en red

1
2
$ arp -a | grep b8:27:eb
$ sudo nmap -PR -sP 192.168.1.0/24 | fgrep -B 2 "Raspberry"

Pulsador encendido/apagado

Existe una configuración accesible mediante un Device Tree overlay que permite arrancar y parar el sistema controladamente con un pulsador entre los pines #5 (GPIO03 o SCL) y GND. Para que funcione hay que añadir lo siguiente al fichero /boot/config.txt:

1
dtoverlay=gpio-shutdown

Aquí se documenta en profundidad.

Pi-top

Enlaces

Artículos interesantes de TheMagPi

  • Librería Python para controlar un puerto USB: Página 14 de #3 de TheMagPi
  • Buffer de dispositivos controlados con el GPIO de RPi: Página 19 de #4 de TheMagPi
  • Librería wiringPi: Sirve para comandar y leer el GPIO desde bash. Página 14 de #6 de TheMagPi
  • Comunicación entre RaspPi y Arduino: Página 4 de #7 de TheMagPi
  • Uso de interrupciones para chequear GPIO sin bucles: Página 12 de #7 de TheMagPi
  • Librería Nanpy para comunicar RaspPi y Arduino por USB: Página 10 de #8 de TheMagPi
  • WebIOPi - Framework REST para controlar el GPIO: Página 8 de #9 de TheMagPi

Ajustes primer arranque

Configuración headless

Activación de SSH

Crear un fichero vacío con nombre ssh en partición boot.

Conexión a punto de acceso Wifi

Crear un fichero con nombre wpa_supplicant.conf en partición boot con el siguiente contenido:

1
2
3
4
5
6
7
8
9
country=ES
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    ssid="<el_ssid>"
    psk="<el_pwd>"
    key_mgmt=WPA-PSK
}

IP estática

Primero averiguamos el nombre del interfaz al que queremos poner la IP estática consultando ifconfig. Luego editamos /etc/dhcpcd.conf y al final añadimos:

1
2
3
4
interface <nombre_interfaz>
static ip_address=<ip>/24
static routers=<gateway>
static domain_name_servers=<dns separadas por espacios>

raspi-config

  • Network Options > Hostname
  • Boot Options > Wait for Network at Boot
  • Localisation Options > Change Locale
  • Localisation Options > Change Timezone

Ajustes usuario

  • Crear una nueva cuenta:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    $ sudo adduser usuario
    $ sudo adduser usuario adm
    $ sudo adduser usuario dialout
    $ sudo adduser usuario cdrom
    $ sudo adduser usuario sudo
    $ sudo adduser usuario audio
    $ sudo adduser usuario video
    $ sudo adduser usuario plugdev
    $ sudo adduser usuario games
    $ sudo adduser usuario users
    $ sudo adduser usuario input
    $ sudo adduser usuario netdev
    $ sudo adduser usuario gpio
    $ sudo adduser usuario i2c
    $ sudo adduser usuario spi
    
  • Cambiar UID de usuario edumoreno para que coincida con el del NAS:

    1
    sudo usermod -u 1002 usuario
    
  • Borrar la cuenta pi desde la nueva:

    1
    $ sudo deluser -remove-home pi
    
  • Copia de clave pública para SSH automático (desde máquina host):

    1
    $ ssh-copy-id -i ~/.ssh/id_rsa.pub usuario@IP_RASPBERRY
    

Instalación de paquetes

  • Instalar paquetes:
    • fail2ban
    • nfs-common
    • transmission-daemon
    • amule-daemon
  • Desinstalar paquete wolfram-engine que ocupa mucho y no se suele usar (en la versión lite no viene).

Montaje NAS

Añadir lo siguiente a /etc/fstab:

1
192.168.1.200:/c/carpeta_compartida /home/usuario/carpeta_compartida nfs4 defaults,user,exec 0 0

SSH

Editar el fichero /etc/ssh/sshd_config y modificar/añadir las siguientes líneas (fuente):

1
2
3
4
PermitRootLogin no
MaxAuthTries 3
MaxStartups 5
AllowUsers edumoreno

Medidas de protección:

Raspad

Enlaces

Configuración

Sistema base

Raspbian

Digitalizador de pantalla

El equipo recién instalado lleva un firmware bastante deficiente en el digitalizador táctil de la pantalla. Hay que actualizarlo siguiendo los pasos del siguiente artículo del wiki de SunFounder: The touch screen does not work properly FAQ

Teclado en pantalla

Instalar el paquete: matchbox-keyboard

Clic secundario

Para conseguir emular el clic derecho del ratón procedemos como sigue (fuentes: 1 y 2):

  1. Instalamos los siguientes paquetes:
    1
    $ sudo apt-get update && sudo apt-get install build-essential libx11-dev libxtst-dev libxi-dev x11proto-randr-dev libxrandr-dev xserver-xorg-input-evdev xinput-calibrator
    
  2. Descargamos el código de twofing y lo extraemos:
    1
    2
    3
    $ wget http://plippo.de/dwl/twofing/twofing-0.1.2.tar.gz
    $ tar -xvzf twofing-0.1.2.tar.gz
    $ cd twofing-0.1.2
    
  3. Compilamos:
    1
    $ make && sudo make install
    
  4. Creamos el fichero /etc/udev/rules.d/70-touchscreen-ilitek.rules con el siguiente contenido:
    1
    2
    SUBSYSTEMS=="usb",ACTION=="add",KERNEL=="event*",ATTRS{idVendor}=="222a",ATTRS{idProduct}=="0001",SYMLINK+="twofingtouch",RUN+="/bin/chmod a+r /dev/twofingtouch"
    KERNEL=="event*",ATTRS{name}=="ILITEK Multi-Touch-V3000",SYMLINK+="twofingtouch",RUN+="/bin/chmod a+r /dev/twofingtouch"
    
  5. Creamos el fichero /usr/share/X11/xorg.conf.d/90-touchinput.conf con el siguiente contenido:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    Section "InputClass"
    Identifier "calibration"
    Driver "evdev"
    MatchProduct "ILITEK ILITEK-TP"
    MatchDevicePath "/dev/input/event*"
    Option "Emulate3Buttons" "True"
    Option "EmulateThirdButton" "1"
    Option "EmulateThirdButtonTimeout" "750"
    Option "EmulateThirdButtonMoveThreshold" "30"
    EndSection
    
  6. Creamos el fichero /etc/udev/rules.d/ 99-input-tagging.rules con el siguiente contenido:
    1
    ACTION=="add", KERNEL=="event*", SUBSYSTEM=="input", TAG+="systemd", , ENV{SYSTEMD_ALIAS}+="/sys/subsystem/input/devices/$env{ID_SERIAL}"
    
  7. Creamos el fichero ~/.config/autostart/twofing.desktop con el siguiente contenido:
    1
    2
    3
    4
    5
    [Desktop Entry]
    Type=Application
    Name=Twofing
    Exec=twofing
    StartupNotify=false
    

Raspi Camera

La documentación de la librería picamera en Python está aquí. Concretamente las recetas para hacer la foto están aquí.

Por ejemplo, para hacer fotos que luego vayan a formar parte de un timelapse:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import time
import picamera
import datetime as dt

with picamera.PiCamera() as camera:
    camera.resolution = (1280, 720)
    camera.framerate = 30
    # calentamiento/enfoque de la camara
    time.sleep(2)
    # fijamos valores para que salga mejor el timelapse
    camera.shutter_speed = camera.exposure_speed
    camera.exposure_mode = 'off'
    g = camera.awb_gains
    camera.awb_mode = 'off'
    camera.awb_gains = g
    camera.annotate_background = picamera.Color('black')
    camera.annotate_text = dt.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    filename = time.strftime("%Y-%m-%d_%H%M.jpg")
    camera.capture(filename)

Activar consola en puerto serie

Las Raspberry Pi Zero W, Pi 3 y Pi 4 traen un adaptador Bluetooth que en Raspbian está conectado precisamente a los pines #08 y #10 donde tradicionalmente se encontraba el puerto serie. En este documento se explican los cambios en estas versiones. En este otro artículo se dan opciones para modificar este comportamiento. Lo que sigue es una versión personal.

Para liberar esta conexión debemos editar el fichero config.txt que hay en la partición boot y añadir (al final por ejemplo) lo siguiente:

1
dtoverlay=pi3-disable-bt

Esto podemos hacerlo sin necesidad de arrancar el sistema, montando la microSD en el ordenador. Para el siguiente paso sí necesitamos arrancar el sistema de la tarjeta en la Raspberry. Una vez estemos en la consola (por SSH o conectando una pantalla/teclado/ratón de alguna manera), ejecutaremos:

sudo raspi-config

Allí acudiremos a la sección Interfacing options > Serial y responderemos de la siguiente forma a las dos preguntas que nos hará:

1
2
Would you like a login shell to be accessible over serial? -> Yes
Would you like the serial port hardware to be enabled? -> Yes

Reiniciaremos y ya podremos conectar a la consola a través del puerto serie.

Crankshaft

Actualización distribución

  1. Descargar la última versión de la página de descarga.
  2. Copiar el zip o mejor el contenido (.img y .md5) a la raíz de un pendrive con formato FAT32.
  3. Conectar el pendrive a la Raspberry antes de arrancar.
  4. El proceso de actualización (descrito en esta página) es lento y requiere varios reinicios. Esperar pues hasta terminar de ver el sistema correctamente arrancado.
  5. Instalar el script del Mausberry Car Switch:

    1. Copiar el siguiente script en la ruta /etc/switch.sh:

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      #!/bin/bash
      
      #this is the GPIO pin connected to the lead on switch labeled OUT
      GPIOpin1=23
      
      #this is the GPIO pin connected to the lead on switch labeled IN
      GPIOpin2=24
      
      #Enter the shutdown delay in minutes
      delay=0
      
      echo "$GPIOpin1" > /sys/class/gpio/export
      echo "in" > /sys/class/gpio/gpio$GPIOpin1/direction
      echo "$GPIOpin2" > /sys/class/gpio/export
      echo "out" > /sys/class/gpio/gpio$GPIOpin2/direction
      echo "1" > /sys/class/gpio/gpio$GPIOpin2/value
      let minute=$delay*60
      SD=0
      SS=0
      SS2=0
      while [ 1 = 1 ]; do
      power=$(cat /sys/class/gpio/gpio$GPIOpin1/value)
      uptime=$(</proc/uptime)
      uptime=${uptime%%.*}
      current=$uptime
      if [ $power = 1 ] && [ $SD = 0 ]
      then
      SD=1
      SS=${uptime%%.*}
      fi
      
      if [ $power = 1 ] && [ $SD = 1 ]
      then
      SS2=${uptime%%.*}
      fi
      
      if [ "$((uptime - SS))" -gt "$minute" ] && [ $SD = 1 ] && [ $power = 1 ]
      then
      poweroff
      SD=3
      fi
      
      if [ "$((uptime - SS2))" -gt 20 ] && [ $SD = 1 ]
      then
      SD=0
      fi
      
      sleep 1
      done
      
    2. Darle permisos de ejecución.

    3. Añadir lo siguiente al final del fichero /etc/rc.local (justo antes del exit 0) para que se ejecute en el arranque:

      1
      /etc/switch.sh &