El autómata celular Ulam-Warburton (UWCA) genera un patrón fractal bidimensional usando autómatas celulares con vecindad de von Neumann con dos estados: encendido y apagado. Comienzan con una celda encendida(generalmente el central) y los demás apagadas. La regla que genera el autómata es muy sencilla, si tienes un único vecino encendido cambias tu estado a encendido. Cuando una celda se enciende ya no se apaga. Por motivos de visualización se puede añadir un nuevo estado que sería «recién encendido» ese estado lo tienen las céldas que acaban de cambiar de estado y solo dura un ciclo antes de cambiar a encendido.
En el ejemplo cada estado viene indicado con un color:
Veamos algo de teoría, a partir del segundo ciclo el número de celdas nuevas en cada ciclo sigue esta formula:
Donde wt corresponde a :
¿Cómo calculamos el sumatorio hasta infinito? Vamos a hacerlo de una forma matemáticamente poco elegante y burda pero fácil de entender. Como 2^k crece muy rápido vamos a calcular el sumatorio solo de los primeros 30 valores (y con menos también serviría).
Debajo dejo el código JS para calcular el valor de wt y de u:
function sumWt(n, k){
if(k == 0) {
return 0;
} else {
return sumWt(n, k-1)+Math.floor(n/Math.pow(2,k))
}
}
function wt(n){
return n - sumWt(n, 30) //calcular hasta k = 30;
}
function u(n){
return 4/3 * Math.pow(3, wt(n-1));
}
Si wt tiene ciclos significa que el número de celdas nuevas (u()) también lo tiene.da igual lo que haya crecido al estructura de celdas activas, habrá un punto en que solo haya 4 y siempre se repetirán los mismo números: 4,4,12,4,12,12,36,4,12,….
En la gráfica de número de celdas nuevas se puede ver esta repetición de subidas y caídas:
Este numero de repeticiones esta ligado con su estructura fractal.
El autómata celular Ulam-Warburton original usa la vecindad de von Neumann pero presenta un comportamiento similar usando la vecindad de Moore, si bien cambia el patrón:
Vamos a empezar este texto develando el truco que usaremos para representar incertidumbre con la regresión lineal para Arduino y que se basa en emplear la versión con pesos del algoritmo de regresión lineal. La incertidumbre estará representada como valores con una variación de pesos según la certeza que tengamos de su valor. Usaremos el peso como porcentaje de certeza de ese dato
Esta no es la mejor ni la única manera de hacerlo. No hay que olvidar que aquí se trata de hacerlo en algo tan limitado en memoria y potencia como pude ser un Arduino UNO.
Usaremos la librería regressino, en concreto su librería para regresión lineal:
#include <LinearRegression.h>
LinearRegression lr = LinearRegression();
Una forma de incertidumbre es cuando directamente tenemos valores de los que «nos fiamos» menos que de otros. Por ejemplo, porque vienen de dos fuentes distintas. En este caso los datos menos fiables tendrán que tener un peso más bajo que los más fiables para que su influencia sobre el resultado final sea menor.
Pero hay otro caso de incertidumbre, cuando no conocemos el valor del dato con seguridad, lo que conocemos son los valores entre los que está comprendido. Generalmente tenemos dos valores, un mínimo y un máximo o tres valores con uno más probable y un mínimo y un máximo (a veces representados como errores) entre los que ese valor puede variar. En este caso tenemos que definir cómo se distribuye el peso (probabilidad) entre estos valores. Hay que recordar que la suma total de los pesos tiene que ser igual a 1.
Una vez definida la forma en que se distribuye la probabilidad hay que descuartizarla en puntos. La idea es que esto funcione en un Arduino UNO y no podemos trabajar directamente con funciones de probabilidad.
Supongamos que para x = 10 sabemos que el valor de y está comprendido entre 2 y 3. Ahora hay que saber cómo está distribuida la probabilidad entre esos dos valores. Veamos algunas posibilidades:
Toda la probabilidad se concentra en cada uno de esos valores por lo tanto el 2 tendría un 50% de certeza y el 3 otro 50%. O lo que es lo mismo un peso de 0.5
lr.learn(10, 2, 0.5);
lr.learn(10, 3, 0.5);
La probabilidad se distribuye de forma uniforme por todo el espacio entre esos dos puntos. Para representarlo tómanos varios puntos entre 2 y 3 y les asignamos a todos la misma probabilidad.
Ya hemos vistovarias formasde extender las capacidades de la regresión lineal en Arduino. En este caso vamos a asociar pesos a los valores para que no todos los casos aporten los mismo al resultado final. Pero qué significa «aportar» más al resultado, de forma gráfica podríamos imaginarnos que los puntos de mayor peso atraen más a la recta de la regresión lineal por lo que esta tiende a acercarse más a estos. La utilidad de este sistema es cuando tenemos resultados que por algún motivo valoramos más que otros.
Vamos a modelar el peso como un valor entre 0 y 1. De tal forma que el peso máximo corresponda con 1 y el mínimo con 0. A mayor peso más «aporta» ese valor al resultado. Entre dos valores uno con peso 1 y otro con peso 0.5 el primer cuenta el doble que el segundo. Cuando el peso es 1 no hay diferencia con la regresión lineal sin pesos. Y cuando el peso es cero el valor no va a aportar nada al resultado.
Como ya hemos visto en otro post vamos a usar «el truco» que consiste en transformar el valor de x e y que se le pasa a la función que calcula la regresión lineal (learn). Podríamos verlo como que el valor de x se usan para modificar el valor de meanX y meanX2 y el de y para meanY y meanY2. Entonces si w es el peso:
Si el peso es 1 x e y no cambian su valor
Si es 0 x e y no tienen que afectar a los valores de meanX y meanY para que pase eso el valor de x ha de ser igual que meanX y el de y igual a meanY.
Si el peso este entre 0 y 1 el valor ha de componerse con el valor de x e y y el valor de las medias de cada uno.
Para conseguir eso vamos a ponderar el valor de la x y el de meanX según w
x = x*w + meanX*(1-w);
y = y*w + meanY*(1-w);
Solo queda añadir un par de comprobaciones para evitar que el valor pueda ser mayor de 1 o menor de 0:
Por último comentar que hay dos posible optimizaciones que se podrían aplicar si fuera necesario y que nos permiten ahorrar algunos cálculos si hay muchos pesos cercanos a 0 o a 1:
Los pesos muy cercanos a 0 se ignoran
Los pesos muy cercanos a 1 se tratan como si no tuvieran peso
Hay una pequeña pérdida de precisión pero en el caso de tener muchos datos puede compensar al reducir el tiempo de cálculo.
Uno de los puntos débiles de las placas más básicas de Arduino es la gestión de errores, siguen la política de «nunca me equivoco» de tal forma que acciones o código que en otros sistemas lanzarían error no producen ninguno en Arduino.
Un excepción es un mecanismo en el software que «salta» cuando se produce un error y permite que el software ejecute una rutina de gestión de errores que se ocupa de gestionarlo para después recuperar su funcionamiento normal, si es posible. Arduino no permite usar el mecanismo habitual de C++, las instrucciones try y catch. Es posible usarlas en el código sin que den error al compilar pero durante el proceso de compilación se desactiva su funcionamiento. No es algo que se haga de forma arbitraria, simplemente no funcionan en Arduino. Si embargo vamos a tratar de conseguir un mecanismo similar que nos permite una gestión de errores muy básica . Para ello emplearemos dos funciones (setjmp y longjmp) y un tipo de variable (jmp_buf). esta funciones permiten establecer un punto de salto dentro de una función al que se puede ir desde cualquier parte del programa:
setjmp – establece el punto donde se va recuperar la ejecución del programa hay que pasarle como parámetro una variable de tipo jmp_buf.
jmp_buf – es un tipo de variable que almacena la información necesaria para restaurar la ejecución del código en el punto indicado por setjmp.
longjmp – salta al punto establecido por setjmp. Requiere dos parámetros uno de tipo jmp_buf que indica a que setjmp va a saltar y otro que indica el código de error que va devolver setjmp tras el salto. Este código nunca puede ser 0 si se usa 0 devolverá 1.
Ahora veamos como se usa, para entenderlo bien el código hay que saber los siguientes detalles:
Es necesario incluir la librería setjmp.h
setjmp la primera vez que se llama se usa para fijar el punto de salto y devuelve el valor cero
Cuando se llama a longjmp es como si el programa continuara desde donde se llamo a setjmp pero en lugar de devolver 0 devuelve otro valor
Para que esto funcione correctamente setjmp tiene que estar dentro de un if o un switch.
Para que todo funcione correctamente setjmp ha de fijar el punto de salto dentro del loop, si lleva a otras funciones puede fallar al llegar al final de la función donde ha saltado
En el caso más simple solo tenemos un tipo de errores y por tanto cada vez que se produce un error la forma de gestionarlo es siempre la misma. Para ello basta con usar un if.
#include <setjmp.h>
jmp_buf exception_mng;
int a = 5;
int b = 1;
int c;
void setup() {
Serial.begin(9600);
}
void loop() {
if (setjmp(exception_mng)) { //si se produce error
Serial.println("EXCEPTION");
}
a--;
divide();
delay(1000);
}
void divide(){
if(a == 0){
longjmp(exception_mng, 1);
}
c = b/a;
Serial.print(b);
Serial.print("/");
Serial.print(a);
Serial.print(" = ");
Serial.println(c);
}
Una versión más avanzada permite gestionar distintos tipos de incidencias según el valor que se le pase a longjmp como segundo parámetro
#include <setjmp.h>
jmp_buf exception_mng;
int a = 5;
int b = 1;
int c;
void setup() {
Serial.begin(9600);
}
void loop() {
switch (setjmp(exception_mng)) {
case 0: //sin errores
break;
case 1: //division por cero
Serial.println("EXCEPTION DIVISION BY 0");
break;
case 2: //divisor negativo
Serial.println("EXCEPTION DIVISION BY NEGATIVE NUMBER");
break;
default: //se ejecuta cuando no se cumple ninguno de los casos anteriores
Serial.println("GENERIC EXCEPTION");
break;
}
a--;
divide();
delay(1000);
}
void divide(){
if(a == 0){
longjmp(exception_mng, 1);
}
if(a < 0){
longjmp(exception_mng, 2);
}
c = b/a;
Serial.print(b);
Serial.print("/");
Serial.print(a);
Serial.print(" = ");
Serial.println(c);
}
Este sistema nos dota de un mecanismo básico de gestión de errores aunque nos obliga a nosotros a realizar la comprobación para lanzar la «excepción».
Este texto mejorado y ampliado forma parte de mi libro sobre como mejorar tus programas en Arduino. Puedes echarle un vistazo aquí.
Puedes ver el vídeo sobre el tema en mi canal de Youtube:
Haz click para ver el vídeo en mi canal de Youtube
Vamos a ver cómo funciona chicote un generador de código basado en plantillas. Hace tiempo tuve que hacer un trabajo muy repetitivo de migración de código de una tecnología a otra, al final el 90% del trabajo era repetitivo. No tan simple como copiar y pegar, pero nada que requiriera demasiado cerebro. Para esos casos cree chicote. Chicote es el nombre de un famoso chef español. Por eso el uso de términos relativos a la cocina.
Vamos a ver de que consta este sistema.
Motor de plantillas
Lo primero que necesita un generador basado en plantillas es un motor de plantillas que genere texto a partir de una plantilla.
Para este caso opte por mustache.js que es simple, ligero y muy fácil de aprender. Además permite personalizar varios aspectos que necesitaba.
Una de sus principales limitaciones es que no se le puede pasar «parámetros» a las etiquetas, para resolverlo tuve que modificar el código añadiendo esa posibilidad.
Operadores de texto
Otra cosa necesaria para generar código amigable para los seres humanos es poder operar sobre el texto. Es habitual que el mismo nombre se escriba en capital, mayúsculas, minúsculas, separado por guiones,… Los programadores somos unos maniáticos de esto y definimos documentos de estilo solo para especificar este tipo de cosas.
Para esto elegí dos librerías voca.js y pluralize.js y transforme sus operaciones en etiquetas que se puedan usar desde la plantilla.
Además son útiles funciones que actúen a nivel de línea para ordenarlas, limpiar espacios, eliminar líneas duplicadas o tabularlas.
Generador de datos falsos
Los datos falsos con cierta estructura son útiles para generar test, plantillas o demos. En este caso recurrí a la librería faker.js
Algunas ayudas más
Finalmente añadí alguna ayuda más con función habituales en programación como la fecha, la hora, un timestamp, números aleatorios o un contador
Directorios y ficheros
Otra necesidad de los generadores de código programador es poder generar directorios y nombres de archivos con algún tipo de plantilla. Es muy habitual usar la estructura de directorios para organizar el código.
El cocinero (Chicote)
Chicote es un generador agnóstico de código basado en plantillas. Es agnóstico puesto que sirve para cualquier lenguaje que use ficheros de texto. Necesita NodeJS para funcionar. No necesitas instalar nada, sólo descargar el código y ejecutar cooking.js
node cooking.js
La salida se genera en el directorio output
La receta (recipes.json)
Necesitas crear un archivo recipes.json, que contiene una o mas recetas, cada receta contiene todos los ingredientes y pasos para generar código. El único apartado obligatorio en cada receta es steps ,un array con donde se indican que pasos (steps) tiene que ejecutar para realizar la receta. Un step es el nombre de un archivo JSON en el directorio steps.
Ejemplo de fichero recipes.json con solo una receta:
Un step es un archivo JSON en el directorio «steps» donde se preparan los ingredientes. Un paso tiene tres partes: variables (vars), directorios (directories), plantillas (templates)
vars son variables creadas a partir de los ingredientes. Actúan de forma similar a los ingredientes.
directories indica los directorios de salida.
plantillas archivos de texto en el directorio de plantillas. Se compone de un array de dos cadenas de texto, la primera indica la ruta de la plantilla en el directorio templates, la segunda la ruta del fichero generado en el directorio output
Se pueden usar los tags que más adelante veremos para calcular lo valores de estos apartados.
Las plantillas son archivos de texto en el directorio «templates» que utilizan la sintaxis de mustache pero con algunas «etiquetas especiales».
{{timestamp}}
{{date}} - fecha en formato yyyy-mm-dd
{{time}} - hora en formato hh:mm:ss
{{year}} - año
{{month}} - mes
{{day}} - dia
{{hour}} - hora
{{minute}} - minuto
{{second}} - segundo
{{GUID}}
{{#plural}}text{{/plural}}
{{#camel}}text{{/camel}}
{{#capital}}text{{/capital}}
{{#decapital}}text{{/decapital}}
{{#dash}}text{{/dash}}
{{#snake}}text{{/snake}}
{{#swap}}text{{/swap}}
{{#title}}text{{/title}}
{{#lower}}text{{/lower}}
{{#upper}}text{{/upper}}
{{#slug}}text{{/slug}}
{{#reverse}}text{{/reverse}}
{{#stripTags}}text{{/stripTags}}
{{#escHtml}}text{{/escHtml}}
{{#unHtml}}text{{/unHtml}}
{{escRegExp}}text{{/escRegExp}}
{{#trim}}text{{/trim}}
{{#latin}}text{{/latin}}
{{#count}}text{{/count}} - reemplaza texto por número de caracteres
{{#countWords}}text{{/countWords}} - reemplaza el texto por el número de palabras
{{#delSpaces}}text{{/delSpaces}} - suprimir todos los espacios
{{#delDuplicateSpaces}}text{{/delDuplicateSpaces}} - eliminar los espacios duplicados
{{#delLast|C}}text{{/delLast|C}} - suprimir la última coincidencia de caracteres C
{{#delFirst|C}}text{{/delFirst|C}} - suprimir la primera coincidencia de caracteres C
{{#delEnd|N}}text{{/delEnd|N}} - suprimir N caracteres del final
{{#delStart|N}}text{{/delStart|N}} - del N caracteres desde el inicio
{{#repeat|N}}text{{/repeat2|N}} - repetir el texto N veces
{{#sortAscL}}text{{/sortAscL}} - ordenar las líneas de forma ascendente
{{#sortDescL}}text{{/sortDescL}} - líneas de ordenación descendente
{{#naturalSortAscL}}text{{/naturalSortAscL}} - líneas de ordenación natural ascendente
{{#naturalSortDescL}}text{{/naturalSortAscL}} - líneas de ordenación natural descendente
{{#shuffleL}}text{{/shuffleL}} - barajar líneas
{{#trimL}}text{{/trimL}} - recortar líneas
{{#joinL}}text{{/joinL}} - unir líneas
{{#removeDuplicateL}}text{{/removeDuplicateL}} - eliminar líneas duplicadas
{{#spaceL|N}}text{{/spaceL|N}} - Añadir N espacios al principio de cada línea
{{#tabL|N}}text{{/tabL|N}} - Añadir N tabulaciones al principio de cada línea
{{#addStartL|C}}text{{/addStartL|C}} - Añadir el carácter C al principio de cada línea
{{#addEndL|C}}text{{/addEndL|C}} - Añadir el carácter C al final de cada línea
{{#log}}text{{/log}} - escribir texto en la consola
{{#eval}}text{{/eval}} - evalúa el texto como código JS
{{#R}}texto{{/R}} - renderizar texto
{{#C=|N}}{{/C=|N}} - poner el contador en N
{{#C+|N}}{{/C+|N}} - aumentar el contador en N
{{#C-|N}}{{/C-|N}} - reducir el contador en N
{{#C}}{/C}} - imprimir el contador
{{#K}}texto{{/K}} - cargar datos de la base de conocimiento (cookbook.json)
{{!text}} - Comentario
{{#faker}}data{{\faker}} - genera un dato aleatorio usando faker.js
{{=AA BB=}} - Cambia los caracteres para indicar que es un tag de {{ }} to AA BB
Actúa como base de conocimiento para Chicote. Funciona como un sistema de clave valor.
Para leer los datos de la base de conocimiento se usan los tags {{#K}} y {{/K}}. Si tenemos {{#K}}texto{{/K}} texto será reemplazado por el valor que se encuentre en la base de conocimiento con la clave texto
Los eventos fundamentalmente sirven para notificar a otras funciones que están «escuchando» esos eventos que algo ha ocurrido. En las aplicaciones web estamos acostumbrados a usar eventos asociados a acciones del usuario como pulsar un botón, mover el ratón, hacer click, … Sin embargo podemos crear nuestros eventos asociados a cualquier acción que deseemos.
Para crear un evento solo necesitamos instanciar un objeto CustomEvent con el nombre del evento:
event = new CustomEvent("event");
Si queremos pasar parámetros tenemos que usar el campo detail:
La función recibe como parámetro un objeto event con todos los datos del evento. Para acceder a los datos que hemos incluido se puede acceder a valor detail del parámetro.
Veamos un ejemplo completo que convierte un click del ratón en dos eventos uno que se lanza las veces pares y otro las impares:
Los eventos permiten una fácil comunicación entre distintas partes de la aplicación. La parte que emite el evento se desvincula de quién está escuchándolo. A su vez los consumidores del evento escuchan o dejan de hacerlo cuando les interesa sin interferir entre ellos.
ESP32-Cam incluye un ejemplo bastante completo de servidor web embebido dentro de la placa. Por si solo puede resultar útil y estaría bien poder modificar la página, personalizarla, quitar opciones o añadir librerias js externas para ampliar su funcionalidad o traducirla. Con solo cambiar la web que incluye el ejemplo tenemos una camada WiFi con un servidor web embebido que nos permite acceder a la misma y sus funcionalidades en remoto. Es una opción muy interesante pero no hay demasiada documentación sobre como hacerlo.
La web se encuentra «escondida» en el código fuente del ejemplo «CameraWebServer» dentro del fichero camera_index.h. La web esta comprimida, para incluirla en el código fuente se ha incluido en forma de un array de bytes (uint8_t) cuyos valores están en hexadecimal.
En le fichero camera_index.h hay dos variables que almacenan la web:
const uint8_t index_ov2640_html_gz[]
const uint8_t index_ov3660_html_gz[]
Que web se usa depende del sensor de la cámara, lo más fácil es probar a reemplazar uno a ver cual devuelve tu placa.
Decodificar la web:
Hay dos maneras de hacerlo, la sencilla y la complicada. La sencilla es tan simple como entrar en la web y click en el botón derecho y «Guardar como…». Tambien se puede usar herramientas como wget o curl.
La complicada requiere ir al código fuente, seleccionar el código hexadecimal del que se compone el array y con él:
Eliminar todos los espacios, comas y saltos de linea
Convertir cada bloque de texto «0x**» en un número hezadecimal
Descomprimir el resultado que esta comprimido unsado gzip
Para facilitar las cosas he usado CybeChef para crear una receta de para decodificar la web la teneis aquí: decodificador . Solo hay que copiar el código hexadecimal que hay en el array y pegarlo en la parte de «input» automáticamente se obtendrá el código dela web en el «output».
Podemos usar esta web como base para nuestros cambios.
Codificar la web:
Una vez programada la web de reemplazo hay que hacer los pasos contrarios:
Comprimir la web usando el formato gzip
Convertimos cada carácter a bytes en hexadecimal en formato «0X**»
Cada carácter hexadecimal tiene que estar separado por una coma, si ademas añadimos un espacio y cada cierto numero de bloques un salto de linea quedara visualmente más atractivo.
También he programado un codificador para facilitar la tarea.
Vamos a ver como crear un «kiosko» a partir de una web con Raspberry Pi, una pantalla táctil y una pagina web que es la que queremos mostrar en nuestro kiosko. Lo que deseamos es que la web aparezca a pantalla completa y sin que el usuario pueda «escapar» de ella. En mi caso lo que deseaba mostrar era una web con el tiempo, un calendario y alguna información del ayuntamiento de mi ciudad. Para ellos bastaba con mostrar una pagina web alojada en la propia Raspberry con iframes para mostrar parte de la información. El problema era que se viera en toda la pantalla y no se pudiera salir accidentalmente (o intencionadamente) de la web.
Para ello existe en chromium y firefox (tambien en chrome aunque para Raspberry no este) el modo kiosko que muestra una página web a pantalla completa, sin barra de herramienta, direcciones, menú o cabecera. La forma de lanzarlo es asi:
La única forma de salir es con un teclado y pulsado alt+f4. En mi caso como no había teclado ya tenia mi kiosko seguro pero hay algunas cosas que hay que tener en cuenta según su uso para que el kiosko sea seguro:
Desactivar el recordar y autocompletar de campos
Nada de teclados
Si se tiene que poner un teclado mejor si es un teclado en pantalla, mejor aun si el teclado es parte de la web, por ejemplo este
El teclado ha de tener solo las teclas necesarias. No tiene que tener teclas «especiales» como control, alt, f1, f2,…
Asegurarse de que la web que se muestra no tiene enlaces que lleven fuera de la misma.
Bloquear los puertos USB para evitar que nadie los use. Si la conexión de red es por WiFi aquí se puede ver como hacerlo
Estas medidas hay que tenerlas en cuenta según el entorno del kiosko, no es lo mismo en una casa que en una tienda o en un lugar publico.
Aun así hay varios puntos de ataque:
Quitar la alimentación.
Quitar la conexión de red.
Quitar la alimentación eléctrica dejaría nuestra Raspberry apagada, el problema esta cuando vuelve, que por defecto se reinicia. Aquí tenemos que decidir porque opción optamos. Si mostrar una pantalla de login (mejor si es consola en lugar de interface gráfica) con usuario y password (ambos deben de ser seguros, nada de dejar los por defecto) y dejar el kiosko sin servicio. La otra opción es configurar el autologin y hacer que el kiosko se lance automáticamente cuando el desktop se inicie. Aquí se explica como hacerlo.
Al quitar la conexión de red (red de datos) el navegador mostrará una pagina de error. Al recuperar la conexión es posible que se quede esa página en lugar de volver a la que debería mostrar el kiosko. Hay una solución que es en lugar de cargar directamente la web remota poner un servidor web en la propia Raspberry Pi, que el navegador en modo kiosko cargue la pagina que sirva este servidor local y ella sea la que se muestren las distintas fuentes de datos. Al falla la conexión el servidor local sigue funcionando y permite tener cierto control sobre lo que ocurra.
Cuando queremos «ejecutar una aplicación al inicio» nos podemos referir a dos momentos distintos: al iniciar la Raspberry, al iniciar el escritorio. En el primer caso solo se pueden lanzar aplicaciones o script que no necesiten una «ventana» para funcionar mientras que el segundo se suele usar más para aplicaciones de escritorio.
Ejecutar una aplicación al iniciar la Raspberry Pi
Para esta tarea podemos recurrir a la herramienta crontab. Ya vimos su uso aqui. Siguiendo las indicaciones de ese posta bastaria con usar el comando:
crontab -e
Y luego añadir la entrada:
@reboot aplicacion
Donde «aplicacion» es la ruta y e lnombre de la aplicación, script o comando a lanzar.
Ejecutar una aplicación al iniciar el escritorio de Raspberry Pi
Hay que ir al directorio /etc/xdg/autostart y crear un fichero con el nombre que queramos pero terminado en .desktop el contenido del mismo ha de ser:
[Desktop Entry]
Name=Lanzo mi aplicacion
Exec=aplicacion
Terminal=false
Type=Application
El campo name puede ser una pequeña descripción de la aplicación y el campo exec contiene la ruta y el nombre de la aplicación a lanzar.
Debo señalar que hay más formas de realizar estas dos tareas y estas solo son dos de las más habituales y sencillas.
Vamos a ver como usar KDEConnect para crear una botonera en el móvil para interactuar con el ordenador y las aplicaciones. En principio es fácil ya que KDEConnect da la opción de «ejecutar órdenes» en el ordenador desde el móvil, basta con dar de alta el comando en el ordenador y aparecerá un botón en la aplicación para móvil que permita lanzarlo. Para ello hay que ir a la configuración de KDEConnect y luego a la configuración del plugin «Ejecutar órdenes». Ahí podemos dar de alta las nuevas órdenes indicando el texto que se mostrará en el botón en el móvil. Tenemos la limitación de que solo se puede introducir ordenes en una línea, si queremos lanzar varios comando uno tras otro tenemos dos opciones: crear un fichero de script y llamar a ese fichero, introducirlas en esa línea separada por «&&».
Ejecutar comandos en segundo plano:
Es el caso más sencillo, para ello podemos usar la opción «Ejecutar órdenes» que hemos comentado antes. Los comando se lanzan en segundo plano.
Ejecutar acciones en programas:
En este caso queremos realizar acciones sobre aplicaciones. Lo que significa que no siempre tendremos un comando que lo haga. Si por ejemplo queremos que al pulsar sobre un comando de la pantalla de nuestro movil se cambie el pincel de nuestra herramienta de dibujo seŕa necesario simular pulsaciones de teclado. Para casos más complicados es posible que tengamos que simular clicks de ratón. Para ello en Linux tenemos la herramienta xdotool que permite simular el teclado, el ratón, actuar sobre las ventanas del sistema y el escritorio.
Supongamos que queremos tener un comando que cada vez que pulsemos su botón correspondiente en el móvil simule que se teclea la fecha:
xdotool type $(date +"%d/%m/%y %H:%M")
O que pulse control + s para guardar el archivo que este editando:
xdotool key ctrl+s
Abrir una aplicación
Tenemos dos opciones usar xdotool exec o directamente usar el comando que lanza el programa. Por ejemplo para lanzar VLC:
vlc
xdotool exec vlc
Control multimedia
No hay que hacer nada, KDEConnect ya tiene un plugin para controlar la reproducción multimedia del PC desde el móvil.
Teclado y ratón remotos
Tampoco hay que hacer nada, KDEConnect ya permite usar la pantalla del móvil como ratón y el teclado remotos
Mostrar la respuesta en el móvil
Es posible que queramos que el comando lanzado nos devuelva algún mensaje diciéndonos si ah terminado y ha sido con esxito.Ya hay un post sobre este tema, puedes leerlo aquí.
Como ejemplo vamos a usar un comando que nos permite ver cuanto espacio nos queda en el disco:
Para que el resultado sea al más visual puedes añadir emojis como si fueran iconos. Puedes usar algún teclado de emojis web para copiarlos y pegarlos o instalar uno como emoji-keyboard. Puedes usar varios emojis y combinarlos con otros caracteres alfanuméricos.