Pantallas informativas (anexo 4): Añadir pantallas -explicado paso a paso-

A raíz de una consulta recibida y de algún problema encontrado a la hora de incorporar alguna pantalla nueva, creo que se hacía más que conveniente el detallar el proceso indicando los problemas que se podrían encontrar y cómo solucionarlos de la forma más fácil posible.

Básicamente lo que hay que hacer es lo que ponía en esta entrada:

Pantallas informativas (IX): Resumen, ajustes para añadir pantallas, cómo adaptar para otros usuarios y ficheros para descargar

Pero recientemente, al preparar una nueva Raspberry para incorporar otra pantalla y grabar una tarjeta con una imagen que se creó tiempo atrás, me topé con un problemilla que al principio me trajo de cabeza: La nueva Raspberry no se conectaba a la WiFi ni a tiros

El problema resultó ser de lo más tonto: La Raspberry no estaba en fecha, pero caer en ello me llevó más de un quebradero de cabeza, os lo aseguro. Son de estas estupideces que como no las veas a la primera te pueden hacer perder la fe en el Silicio. Es como no ver que te has dejado un punto y coma al final de una línea en PHP. Un dolor.

Lógicamente tenía la fecha de cuando se grabó aquella imagen, meses atrás, y como estaba configurada para conectarse directamente por Eduroam, pues esa variación en las fechas provocaba que el certificado fuera rechazado.

Además, ejecutar los scripts al inicio no ayuda demasiado a la hora de configurar el nuevo nombre, claves, etc. Así que lo que se debería hacer es lo siguiente:

Con vistas a incorporar nuevas pantallas, guardaremos previamente una imagen a la que antes hayamos comentado las líneas del crontab, para que al iniciar la nueva Raspberry se nos quede en el prompt sin ejecutar nada. Añadimos un # al principio de cada línea:

#@reboot sleep 10 && /home/pi/iniciando.sh > /dev/tty1; /home/pi/actualizadia.sh; /home/pi/actualiza.sh; /home/pi/fecha.sh &
#
#* 6 * * * /home/pi/actualizadia.sh &
#
#* 9 * * * /home/pi/fecha.sh &
#
#*/15 * * * * /home/pi/queip.sh &
#
#*/30 * * * * /home/pi/actualiza.sh &

Con eso, guardamos la imagen para clonar las siguientes Raspberrys y nos será más fácil trabajar con ellas.

Ahora sí, una vez grabada la tarjeta para la nueva raspberry, arrancamos y en el prompt escribimos startx para acceder al escritorio.

Cambio de nombre

Cambiar el nombre del host es de lo más simple ahora, podemos usar el apartado de configuración de la Raspberry:

La imagen puede diferir dependiendo de la versión de Raspbian que estemos usando

 

Luego, abrimos una ventana de terminal y seguimos por línea de comandos:

Fecha y hora

Primero la ponemos en fecha y hora. Vamos a suponer que la imagen es del año pasado, del 2018 y hoy estamos a 9 de diciembre de 2019 y son las 11:15 Pues

sudo date 120911152019

Es decir: sudo date mm dd  HH MM [cc] yy Que viene a ser sudo date mes, día, hora, minuto, dos primero dígitos del año (que son opcionales), dos segundos dígitos del año. Si fuera en el mismo año podríamos dejar de poner cc y yy

Creamos las nuevas claves

Las creamos tal como está indicado en la entrada correspondiente:

Pantallas informativas (I): Instalación SO y conexión SSH

Sustituimos la clave privada (dejamos el mismo nombre y comprobamos los permisos)

Si siguiendo con el ejemplo de la entrada hemos llamado al fichero “miclave” y está alojado en el subdirectorio .ssh del home, pues nombraremos al nuevo fichero igual y machacaremos el viejo.

Copiamos la clave pública al servidor y la añadimos al final del fichero authorized_keys

Copiamos la clave pública a nuestro home del servidor y vamos a seguir suponiendo que como en la entrada el nombre que le hemos puesto al fichero es “miclave.pub”

Ahora es recomendable sacar primero una copia del fichero authorized_keys por si acaso. Y después, para añadir la clave pública al final, sabiendo que estemos en el home del servidor, sería:

cat miclave.pub >> .ssh/authorized_keys

Una vez que tengamos preparado todo, comprobado que tenemos conexión a Internet (reiniciando si fuera preciso), nos conectamos manualmente al servidor usando las claves, tal como se indicaba en el apartado en que se trató este tema cuyo link está un poco más arriba.

ssh -i /home/pi/.ssh/miclave [email protected]_del_servidor

Posiblemente nos pida confirmación en esta primera ocasión, así que lo aceptamos y en cuanto veamos que estamos conectados ya podemos cerrar. Ya está.

Descomentamos las líneas del crontab

Editamos con crontab –e y quitamos los comentarios a las líneas para que al arrancar y cada x tiempo se ejecuten los scripts tal como queremos.

Y listo. Eso es todo.

En realidad es casi más extenso de explicar que de hacer, porque realmente son cuatro cosas que se hacen en un momento si tenemos todo bien preparado.

Pantallas informativas (anexo 3): Programar fecha de inicio de reproducción de archivos

Mira que lo pensé: “Tendría que poner un algo para poder subir ficheros y que se comenzaran a reproducir a partir de una fecha…” Pero dije “Bah, para lo que se va a usar esa función…”

Pues en efecto, se usa poco, pero algo sí, y es una auténtica lata el tener que andar con posit pegados por el monitor para acordarnos de cuándo subir uno u otro archivo por no escribir cuatro líneas de código. Así que: al tajo. Vamos a escribir esas cuatro líneas y así el próximo archivo que tengamos que programar una fecha concreta de visualización será dentro de un lustro y ya ni nos acordaremos (vamos, es lo que pasa siempre, pero no escribas esas líneas y cada semana tendrás un archivo de esos. Dichoso Murphy…).

Esto lo vamos a hacer en el servidor, ya sabéis, en nuestro caso el cacharro ese que sacamos de la basura y que sigue funcionando 24/7 con Ubuntu tan campante, y que así siga ad aeternum.

En el Home de Pi, donde tenemos su carpeta datos y las subcarpetas dias y pantallas, meteremos una tercera subcarpeta: programa. En esa carpeta meteremos los archivos que se tengan que reproducir a partir de una determinada fecha.

La fecha de inicio de reproducción de los archivos la incluiremos en el nombre del archivo, al final, después de la extensión en formato YYYYMMDD al que ya estamos acostumbrados. Crontab ejecutará un sencillo script que comparará los últimos 8 caracteres del nombre del archivo con la fecha actual, y si coinciden moverá dicho archivo a la carpeta pantallas eliminando esos caracteres. ¡Fácil!

Así pues, si queremos anunciar que se abre un plazo de inscripciones, digamos, el 15 de marzo de 2021 y el archivo se llama “inscripcurso.jpg”, pues lo subiríamos a la carpeta programa con el nombre inscripcurso.jpg20210315 y nos podemos olvidar de él sin necesidad de tener año y medio un posit colgando del monitor.

Vale, pues ahora que ya hemos definido el método, escribimos el script:

Como se puede ver es muy simple, ocupan más espacio los comentarios que el código.

En modo copy&paste:

#!/bin/bash
#Comprobamos la fecha actual y la metemos en variable hoy
hoy=$(date +%Y%m%d)
#Comprobamos los ficheros que puede haber en la carpeta programa
for file in /home/pi/datos/programa/*
do
#Sacamos su nombre y lo metemos en variable
	filename=$(basename $file)
#Extraemos los 8 últimos caracteres, que tienen que comprender la fecha
	fechaprog=${filename: -8}
#Comparamos si las fechas son iguales
	if [ $fechaprog = $hoy ]
		then
#Si lo son, preparamos el nuevo nombre al fichero, eliminando la fecha de programación
#Y movemos el fichero a la carpeta "pantallas" con el nombre nuevo
			nuevonombre=${filename::-8}
			mv $file /home/pi/datos/pantallas/$nuevonombre
	fi
done

Nombramos el archivo con el nombre que queramos, por ejemplo “programafecha.sh”, lo ubicamos en nuestro /home/pi en el servidor y le damos permisos de ejecución

Vale. Ahora lo único que hay que hacer es programar crontab para que lo ejecute por la noche, eso sí, pasadas las doce, y así a la mañana del día en cuestión se comenzará a proyectar. Vamos a ponerle que ejecute el script a las 2 am, así que con la instrucción crontab -e añadimos la siguiente línea:

* 2 * * * /home/pi/programafecha.sh &

Listo, eso es todo. Y como hemos visto, todo en el servidor. Esta vez no ha hecho falta tocar las Raspberry para nada.

 

Pantallas informativas (anexo 2): No reproducir un archivo

Más cosicas que van saliendo: En este caso se trata de que una pantalla no reproduzca un determinado archivo.

Habíamos preparado el script proyecta.sh para que una determinada pantalla pudiera reproducir un determinado archivo, pero no al revés. De eso se trata ahora, de que todas pantallas reproduzcan un archivo, menos una. Esto, por ejemplo, puede permitir que una pantalla reproduzca un vídeo con sonido mientras que el resto lo hagan en silencio ¿cómo? Pues creando dos archivos: al de audio le diríamos que sólo lo reprodujera la pantalla en la que queremos sonido y subiríamos otro archivo idéntico, sin la opción AAA y con esta opción que vamos a implementar.

La forma de hacerlo no puede ser más simple, casi alcanza la categoría de “chorrada”. Vamos a modificar el script proyecta.sh añadiendo las siguientes líneas, así:

Vamos, que lo que hemos hecho ha sido coger las líneas que ya teníamos para que sólo reprodujera una pantalla y justo debajo colocar estas, cambiando las X por Z y la comparación pues de distinto (!=) a igual (=). No hay más misterio, no obstante va una captura un poco más amplia:

Vemos aquí las dos opciones: Con XXX más el nombre de la pantalla el archivo el archivo se reproduce (recordamos que el if lo que hace es lo contrario: “con XXX si no está el nombre de la pantalla no hagas nada”; y con ZZZ más el nombre de la pantalla no se reproduce (aquí el if hace justamente eso: con ZZZ si está el nombre de la pantalla, no hagas nada)

A partir de ahora tenemos que:

Si un archivo comienza por XXX seguido del nombre de la pantalla, ese archivo sólo se reproduce en esa pantalla.

Si un archivo comienza por ZZZ seguido del nombre de la pantalla, ese archivo es ignorado por dicha pantalla y no se reproduce.

¡Molto facile e divertente!

Pues hala, hasta la próxima ocurrencia 🙂

Pantallas informativas (anexo 1): Caducidad de ficheros

Hay detalles en los que uno no repara en la fase de diseño pero que luego echa en falta cuando tiene la aplicación, o lo que sea, en marcha. Como comentaba al final de la última entrada relativa al proyecto de las pantallitas, aquí echábamos de menos un control sobre la fecha de caducidad de los ficheros. Afortunadamente tenemos múltiples formas de solucionar esto, desde las elegantes: con un formulario, haciendo uso de Apache, PHP, MariaDB, etc; hasta la fácil y churrutera que he elegido: modificando el nombre de archivo.

Modificando el nombre de archivo podemos seguir trabajando como hasta ahora, subimos un archivo con un determinado nombre y el sistema hace el resto. Ahora bien, se trataba de no perder el resto de funcionalidades: archivos que van a una sola pantalla, sonido, etc.

También esto se puede hacer de varias formas, pero por la que me he decantado es añadiendo un punto y la fecha antes de la extensión, quedando más o menos así:

[opción]nombre_archivo[opción].ext >> [opción]nombre_archivo[opción].fecha.ext

Y siempre justo antes de la extensión pongamos o no opciones de especificar pantalla o audio.

La fecha que habremos de poner será la del evento o del último día del mismo, en formato YYYYMMDD (año con cuatro dígitos, mes con dos dígitos y día del mes con dos dígitos), y al día siguiente el fichero será borrado.

Si no se pone fecha no pasa nada, simplemente ese fichero no caducará.

El script es muy sencillo, de hecho no lleva ningún sistema de control ni nada, por lo que si ponemos una fecha mal el fichero no se borrará, pero vamos, esto ya cada cual que lo complique cuanto quiera pero creo que no hace falta más, vamos a tener informes con los nombres de ficheros, los vamos a estar viendo al conectarnos a la carpeta… en fin, que un mínimo de atención por nuestra parte tampoco viene mal.

Este es el código:

Fácil ¿no?

Vamos por partes: Este script lo alojaremos en el servidor y le daremos permisos de ejecución. Programaremos una tarea con crontab para que se ejecute de madrugada, a partir de las 00 La hora en realidad da un poco lo mismo, porque desde que apagamos la pantalla por la noche hasta que se enciende por la mañana, en cualquier momento una vez hayamos cambiado de fecha puede ejecutarse.

En la línea 2 calculamos la fecha que era “ayer” y si coincide con la que tiene el fichero lo borramos. ¿Por qué ayer? Pues porque si el evento se celebró “ayer” o “ayer” era el último día, es obvio que “hoy” no hace falta anunciar nada. La comparación se hace en la línea 8, de forma que si las variables “de texto” coinciden el fichero se borra. Compararlas como si fueran de texto tiene la ventaja de que nos evitamos errores si el fichero no lleva fecha e intentamos comparar un número con una cadena alfanumérica. Por contra, para nuestros fines, nos obliga a usar sólo el “igual que”, ya que de otro modo se podrían borrar ficheros sin caducidad, por eso hay que tomar la fecha de “ayer”.

Para sacar la fecha de caducidad del nombre del fichero recurrimos a algo que ya tenemos hecho en el script proyecta.sh Primero almacenamos el nombre con la extensión, eliminando la ruta ($filename en línea 5), luego eliminamos del mismo la extensión ($nombrefichero en línea 6) y luego extraemos la fecha del mismo modo que extraemos la extensión en proyecta.sh (variable $caduca en línea 7)

Ahora ya sólo resta programar el script para que se ejecute con crontab a una hora indecente y listo.

Modificar proyecta.sh

Pero el intercalar esto en el nombre de archivo nos obliga necesariamente a modificar ligeramente, muy ligeramente, el fichero proyecta.sh Recordamos que allí recogemos en la variable $fname el nombre del fichero sin la extensión, vamos a hacer memoria:

Estas son las líneas que tenemos ahora, que están pensadas para un fichero del tipo nombre_fichero.ext de forma que $extension sería “ext” y $fname sería “nombre_fichero”.

Sin embargo si ahora tenemos nombre_fichero.fecha.ext la variable $fname será “nombre_fichero.fecha”, con lo que la opción de audio no nos funcionaría, así que necesitamos quitar la fecha de esa variable y el procedimiento no es nada complicado, de hecho es una minúscula y sutil modificación, esta:

Exacto, cambiar “%” por “%%” en la línea que asigna el valor a la variable $fname (en este caso de ejemplo, la línea 49). Esto hace que se elimine, desde la derecha, todo lo que haya hasta el último punto. Si hay uno se eliminará sólo la extensión, si hay dos, porque el fichero lleva fecha de caducidad, se eliminará la extensión y la fecha. Y ojo, ya imagino que os habréis dado cuenta, pero acabamos de añadir una restricción en los nombres de ficheros que es importante: el nombre del fichero no puede contener más puntos.

Y ya está, eso es todo, ya podemos subir ficheros sin preocuparnos de tener que borrarlos.

Dejo el script “caducados.sh” en formato texto para copiar y pegar. La modificación del “proyecta.sh” es tan simple que no veo que haga falta copiar todo el texto ni subir un fichero nuevo, que hay que ahorrar ancho de banda que está la cosa mu achuchá.

#!/bin/bash
ayer=$(date --date "yesterday" +%Y%m%d)
for file in /home/pi/datos/pantallas/*
do
	filename=$(basename $file)
	nombrefichero="${filename%.*}"
	caduca="${nombrefichero##*.}"
	if [ $caduca = $ayer ]
		then
			rm $file
	fi
done

Ah! Y sí, me encantan los mejillones, son nutritivos, muy beneficiosos para la salud y están de rechupete en cualquiera de sus formas y presentaciones 🙂


Ficheros tratados en esta entrada

    • caducados.sh: Borra los ficheros cuando caduquen.
    • proyecta.sh: Hay que modificar el script principal como se indica
    • crontab: Hay que programar caducados.sh para que se ejecute con crontab

Pantallas informativas: Instrucciones

Sí, bueno, en el apartado VIII decíamos que había que ponérselo fácil al usuario, pero claro, si después de todo esto no le decimos qué tiene que hacer y cómo, por muy fácil que sea no lo va a adivinar, así que al tajo. Ah! y al final de la entrada están en pdf, por si alguien quiere llevárselas a la playa y ahorrarse la novela.

Instrucciones para el usuario

Lo que debemos saber

Las pantallas pueden:

    • Reproducir un vídeo con o sin sonido
    • Que un determinado archivo sólo lo reproduzca una pantalla
    • Que un archivo lo reproduzcan todas pantallas menos una
    • Poner una fecha de caducidad al archivo
    • Funcionar en los días y horas que les programemos

Y además nos informarán por correo electrónico:

    • Cuando se actualicen
    • Cuando encuentren algún problema para actualizarse
    • Cuando cambien la IP
    • Cuando les requiramos un informe

Extensiones de archivo

El sistema de pantallas reproduce imágenes fijas en formato jpg y vídeos en distintos formatos, avi o mp4, por ejemplo (con codificación mpeg, H264, etc.). Nos ceñiremos exclusivamente a estas extensiones.

Los jpg los podemos preparar con un montón de aplicaciones, quizás la más potente y gratuita sea GIMP, que tiene versiones para Linux y Windows (y creo que también para Mac).

Para el uso de este tipo de pantallas vienen también muy bien las presentaciones en PowerPoint, son fáciles de hacer y vistosas. Desde, al menos, la versión 2016, PowerPoint permite guardar las presentaciones en formato de vídeo mp4, totalmente compatible con este sistema de pantallas.

Resolución

Una pantalla HD normalmente tiene una resolución de 1920×1080, lo ideal es dejar vídeos e imágenes a esa resolución, pero hay ocasiones en que no se puede, bien porque es un vídeo en formato antiguo 4:3, una imagen de un cartel en vertical, etc. En estos casos el sistema ajustará la imagen para que ocupe toda la pantalla, pero sin cortarla, ampliando o reduciendo y dejando espacios en negro verticales u horizontales, según sea el caso.

No obstante, atentos a la resolución, porque aunque la pantalla ajuste la imagen no hace milagros. Si por ejemplo nos pasan un jpg de muy poca resolución, al pasarlo a la pantalla la imagen se ajustará, pero lo veremos con unos pixels del tamaño de un perrico pequeño, y el resultado será lo que saca ese perrico por ese orificio que tiene junto al rabo.

Y del mismo modo a la inversa: si nos pasan para subir el vídeo muy chulo de una presentación en 4K y que aunque se proyecte en total silencio va con audio en tres idiomas en 5.1… pues a ver, que aunque quepa en la tarjeta lo que tiene que reproducirlo es una modesta Pi Zero que lo mismo sale corriendo.

Resumiendo: Antes de subir un archivo a las pantallas hay que fijarse en la resolución y características. Habrá archivos que simplemente no valgan, sin más. En estos casos se avisa al remitente y que nos mande un archivo conforme a lo que le especifiquemos.

Reproducción de archivos

Nombre de los archivos

En los nombres de archivos vamos a evitar, por si acaso: espacios, símbolos (excepto guion y guion bajo), acentos y eñes. Lo más fácil: usar sólo letras, números y guión bajo. Sólo con esto podemos hacer diabluras, no es complicado y es una buena práctica.

Un archivo del tipo nombre.ext se reproducirá de forma normal, sin sonido, en todas las pantallas. Para conseguir que un archivo tenga un comportamiento especial hay que modificar su nombre de archivo, bien al principio o al final:

    • XXX + Nombre de la pantalla + nombre del archivo + extensión: Muestra el archivo sólo en esa pantalla
    • ZZZ + Nombre de la pantalla + nombre del archivo + extensión: Muestra el archivo en todas pantallas menos en esa
    • nombre del archivo + AAA + extensión: Reproduce el vídeo con audio.
    • nombre del archivo + .fecha de caducidad + extensión: Indica cuando caduca el archivo.

Por ejemplo, si tenemos tres pantallas llamadas: pantalla1, pantalla2 y pantalla3; si lo que queremos es que la 2, y sólo la 2, muestre un archivo llamado, por ejemplo “jornadas.avi”, lo deberemos nombrar así:

XXXpantalla2jornadas.avi

El nombre del archivo deberá comenzar por XXX en mayúscula y a continuación el nombre de la pantalla, para luego seguir con el nombre del archivo, etc.

Y si quisiéramos justo lo contrario, que la pantalla2 no reprodujera ese archivo, pondríamos lo mismo pero comenzando por ZZZ:

ZZZpantalla2jornadas.avi

Por defecto los vídeos tienen el sonido desactivado, pero si por lo que sea queremos que alguno se muestre con sonido basta colocar AAA, en mayúscula, justo después del nombre del archivo y antes del punto:

jornadasAAA.avi

Y para establecer una fecha de caducidad a un archivo deberemos poner justo antes de la extensión y separado por un punto la fecha de caducidad en formato AAAAMMDD (año con cuatro dígitos, mes con dos dígitos y día del mes con dos dígitos). Esa fecha será la del último día que el fichero estará en pantalla, es decir, se reproducirá desde que lo subamos hasta esa fecha inclusive.

Si por ejemplo, siguiendo con el archivo anterior, queremos que este se reproduzca hasta el 22 de abril de 2019 inclusive pondríamos:

jornadas.20190422.avi

Por supuesto todas las opciones se pueden combinar. Si por ejemplo quisiéramos que el vídeo del ejemplo se reprodujera en la pantalla2, con audio, y hasta esa fecha, pues deberíamos nombrarlo:

XXXpantalla2jornadasAAA.20190422.avi

De hecho aún podemos dar una vuelta de tuerca, si queremos que ese vídeo se muestre con sonido en una pantalla, la pantalla2 por ejemplo, y sin sonido en el resto. Tendríamos que subir el mismo archivo con dos nombres distintos, uno el que justo acabamos de ver y otro este:

ZZZpantalla2jornadas.20190422.avi

Este último nombre hace que el vídeo se reproduzca en todas pantallas excepto en la pantalla2 y sin audio (por defecto).

No obstante, aunque todas las opciones que se pongan estén bien y nunca estén de más, lo que más se va a usar y con diferencia es el nombre de archivo liso y laso junto con la fecha de caducidad:

Jornadas.20190422.avi

Subir y actualizar archivos

En el servidor tenemos configurado un usuario y un password. Lo normal es que en el ordenador donde estemos trabajando tengamos una carpeta de red conectada con nuestro usuario a la del servidor que contiene los archivos, así que la forma de subirlos o actualizarlos será tan fácil como arrastrar un archivo de la carpeta que sea de nuestro PC a esa carpeta o unidad de red.

Las pantallas también tienen programado el horario de encendido y apagado en función del tipo de día: horarios de verano, reducidos, etc. Estos horarios están definidos en los ficheros que contiene la carpeta “días” del servidor, son ficheros de texto que podemos modificar quitando o poniendo las fechas que sean necesarias. Las fechas van en el mismo formato comentado antes, AAAAMMDD, y separadas por un espacio.

Para acceder a estos archivos del servidor hay que conectarse por FTP con nuestro usuario y password.

También, por supuesto, por FTP podemos actualizar los archivos que ha de reproducir la pantalla, ya que por este sistema tendremos accesible la carpeta “días” y la carpeta “pantallas” que alberga dichos archivos.

Si queremos que un determinado archivo deje de reproducirse tan sólo tenemos que borrarlo del servidor. La Raspberry se conecta con el servidor cada media hora, por lo que las actualizaciones que llevemos a cabo se harán efectivas en las pantallas al punto y a la media, salvo errores de conexión, claro.

Opciones especiales

Podemos subir ficheros especiales que provoquen lo siguiente:

    • Envío de un informe de todas las Raspberry
    • Apagar una determinada Raspberry
    • Reiniciar una determinada Raspberry
    • Parar la Raspberry y dejar encendida la pantalla
    • Parar la Raspberry y apagar la pantalla

Respectivamente esto lo podemos hacer subiendo los siguientes ficheros como si fueran ficheros a reproducir y que pueden estar completamente vacíos:

    • test.txt
    • nombrepantalla.001
    • nombrepantalla.002
    • nombrepantalla.003
    • nombrepantalla.222

Obviamente, nombrepantalla deberá ser cambiado por el nombre de la pantalla que queremos que haga lo que sea. Y también, para ser exactos, la última extensión, ahora mismo, podría ser cualquier número mayor que 003 (basta mirar el código de proyecta.sh para comprenderlo), que son las acciones que en estos momentos hay definidas, pero por si acaso se me ocurre meter alguna cosa más y como no tengo ganas de andar revisando instrucciones, pues ponemos 222, que tiene número de galleta y dudo que meta más de doscientas opciones.

Las Raspberry nos enviarán correos electrónicos a la dirección que hayamos definido, indicando entre otras cosas actualizaciones e IP.

También podemos, con otro usuario y pass, acceder a la Raspberry por SSH y realizar las acciones que sean precisas, pero para esto deberemos usar un ordenador que esté conectado a la misma red que la Raspberry.

Instrucciones en PDF

Pantallas informativas: Anexos e Instrucciones

Llega el momento de los parches y los zurcidos, y es que es poniendo a funcionar el montaje cuando vamos viendo algunas funcionalidades que nos serían útiles. En las siguientes entradas se detallarán aquellos ajustes que se han llevado a cabo una vez puesto en marcha el sistema.

De momento ninguno de los códigos de los anexos está recogido en los ficheros para descargar de la entrada IX, ya que de momento son pequeñas modificaciones y tampoco estamos haciendo una aplicación, sino comentando un sistema y dando algunas ideas. No obstante, si en algún momento se hace algún cambio importante se modificará el fichero de la mencionada entrada y se indicará aquí y en los anexos correspondientes.

Pantallas informativas (IX): Resumen, ajustes para añadir pantallas, cómo adaptar para otros usuarios y ficheros para descargar

En las anteriores entradas hemos visto cómo llevar a cabo todo el sistema, desde cero. Llegados a este punto ya tenemos todos los códigos de los scripts, los archivos de texto que usaremos para controlar nuestra aplicación, etc. Es el momento de recapitular y enumerar los pasos necesarios para hacer una instalación desde cero y cómo añadir a ella nuevas pantallas o distintos usuarios.

Instalación desde cero

Raspberry

    • Instalación de Raspbian Desktop
      • Configurar País, lenguaje, Timezone
      • Poner un pass decente a Pi
      • Activar SSH, VNC, desactivar overscan y poner memoria GPU a 128
      • Configurar WiFi y actualizar sistema
      • Poner nombre a host que lo diferencie del resto de pantallas
    • Generar el par de claves para conectar al servidor
      • Configurar ficheros y carpetas
    • Instalar FIM
      • Crear fichero de configuración FIM
    • Instalar cec-utils
    • Crear las carpetas y copiar los ficheros
      • Carpeta dias
      • Ficheros de días
      • Ficheros de texto de control
      • Scripts
    • Configurar
      • Configurar conexión
      • Configurar correo de destino de los mensajes
      • Configurar Mutt
      • Configurar Crontab

Servidor

    • Instalar Ubuntu
    • Crear usuario “Pi” para conexión con Pi de Raspberry
      • Crear fichero con clave pública
      • Crear estructura de carpetas
      • Almacenar ficheros de días (calendario)
    • Crear usuario userpantallas para actualizaciones
      • Crear enlace simbólico ftp en su home hacia carpeta de Pi
    • Configurar Samba
    • Instalar VSFTPD
      • Configurar VSFTPD

Partiendo desde cero, es largo, pero tampoco excesivamente complicado cuanto ya tenemos los scripts preparados. Llegados a este punto sería bueno “clonar” la tarjeta de la Raspberry y así, además de servirnos como copia de seguridad ante un eventual desastre, podemos añadir más pantallas muy fácilmente.

Añadir más pantallas (para un mismo usuario)

Actualización Diciembre de 2019

Se ha añadido la siguiente entrada que detalla el proceso y sugiere algún cambio que lo facilita:

Pantallas informativas (anexo 4): Añadir pantallas -explicado paso a paso-

Para añadir más pantallas lo único que habría que hacer sería grabar esta imagen en una nueva tarjeta y:

En la Raspberry

    • Cambiar el nombre del host
    • Generar un nuevo par de claves
    • Machacar la anterior clave privada con la nueva (dar mismo nombre)

En el servidor

    • Mandar la clave pública al servidor y añadirla al final del archivo.

Y ya está, ahora sí que es tremendamente fácil y podemos añadir todas las que queramos.

Añadir otros usuarios (y sus pantallas)

Y si lo que queremos es añadir otros usuarios que se conecten a nuestro servidor, pero que usen sus conexiones y proyecten sus propios archivos, lo que haríamos sería lo siguiente:

En la Raspberry

Tras grabar nuestra imagen:

    • Cambiar el nombre del host
    • Generar un nuevo par de claves
    • Machacar la anterior clave privada con la nueva (dar mismo nombre)
    • Modificar el archivo correo.txt con el correo al que dirigir los mensajes
    • Modificar wpa_supplicant con login y pass de conexión
    • Modificar los scripts actualiza y actualizadia con el login Pi2 (o el que creemos nuevo en el servidor)

En el servidor

    • Crear otro usuario “Pi2”
      • Crear su fichero con clave pública
      • Crear estructura de carpetas
      • Almacenar ficheros de días (calendario)
    • Crear otro usuario userpantallas2 en sistema y Samba
      • Crear enlace simbólico ftp en su home hacia carpeta de Pi2
    • Configurar Samba para este usuario
    • Añadir este usuario a la lista de usuarios de VSPFTP

Es importante que el enlace simbólico también se llame ftp y así sólo habrá que añadirlo a la lista de usuarios VSFTPD

Y que no se nos olvide clonar su tarjeta por seguridad.

En fin, que lo más laborioso ha sido toda la creación de scripts y ficheros, pero una vez que los tenemos, añadir usuarios o trasladar el sistema a otros nuevos no requiere de mucha complicación.

Además, he modificado ligeramente los scripts para que el correo de destino lo tomen del archivo correo.txt, que aparece en estas líneas, para que haya que tocar menos cosas.

Descarga de ficheros

En las entradas previas se ha ido publicando el código de los distintos scripts paso a paso. El siguiente enlace contiene, comprimido en 7z, todos los scripts que se han ido mencionando y los ficheros de texto para el manejo de la aplicación.

Ficheros Proyecto Pantallas v.01

Clonar la tarjeta

Llegados a este punto resultaría bastante aconsejable que una vez que tengamos perfectamente configurada la tarjeta le sacáramos una copia por si las moscas. Además con esta copia sería fácil adaptar el sistema para nuevas pantallas.

Para el proceso de clonado de la tarjeta hay una entrada específica aquí:

Clonar la tarjeta

Cosas que faltan

Seguridad

Como ya he dicho por algún rincón de este blog, todo esto son cosas que van saliendo conforme las voy aprendiendo, así que estoy a eones de ser ya no un “experto” sino un mero “entendido”, pero me relaja escribir y me sirve de bloc de notas, y quién sabe si además le puede servir esto a alguien. Pero esta inexperiencia es la que me lleva a pensar que lo primero que habría que revisar es la seguridad en la Raspberry y el Servidor, cerrar las puertas a que alguien pueda hacer “la gracia”. La seguridad hay que revisarla.

Apagado de emergencia

Un botón de apagado de emergencia en la Raspberry estaría bien. Alguna prueba me ha llevado a tener que apagarla a las bravas, y aunque la tarjeta de memoria ha aguantado sé que estas prácticas le sientan como una patada entre las patillas (del micro). Se me ocurre que con Python se podría hacer un programeja para controlar una interrupción en un puerto GPIO, de modo que al accionar un pulsador se activara dicha interrupción y se produjera un apagado ordenado, incluso le podríamos poner un led para saber cuando concluye el apagado y no tener que abrir la caja, que además los bombillicos siempre hacen gracia.

SAI

Un SAI de bajo coste también aparece como tarea pendiente: Un power bank con capacidad de carga y descarga simultánea (pass through charging), un relé, un par de adaptadores y lo de antes, mediante una interrupción controlar cuando hay un corte de suministro eléctrico, controlar el tiempo que estamos sin electricidad y llegado el momento hacer un apagado ordenado.

Fecha de caducidad de los ficheros

También, en el tiempo que llevamos de pruebas con una de las pantallas, se va echando en falta un sistema de caducidad de los ficheros a reproducir. Y para evitar que las tripas de la Raspberry se vayan llenando de ficheros caducados, se me ocurre que eso habría que hacerlo en el servidor. Quizás con un simple script leyendo un índice supiera qué fichero tiene que borrar y cuando.

Se podría hacer lo mismo pero a la inversa, programar un día de activación del fichero, en la web (WordPress, Drupal, etc.) es una opción que encontramos disponible de forma bastante común, pero mi experiencia precisamente con la publicación de contenidos web en trabajos similares al que nos ocupa me dice que es una característica perfectamente prescindible, creo que no la he usado nunca. La caducidad sí, no hay publicación de esta índole que se libre porque se trata de charlas, cursos, exposiciones, etc. perfectamente definidos en el tiempo, pero la activación no, porque interesa que el evento tenga días de publicidad y además lo habitual es que te den las cosas “para ayer”.

Pantallas informativas (VIII): Gestión de ficheros fácil para el usuario

Introducción

Conforme estaba escribiendo esta entrada me estaba dando cuenta de que para muchos casos esto puede ser matar moscas a cañonazos, por eso he creído conveniente poner esta introducción inicial.

Si en algún momento del espacio-tiempo alguien, aparte de mí mismo, lee estas entradas y decide poner en marcha un sistema como este, es muy posible que lo que a continuación se detalla no le sea necesario. Si alguien pretende ponerse una tele en el escaparate de su tienda y manejarla él mismo, puede tranquilamente saltarse este apartado, pues podrá poner los ficheros a reproducir subiéndolos por ftp como se ha estado haciendo hasta ahora para las pruebas.

En nuestro caso concreto, y hablo del montaje que se está realizando, esto no va a ser así. Al cargo de la actualización de los archivos podrá haber personas con unos conocimientos de informática a nivel ofimático y de usuario, que a lo mejor lo de combinar correspondencia en Word lo manejan con la habilidad de un prestidigitador, pero que lo del manejo del FTP y demás les sobrepasa un poco, por tanto hay que diseñar un sistema fácil y seguro.

Desarrollo

Al usuario hay que ponérselo fácil, lo más fácil posible, como un juego de niños. Siempre he dicho que hay que considerar al usuario como un completo ignorante en temas informáticos, pero no en modo despectivo en absoluto, sino porque tiene, tenemos, todo el derecho del mundo a serlo, y porque cuando yo mismo uso alguna nueva aplicación agradezco si su creador ha seguido esta misma filosofía y no me obliga a invocar a los arcanos mayores para hacer cosas de lo más simples.

Así pues, para copiar un archivo ¿Qué hay más simple para un usuario que arrastrar un icono de una carpeta a otra? Eso lo haremos con Samba.

Pero también habrá que configurar esos otros archivos del calendario, una tarea que haremos de ciento a viento. Eso lo haremos por FTP “enjaulando” a los usuarios. Se podría hacer tranquilamente por Samba, con otro usuario y otra configuración, de forma muy fácil, pero para qué engañarnos, también me apetecía probar esta configuración a ver qué pasaba, así hay donde elegir.

Y a la vez, todo esto lo haremos evitando conectarnos al servidor como “pi”, eso lo dejaremos para el maestro de ceremonias, es decir, nosotros mismos, preservando todos los ficheros de configuración de cualquier mal uso.

Comenzamos.

Samba

Con Samba vamos a crear un usuario en el servidor que tenga acceso “sólo” a la carpeta de los archivos que han de reproducir la pantallas, luego conectaremos esa carpeta en un ordenador con Windows para tenerla siempre disponible y después sólo será necesario tratarla como una carpeta más de nuestro ordenador: abrimos con doble clic, arrastramos un fichero, borramos el que ya no necesitemos, etc. Más fácil imposible.

Bien, en el servidor tenemos al usuario pi y en su home tenemos el directorio datos y sus subdirectorios dias y pantallas. Va a ser el subdirectorio pantallas el que compartamos con Samba.

Como root, vamos a crear en primer lugar un usuario con home pero sin acceso a la shell, le asignaremos una contraseña y lo meteremos en el grupo de pi, lo vamos a llamar “userpantallas“:

useradd -g pi -m -s /usr/sbin/nologin userpantallas

Le configuramos un pass

passwd userpantallas

Y aquí le colocamos el que queramos, pero lo apuntamos para que no se nos olvide porque lo usaremos más adelante con FTP, ahora confirmamos y seguimos.

Nos metemos en el home de userpantallas y vamos a crear aquí un enlace simbólico a la carpeta datos de pi, así:

ln -s /home/pi/datos ftp

Como estamos como root, vamos a asignarle a ese enlace el propietario userpantallas y el grupo pi. Ojo, que la instrucción chown con los enlaces no se puede usar tal cual, o cambiará el propietario de las carpetas de destino, y eso no es lo que nos interesa, hay que poner la opción -h

chown -h userpantallas:pi ftp

Bien, si ahora entramos en ftp veremos que dentro encontramos los subdirectorios dias y pantallas ¡¡¡Magia!!! No, no es magia, es… un enlace simbólico.

Comprobamos que Samba está instalado en el ordenador con Ubuntu, nuestro servidor, y si no procedemos a ello como con cualquier aplicación, no tiene misterio.

Ahora tenemos que seguir con el usuario userpantallas y crearlo en Samba, para ello:

smbpasswd -a userpantallas

Nos pedirá un pass, así que le asignamos uno que no tiene que ser el mismo que hemos puesto en Ubuntu, y seguimos.

Ahora toca configurar Samba, para ello editamos el fichero smb.conf que se encuentra en la ruta /etc/samba

El fichero es bastante extenso porque vienen comentadas las opciones de configuración. Sobre esto, como soy bastante profano en la materia, se recomienda tirar de manual para hacer una configuración correcta y segura. No obstante, la que he llevado a cabo y funciona es la siguiente, que pego sin comentarios:

[global]
   workgroup = NUESTRO_GRUPO_DE_TRABAJO
   server string = %h server (Samba, Ubuntu)
   dns proxy = no
   log file = /var/log/samba/log.%m
   max log size = 1000
   syslog = 0
   panic action = /usr/share/samba/panic-action %d
   server role = standalone server
   passdb backend = tdbsam
   obey pam restrictions = yes
   unix password sync = yes
   passwd program = /usr/bin/passwd %u
   passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .
   pam password change = yes
   map to guest = bad user
# Desactivamos impresion en samba
   load printers = no
   printing = bsd
   printcap name = /dev/null
   disable spoolss = yes
[printers]
   comment = All Printers
   browseable = no
   path = /var/spool/samba
   printable = yes
   guest ok = no
   read only = yes
   create mask = 0700
[print$]
   comment = Printer Drivers
   path = /var/lib/samba/printers
   browseable = yes
   read only = yes
   guest ok = no
[pantallas]
   path = /home/userpantallas/ftp/pantallas
   browseable = no
   writeable = yes
   valid users = userpantallas
   directory mask = 0775
   guest ok = no

Al principio del fichero de configuración hay que poner el grupo de trabajo que tengamos configurado en nuestra red, y al final, como valid users, está el usuario que hemos creado para este fin y el path un tanto extraño que nos enlaza con la carpeta que contiene los ficheros a reproducir, ya que recordamos que la carpeta ftp de userpantallas es un enlace simbólico a la carpeta datos de pi, con todo su contenido.

El resto de opciones de global son las que vienen por defecto, aunque se han borrado algunas que contenía el fichero original. Las opciones de impresión no las vamos a usar, así que no sé si están correctamente configuradas ni para usarlas ni para dejar de hacerlo.

Y llegados a este punto guardamos el fichero con esta configuración y reiniciamos Samba.

samba restart

Vale, pues vamos a probar la conexión desde un equipo con Windows. En este caso va a ser un equipo con Windows 10 pero el proceso es similar en otras versiones de Windows.

Pinchamos con el botón derecho del ratón sobre el icono de Red y seleccionamos “conectar a unidad de red”.

Nos saldrá una ventana como esta:

Ponemos la IP del equipo y el nombre de la carpeta que hemos compartido en Samba. Ojo que ya se puede ver que no es la trayectoria completa, sólo \\IP\nombre_carpeta_samba. Marcamos también la casilla “Conectar con otras credenciales” y si quisiéramos tenerla siempre disponible marcaríamos también “Conectar de nuevo al iniciar sesión”, como es una prueba, de momento esa la dejamos en blanco. Pinchamos en “Finalizar” y pasamos a la siguiente ventana:

Aquí ponemos el nombre de usuario de Samba, según el ejemplo que estamos siguiendo en esta entrada será userpantallas y el pass que le hemos puesto en Samba. Y lo mismo, si quisiéramos tener siempre accesible esta carpeta marcaríamos “Recordar mis credenciales“, en este caso lo dejamos en blanco y pulsamos “Aceptar“.

Y listo. Si todo ha ido bien y no hemos metido la pata en la configuración deberíamos estar viendo el contenido de la carpeta pantallas y podríamos trabajar con ella como si fuera una carpeta más de nuestro propio equipo.

Ahora, viendo que todo funciona, sería cuestión de realizar esta conexión en el equipo, o equipos, que se encarguen de actualizar la información que muestren las pantallas, y en estos casos sí que marcaríamos las casillas que antes hemos dejado en blanco, tanto la de “conectar de nuevo al iniciar sesión” como la de “recordar mis credenciales“, con ello esta carpeta aparecería siempre como si fuera una unidad más de disco.

Llegados a este punto sería muy fácil crear otro usuario en Samba y que se conectara a la carpeta /datos/dias para actualizarla cuando fuera preciso, pero la ventaja que tiene Samba es que permite tener la carpeta siempre accesible y eso es precisamente lo que no queremos para la carpeta dias, y como además nos gusta probar cosas, pues vamos a hacer que esa actualización sea por FTP.

VSFTPD

 Como ya hemos dicho, queda una parte que también ha de actualizar de vez en cuando el usuario y que no nos interesa que sea “tan” fácil, y es la actualización de los archivos con los listados de fechas. Estas actualizaciones se harán una vez al año o poco más si sale alguna incidencia, y es por ello que no interesa que esa carpeta esté ahí todo el tiempo siendo candidata a un “¡Ay! Es que la he borrado sin darme cuenta”. Subimos un poco el nivel y para actualizar ese directorio habrá que usar el FTP. ¡Un drama!

Pues no, nada de drama. Vamos a instalar VSFTPD en nuestro particular servidor y vamos a “enjaular” a los usuarios, de tal modo que cuando el usuario se conecte por FTP sólo tenga acceso a la carpeta que nos interese pero sin que pueda navegar por otros directorios del sistema o de otros usuarios, ni siquiera por el resto de subdirectorios de su home, preservando así, por ejemplo, la clave pública para la conexión de la Raspberry y otros archivos de configuración.

Como puede verse, dificultad mínima, tan sólo se trata de instalar un programa de FTP y conectarse a una IP con un pass. Punto pelota.

Que nadie sufra por estos dos “usuarios”, fueron “desenjaulados” al cabo de un rato. A los nuestros sin embargo les espera la perpetua ¡Nunca saldrán de su home!

Vamos al tajo. Comenzamos instalando vsftpd en el servidor con Ubuntu:

sudo apt-get install vsftpd

Y lo activamos

sudo systemctl start vsftpd

sudo systemctl enable vsftpd

Hacemos una copia del fichero de configuración

sudo cp /etc/vsftpd.conf /etc/vsftpd_conf.bak

Y ahora editamos el fichero de configuración vsftpd.conf para adaptarlo a nuestros propósitos. El fichero viene bastante comentado y hay páginas por Internet que nos pueden ayudar a su comprensión.

La instrucción clave es allow_writeable_chroot=YES esto es lo que permite enjaular a los usuarios en el local root que les definamos, que será ftp con esta instrucción: local_root=/home/$USER/ftp

Además crearemos una lista de usuarios capaces de usar este servicio, no valdrá sólo con crear un usuario y agregarle un directorio ftp, deberá estar también en la lista: vsftpd.userlist

Pero pese a todo he de reconocer que un par de veces que lo he configurado en distintos equipos, un par de veces que he tenido que pelear con él. Así pues, a continuación pongo el fichero de configuración que está probado y funcionando, aunque posiblemente se pueda afinar algo más.

En la línea 10 tenemos el “enjaulamiento”, en la 20 el directorio, que en este caso es un enlace simbólico pero funciona exactamente igual que si fuera un directorio y en la 22 la ubicación y nombre del archivo de los usuarios autorizados. Deberemos pues crear este fichero y colocar allí a userpantallas

sudo nano /etc/vsftpd.userlist

Guardamos, salimos y reiniciamos el servicio

systemctl restart vsftpd

Y para saber si todo está funcionando bien podemos probar:

service vsftpd status

Deberíamos ver “algo verde”, si vemos “algo rojo” es que “algo” no va bien. Muy posiblemente un triste error sintáctico en el fichero de configuración, cuestión de repasarlo (nada que no consigamos tras toda una tarde tirándonos de los pelos, lo normal…)

Por último, si recordamos, hemos creado al usuario userpantallas sin shell, indicando que usara /usr/sbin/nologin Bien, pues ahora toca añadir esto en el archivo /etc/shells porque si no no podremos conectarnos por ftp, así que nos situamos en etc y:

sudo nano shells

Y añadimos al final la línea indicada. El fichero quedará más o menos así:

Y llegados a este punto toca probar. Vamos a probar con WinSCP:

En protocolo seleccionamos FTP sin cifrado, colocamos la IP del ordenador al que queremos conectarnos, el que hace de nuestro servidor y colocamos el nombre de usuario del usuario que tenemos creado userpantallas y el pass que le hemos dado a la hora de crearlo en Ubuntu, no el de Samba, VSFTPD funcionará con el pass que tenga el usuario en el sistema.

Y ahí están las carpetas dias y pantallas accesibles.

Ha sido un trabajo un poquito laborioso, pero hemos conseguido dejarlo fácil para el usuario, que es de lo que se trataba.

El código de fsftpd.conf para copy&paste, aquí:

listen=NO
listen_ipv6=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
chroot_local_user=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
ssl_enable=NO
pasv_enable=YES
pasv_min_port=10000
pasv_max_port=11000
user_sub_token=$USER
local_root=/home/$USER/ftp
userlist_enable=YES
userlist_file=/etc/vsftpd.userlist
userlist_deny=NO
allow_writeable_chroot=YES
check_shell=NO

 

 

Pantallas informativas (VII): Programado de encendido y actualizaciones con crontab

En las anteriores entradas hemos estado hablando de automatizar y apagar, ahora toca encender la pantalla y ejecutar las tareas a su hora, y eso lo vamos a hacer muy fácil con crontab.

Vamos a definir:

    • Ejecución de comandos y scripts al iniciar.
    • Actualización del calendario a las 6 am.
    • Encendido de la pantalla a las 9 am.
    • Comprobar actualizaciones de ficheros cada 30 minutos.
    • Comprobar IP cada 15 minutos.

Como paso previo, damos a todos los scripts que hemos hecho permisos de ejecución con el comando:

chmod +x nombre_del_script.sh

Y ahora programamos su ejecución con crontab.

Sin extendernos mucho, porque no lo voy a hacer mejor que el peor manual de Linux, para programar con crontab la forma es:

* * * * * nombre_del_script.sh

Y los asteriscos, comenzando por la izquierda, son:

      • minuto
      • hora
      • día de la semana
      • mes
      • día del mes

Así, si a las seis de la mañana queremos que se actualicen los ficheros de fechas, pondremos lo siguiente:

* 6 * * * /home/pi/actualizadia.sh

Fácil, ¿no?

Si queremos que una tarea se ejecute cada 15 minutos en el primer asterisco pondremos */15, que vendría a decir “cada 15”, ya que si ponemos sólo 15 la tarea se ejecutará en el minuto 15 de cada hora, no cada 15 minutos. Así:

*/15 * * * * /home/pi/queip.sh

Y si queremos que algo se ejecute al iniciar la Raspberry pues ponemos @reboot loquesea.

Bien, pues ahora que sabemos qué queremos hacer y cómo, nos ponemos manos a la obra.

Editamos crontab, como pi, con el siguiente comando:

crontab -e

Y la primera vez nos preguntará por nuestro editor de textos favorito, yo me apaño bien con nano, pero para gustos colores, podéis seleccionar el que queráis.

Una vez dentro del fichero veremos un montón de líneas comentadas, pues al final colocamos las nuestras:

@reboot sleep 10 && /home/pi/iniciando.sh > /dev/tty1; /home/pi/actualizadia.sh; /home/pi/actualiza.sh; /home/pi/fecha.sh &
#
* 6 * * * /home/pi/actualizadia.sh &
#
* 9 * * * /home/pi/fecha.sh &
#
*/15 * * * * /home/pi/queip.sh &
#
*/30 * * * * /home/pi/actualiza.sh &

Al iniciar le decimos que espere 10 segundos, para dar un poco de tiempo a que acabe de cargar todo antes de comenzar a ejecutar los scripts.

Primero ejecutará iniciando.sh que es el que se encarga de comprobar la wifi. Podríamos haber hecho eso mismo con el sistema, pero prefiero hacerlo así y ver que tengo conexión y una mínima indicación en pantalla por si en algún momento algo va mal.

Y aquí vemos que la salida se ha enviado a /dev/tty1, la pantalla, porque este script lo está ejecutando crontab, no nosotros, y él no necesita pantalla. Por ello, los scripts que hemos hecho hasta ahora habrá que modificarlos ligeramente teniendo en cuenta esto, que habrá que mandar la salida a /dev/tty1 y que si hay que borrar habrá que cambiar el clear por clear_screen. Luego lo vemos porque en realidad son cuatro cambios.

Siguiendo con la línea del inicio, ejecutamos también el fichero de actualización de fechas y luego el de archivos y por último el fecha.sh que será el que compruebe qué tipo de día es y según eso lance el script principal proyecta.sh. Este último será el que tengamos que modificar más cuidadosamente.

Y el resto de líneas es lo comentado anteriormente según lo definido al inicio.

Por legibilidad hemos dejado una línea en blanco, comentada, entre medio de cada línea de tareas programada, pero es completamente optativo esto.

Modificación del fichero proyecta.sh

Bien, como este script es lanzado por otro que a su vez lo ejecuta crontab, cuando decimos en él “borrar pantalla” tenemos que decir “qué pantalla”, así que dirigiremos el comando a /dev/tty1 en estas líneas:

Fácil. Modificamos las líneas necesarias y hemos dejado comentadas las viejas para mejor comprensión.

En esta entrada no pego el código completo del script porque en la siguiente estarán todos los ficheros empaquetaditos y los cambios como se puede ver son mínimos.

Y esto ya casi está. En la siguiente entrada hacemos un repaso, vemos cómo preparar el sistema para más pantallas, para otros usuarios, clonar tarjetas y listo.


Ficheros tratados en esta entrada

    • proyecta.sh (script principal)
    • crontab

 

Pantallas informativas (VI): Distintos horarios de funcionamiento según la fecha

Para hacer el sistema lo más autónomo posible, lo suyo sería que se encendiera y apagara a la hora programada, e incluso, que el encendido y apagado pudiera variar según determinadas fechas.

Este proyecto está diseñado para varios edificios con una apertura al público en diversos horarios según la época del año, es un tanto particular, así que vamos a buscar un ejemplo que lo haga más comprensible.

Vamos a imaginarnos un comercio que abre la persiana a las 9 y la baja a las 20 horas, que abre determinados sábados de 9 a 13, algunos sueltos, y que para el verano tiene días de apertura sólo de mañanas, de 9 a 15, por último este comercio cierra los días de vacaciones como es lógico, y los domingos y festivos.

Vamos a ver cómo programar todo esto, que parece un lío pero no es para tanto. De momento lo planteamos

Tenemos cuatro posibilidades:

    1. Horario normal, N: encendido a las 9 y apagado a las 20
    2. Horario de mañanas, M: encendido a las 9 y apagado a las 15
    3. Horario de sábados, S: encendido a las 9 y apagado a las 13
    4. Festivos, F: apagado todo el día

Estamos en Zaragoza (España), es 2019 y el calendario que nos pasan podría ser como el siguiente:

En rojo están los festivos, sábados y domingos; en azul las vacaciones, en amarillo los días que abre sólo de mañana y en verde los sábados que tiene apertura.

Vamos a preparar un script que haga lo siguiente:

    1. Partiremos suponiendo que el día es normal y asignaremos a una variable, $hoy, el valor “N”

A partir de aquí haremos una serie de comparaciones if-then, no if-elif-else, pues el valor puede cambiar varias veces, que parece una estupidez pero es por comodidad, luego lo veremos más claro.

    1. El segundo paso será comprobar si es horario de mañanas, y si lo es, cambiar $hoy a “M”.
    2. El tercer paso será comprobar si es vacaciones o festivo, en cuyo caso asignaremos $hoy a “F”
    3. A continuación comprobamos si es sábado o domingo y de serlo asignamos a $hoy el valor “F”
    4. Y por último comprobamos si estamos ante un sábado de apertura, en cuyo caso asignamos a $hoy el valor “S”

Bien, hemos hablado de comprobar, comprobar, comprobar… ¿pero cómo comprobamos? Pues con un un listado de fechas para cada tipo de día. Necesitaremos en este caso: Un fichero con las fechas de los festivos y días de vacaciones, otro con los días que sólo se abre de mañanas y un tercero con los sábados que se trabaja. Una vez que tengamos estos ficheros el sistema es cargar el contenido en un array y comparar cada registro del array con la fecha en la que nos encontremos.

Ficheros con los listados de fechas

Una forma fácil de hacer la comparación que mencionábamos es usar la nomenclatura Año-mes-día sin separación. Si escribimos en el shell

date -%Y%m%d

veremos que obtenemos la fecha así, saldrá algo como 20190304. Así pues, los ficheros que generemos tendrán que tener la fecha en este formato, uno detrás de otro y separado por un espacio, por ejemplo el de los sábados de apertura tendrá el contenido: 20190105 20190302 20190907 20191005 20191019 y lo guardaremos como sabados.txt

Para el resto de tipos de días haremos lo mismo. Un truquillo es hacerlo con Excel o Calc. Por ejemplo, para los días de apertura sólo de mañanas podemos coger el Excel y en la primera celda (A1) escribir 20190708 y en la de la derecha (B1) poner una fórmula que sume 1 a esta celda (=A1+1)

Luego hacer un llenado hacia la derecha (Ctrl-D) y rellenar las celdas hasta el valor 20190726, es decir, 19 celdas.

Salvamos como texto separado por comas (o punto y coma) y con nuestro editor de texto favorito reemplazamos el carácter separador por un espacio. Luego añadiríamos los días que faltan, del 19 al 23 de agosto, y listo. Ya tenemos un bloque.

Con el de vacaciones haríamos lo mismo, y los días festivos los añadiríamos a mano al fichero. Parece muy lioso pero en realidad es más largo de explicar que de hacer.

Y llegados a este punto puede deducirse por qué antes hemos hablado de usar if-then e ir cambiando el valor. Vemos que no nos hemos preocupado de separar fechas en el mes de julio, considerando del 8 al 26 como que se abre de mañanas, pero entre medio hay sábados y domingos. Haciéndolo así nos despreocupamos de tener que ir seleccionando los días a la hora de crear los ficheros, simplemente al comparar la fecha, por ejemplo, del 20 de julio, primero tomará, por defecto, el valor “N”, luego comparará el fichero de “sólo mañanas” y tomará el valor “M” pero después verá que cae en fin de semana y cambiará de nuevo, esta vez finalmente a “F”.

Bien, pues damos por hecho que ya tenemos tres ficheros, que van a llamarse: “mananas.txt”, “festivos.txt” y “sabados.txt” y los vamos a meter en una carpeta que se llame “dias” en el home de pi en la Raspberry y a preparar el script que se habrá de ejecutar a las 9 de la mañana:

Script fecha.sh

Comenzamos asignando el valor a tres variables:

La variable $dia va a contener el tipo de día que es, comenzando como ya hemos dicho por “N” (normal)

$esfinde la usaremos para saber qué día de la semana es +%u devolverá 1 si es lunes, 2 si es martes, etc. La usaremos para saber si estamos ante un fin de semana.

$hoy tomará el valor de la fecha actual en el formato antes mencionado.

Hacemos ahora la primera comparación para ver si estamos en horario de mañanas:

Y aquí está todo el meollo: Creamos un array en el que metemos el contenido del fichero de texto “mananas.txt”, luego vamos recorriendo con un for-in cada uno de sus elementos y comparándolos con el contenido de la variable $hoy, si alguno coincide asignamos a $dia el valor “M” y si no no hacemos nada.

Y el resto de comparaciones van igual, sólo que con otros nombres:

Se puede ver en la imagen que los bloques de comparación son casi un calco unos de otros a excepción del que comprueba si es sábado o domingo, que lo que hace es comprobar que el valor numérico de la variable $esfinde es mayor que 5.

Vale, ya tenemos el valor de $dia, así que ahora tan sólo tenemos que arrancar nuestro script de visualización de los archivos pasando este valor como argumento, así:

Vamos a llamar a este script fecha.sh y su código completo es el siguiente:

#!/bin/bash
dia="N"
esfinde=$(date +%u)
hoy=$(date +%Y%m%d)
# Comprobamos si se abre solo de mañanas
mananas=$(cat /home/pi/dias/mananas.txt)
for m in $mananas
do
	if [ $m = $hoy ]
	then
		dia="M"
	fi
done
# Comprobamos si es festivo o vacaciones
festivos=$(cat /home/pi/dias/festivos.txt)
for f in $festivos
do
	if [ $f = $hoy ]
	then
		dia="F"
	fi
done
# Comprobamos si es sabado o domingo
if [ $esfinde -gt 5 ]
then
	dia="F"
fi
# Comprobamos si es sábado de apertura
sabados=$(cat /home/pi/dias/sabados.txt)
for s in $sabados
do
	if [ $s = $hoy ]
	then
		dia="S"
	fi
done
# Si no es festivo, arrancamos proyecta.sh
# y pasamos en el argumento el tipo de día
if [ $dia != "F" ]
then
	bash proyecta.sh $dia
fi

Modificando proyecta.sh

Ahora toca hacer los ajustes en el script proyecta.sh que venimos arrastrando desde las anteriores entradas. Al principio del mismo colocamos lo siguiente:

 

La variable $1 contiene el argumento que acabamos de pasar, así que hacemos un case y a la variable $apaga le asignamos el valor numérico que corresponderá a la hora-minutos de apagado.

Una aclaración: aquí bien podríamos haber pasado el valor de la hora de apagado directamente como argumento, haciendo el case en el script que compara los ficheros, e incluso no haciéndolo y asignando 1300 en lugar de “S” a la variable cuando detecte un sábado laborable, por ejemplo, y así con el resto. Pero es todo cuestión de orden y a mí me resulta más cómodo así, por tener todas las variables que pueda definir lo más agrupadas posibles, por si en algún momento tengo que modificar algo.

Bien, pues ya tenemos la variable $apaga con la hora de apagado de la pantalla, ahora nos metemos en el while y comprobamos:

Al inicio del bucle cargamos en la variable $quehora la hora actual del sistema en formato HHMM, acto seguido comparamos si el valor de dicha variable es superior al de la variable $apaga, en caso de serlo cambiamos el valor de la variable que hace que el bucle se ejecute, ponemos $ejecutacon valor “fin” y salimos del bucle.

Obviamente no es un apagado “exacto”, pero el sistema tampoco nos requiere una precisión de cirujano y nos sirve perfectamente.

Y ahora toca apagar la pantalla. Hay varias formas de hacer esto, yendo de lo más fácil a lo más complicado serían:

    • Quitar la señal al HDMI
    • Usar comandos CEC
    • Quitar la corriente a la pantalla con un relé usando un puerto GPIO

Vamos a comenzar probando a, simplemente, desactivar el HDMI. Hay unos cuantos monitores y pantallas que si dejan de recibir señal por HDMI se ponen automáticamente en standby transcurridos unos segundos, pues bien, probaremos a ver si tenemos suerte.

Escribimos esto en el shell. Esto desactivará el HDMI en el que tenemos conectada la pantalla:

vcgencmd display_power 0

Si al cabo de unos segundos la pantalla pasa a standby, fenomenal, yo no me complicaría más y lo dejaría así. Iríamos al final del archivo, donde están los if para realizar las tareas oportunas una vez que hemos salido del bucle, y colocaríamos nuestra condición para apagar:

Y para encender sería la misma instrucción pero con un “1”, que colocaríamos al principio del script:

vcgencmd display_power 1

Sin embargo en nuestro caso eso no ha funcionado, se desactivaba el HDMI pero se quedaba el cartelito de “no signal” ad eternum. Tocaba exprimirse las meninges.

Lo primero fue instalar las cec-utils

sudo apt-get install cec-utils

Y a continuación probar los comandos para apagar y encender:

Apagado:

echo standby 0 | cec-client -s -d 1

Para encender:

echo on 0 | cec-client -s -d 1

Y sí, eso en nuestra pantalla de pruebas, una Panasonic modelo viejo, gordo y pesado, funcionó. O casi, porque al encender se iba al canal de TV. Tras unas cuantas pruebas el comando que funcionó para cambiar al HDMI 1 que era donde estaba conectada la Raspberry fue el siguiente:

echo 'tx 4f:82:11:00' | cec-client -s -d 1

Sinceramente no puedo explicar bien estos comandos. Los de encendido y apagado lo he visto en varias páginas de Internet, los he probado y funcionan, el de cambio a HDMI ya es un poco “refrito y prueba”. Ayudado por la página: http://www.cec-o-matic.com/ “4” sería “fuente: playback 1”; “f”: “destino: broadcast”; “82”: “Used by a new source to indicate that it has started to transmit a stream OR used in response to a “Request Active Source” (Brodcast)”; y “11:00”: “physical address” que por lo que tengo entendido, con esos valores corresponde a HDMI 1 que es donde está pinchada la Raspberry.

Así que, con un poco de deducción y otro poco de la técnica que usó el burro del cuento para hacer sonar la flauta, el caso es que la tele se enciende, se apaga y conseguimos pasarla al HDMI que nos interesa. Así que nuestro if para apagar tiene que quedar así:

De paso añadimos también el apagado de pantalla si salimos con una opción que no sea la 003:

Y por supuesto añadimos el encendido de pantalla al principio del fichero con las dos instrucciones mencionadas: la de encendido y la de conmutar a HDMI 1

Y si esto tampoco funciona, entonces el asunto ya se nos complicaría un poco. Tendríamos que programar una salida del GPIO para que activara un relé que cerrara el paso de corriente de la pantalla, y que esta se encendiera cuando se activara el relé y se apagara cuando el relé le cortara la corriente. Pero ojo, además necesitaríamos que al encender así, a lo bruto, la pantalla se activara completamente y no quedara en standby que es como muchas suelen quedar si las desenchufamos a las bravas y las volvemos a enchufar, de ser así, de quedarse en standby, ya nos podemos ir olvidando porque no tendremos más remedio que usar el mando a distancia al no poder controlarla por HDMI de ninguna manera.

Y habréis visto que en el script hemos configurado el horario de apagado de las pantallas, pero no el de encendido. Eso lo haremos con crontab y lo trataremos en la siguiente entrada, pero antes de pasar a ella nos queda todavía algo pendiente ¿cómo actualizamos los archivos de fechas en la Raspberry? Necesitamos otro script.

Actualización de fechas en la Raspberry

Este va a ser fácil, será una modificación del script actualiza.sh La Raspberry comprobará si existe alguna diferencia entre los ficheros almacenados en las carpetas dias del servidor y la Raspberry, tal como se hace con los archivos a proyectar. La única diferencia es que aquí prescindiremos de la opción -delete y no borraremos nada .

Bueno, hay más diferencias, el script sólo nos mandará un correo si realiza alguna actualización en los archivos, en caso contrario no nos molestará. Lo que sí que hará será guardar la fecha y hora de cualquier actualización o comprobación exitosa, en un fichero que llamaremos calendario.txt, así, ante cualquier duda, podremos pedir un test y sabremos cuando se han actualizado o verificado estos archivos. En proyecta.sh lo integraríamos así:

Fragmento de “proyecta.sh”. Hemos insertado en las líneas 66 y 67 la información relativa a la fecha y hora de la actualización o verificación de los ficheros de fechas

Vamos ya con el script para actualizar el calendario, le llamaremos actualizadia.sh

Script muy sencillo para la actualización de los ficheros de fechas en la Raspberry. La verdad es que podría estar más currado, con algún control para verificar que todos los archivos necesarios existen en el servidor, las fechas están actualizadas, etc. pero en fin, eso lo dejaremos para una posterior actualización.

Vemos que la conexión y la actualización se realiza como ya hemos visto antes, aunque con las carpetas de los calendarios. En la línea 11 se graba la fecha si la actualización o verificación ha sido correcta y luego en la línea 18 al comparar los contenidos de los ficheros que contienen el antes y el después, sólo se mandará un mail si existe alguna diferencia.

Este script haremos que se ejecute diariamente a eso de las 6 am, a fin de que no interfiera con ninguna tarea.

Aquí está el código para copy&paste:

#!/bin/bash
nombrepantalla=$(hostname)
correo="[email protected]"
#Volcamos el contenido de los ficheros de "dias" en dias.old
cat /home/pi/dias/* > /home/pi/dias.old
rsync -rtvu --timeout=60 -e "ssh -i /home/pi/.ssh/miclave" [email protected]:/home/pi/datos/dias/ /home/pi/dias/
if [ $? -eq 0 ]
#Si no hay errores apuntamos en calendario.txt la fecha de comprobación
then
	resultado="Actualización calendario correcta"
	date > calendario.txt
fi
#Volvemos a volcar el contenido de los ficheros de "dias" esta vez en dias.new
#y comparamos los ficheros, si hay diferencias mandamos un correo
#así sólo se enviará un correo cuando haya una actualización exitosa
#y que modifique alguno de los archivos
cat /home/pi/dias/* > /home/pi/dias.new
diff -q /home/pi/dias.old /home/pi/dias.new > /dev/null
if [ $? -ne 0 ]
then
	hostname -I > /home/pi/ip.new
	cp /home/pi/ip.new /home/pi/ip.old
	printf "$resultado en $nombrepantalla\n\n" > /home/pi/report.txt
	printf "\nIp: " >> /home/pi/report.txt
	cat /home/pi/ip.new >> /home/pi/report.txt
	printf "\nActualizado a: " >> /home/pi/report.txt
	cat /home/pi/calendario.txt >> /home/pi/report.txt
	mutt -s "$resultado en $nombrepantalla" $correo < /home/pi/report.txt
fi

Para terminar, aquí está el código actualizado del script proyecta.sh con los últimos cambios que hemos visto en esta entrada:

#!/bin/bash
#Establecemos en estas variables:
#El nombre de la pantalla a gestionar
#El correo donde mandar los informes
#La variable $ejecuta: bucle, salir, apagar...
nombrepantalla=$(hostname)
longitud=${#nombrepantalla}
correo="[email protected]"
ejecuta="bucle"
#Almacenamos en la variable $apaga la hora de apagado según el tipo de día
case $1 in
	'N') apaga=2000 ;;
	'M') apaga=1500 ;;
	'S') apaga=1300 ;;
esac
#Encendemos la pantalla y seleccionamos HDMI 1
echo on 0 | cec-client -s -d 1
echo 'tx 4f:82:11:00' | cec-client -s -d 1
#Ocultamos el cursor
echo -e "\e[?1;0;0c"
clear
#Ejecutamos el bucle mientras $ejecuta sea "bucle"
while [ $ejecuta = "bucle" ]
do
#Comprobamos la hora para apagar la pantalla
#Si la sobrepasa cambiamos el valor de la variable $ejecuta y salimos del bucle
#Fuera del bucle compararemos el valor de la variable y apagaremos
quehora=$(date +%H%M)
if [ $quehora -gt $apaga ]
then
	ejecuta="fin"
	break
fi
#Refrescamos el directorio
cd .
#Recorremos el directorio
for file in /home/pi/Videos/*
do
#Metemos en variable el nombre y la extensión
extension="${file##*.}"
filename=$(basename $file)
fname="${filename%.*}"
#A continuación usaremos nombres de archivo que reservaremos para ejecutar diversas acciones
#Si el nombre coincide con el nombre de la pantalla pararemos el bucle
#borraremos el fichero y luego ejecutaremos la acción relacionada
if [ $fname = $nombrepantalla ]
	then
		ejecuta=$extension
		rm $file
		break
#Si el fichero comienza por XXX pero a continuación no se encuentra el nombre
#de la pantalla, lo ignoraremos.
elif [ ${fname:0:3} = "XXX" ] && [ ${fname:3:$longitud} != $nombrepantalla ]
	then
		:
#Si el nombre del fichero es test preparamos un informe que nos diga
#los ficheros que contiene el directorio, IP y la hora de actualización
elif [ $fname = 'test' ]
	then
		printf "Test de $nombrepantalla\n\nArchivos en directorio:\n\n" > /home/pi/report.txt
		ls /home/pi/Videos >> /home/pi/report.txt
		printf "\nIp: " >> /home/pi/report.txt
		hostname -I >> /home/pi/report.txt
		printf "\nActualizado a: " >> /home/pi/report.txt
		cat /home/pi/actualizacion.txt >> /home/pi/report.txt
		printf "\nActualizado a: " >> /home/pi/report.txt
		cat /home/pi/calendario.txt >> /home/pi/report.txt		
		mutt -s "Test $nombrepantalla" $correo < /home/pi/report.txt
		rm $file
#A partir de aquí suponemos que ya son ficheros para proyectar
#Si el fichero tiene extensión jpg lo mostramos en pantalla la duración establecida
elif [ $extension = 'jpg' ]
	then
		clear
		fim $file -a -c '{sleep 20;quit;};'
		clear
#En cualquier otro caso asumimos que se trata de un video y lo reproducimos
#Por defecto, al ser pantallas informativas,
#reproduciremos el vídeo sin sonido
#Si queremos sonido basta con poner al final del nombre de archivo AAA justo antes del punto de la extensión
else
	if [ ${fname: -3} = "AAA" ]
	then
		omxplayer  -b --blank --aspect-mode letterbox "$file" > /dev/null
	else
		omxplayer  -b --blank --aspect-mode letterbox --vol -6000 "$file" > /dev/null
	fi
fi
done
done
#Si salimos del bucle puede ser por algún fichero del tipo
#nombrepantalla.extensión y la extensión la tenemos en variable ejecuta
#La extensión deberá ser 001, 002, etc y según sea se ejecutará lo siguiente:
#Si es 001 apagamos la Raspberry
if [ $ejecuta = '001' ]
then
	sudo shutdown -h now
#Si es 002 reiniciamos:
elif [ $ejecuta = '002' ]
then
	sudo shutdown -r now
#Si es 003 borramos
elif [ $ejecuta = '003' ]
then
	clear
#Si hemos salido porque hay que apagar la pantalla:
elif [ $ejecuta = 'fin' ]
then
	echo standby 0 | cec-client -s -d 1
#En cualquier otro caso termina el script y borramos la pantalla
else
	clear
	echo standby 0 | cec-client -s -d 1
fi
#Podemos ir añadiendo las condiciones que queramos con elif
#Debemos evitar los ficheros de imagen y video con el nombre de la pantalla
#o el script se detendrá

Ficheros tratados en esta entrada

Listados con fechas

    • mananas.txt: fichero de texto con los días de apertura matinal
    • festivos.txt: fichero de texto con los días festivos
    • sabados.txt: fichero de texto con horario de sábados

Fichero de control de actualización de fechas

    • calendario.txt

Scripts

    • fecha.sh: script que activa o no proyecta.sh con argumento
    • actualizadia.sh: script que actualiza los calendarios de días en la Raspberry
    • proyecta.sh: modificación del script principal