Domotizando X – Riiiiing – (Parte 2: Soft)

Pues vamos con la segunda parte de la instalación del timbre-telegram…

Hablemos un poco del tema programación.

Como ya dije en la anterior entrada, parecía que no iba a entrañar mucho problema toda la parte de programación ya que básicamente me hice a la idea de que tendría que ser un proceso que estuviera esperando un flanco (ya sea negativo o positivo) en la entrada GPIO 17 de la raspberry.

raspberry-pi-15.jpg

Arriba vemos el conexionado que hice de la raspberry corregido, ya que al principio como dije, conecté el cable verde a 3.3V y el gris a a GPIO17 (igual debería haberlo metido en el apartado de hard, pero bueno, supongo que hasta hoy no me apetecía hacer el dibujo en el paint…).

Por cierto, el módulo de relés que aparece en la foto no es el módulo RF que uso para el timbre pero bueno, los relés sí son prácticamente idénticos.

Dicho esto entremos por fin en materia:

Captura de pantalla 2016-08-08 a las 17.21.01.png

Como ya comenté, partí de un programa ejemplo que encontré por internet en el que hacía uso de entradas/salidas GPIO de la raspberry programadas en C. La URL a dicha página creo que la puse, la repito:

https://learn.sparkfun.com/tutorials/raspberry-gpio/c-wiringpi-example

Para instalar las librerías y demás solamente hay que seguir el tutorial que viene en la página, bastante sencillo, simple y cómodo.

Después de esas declaraciones y cabeceras de la captura anterior viene el bucle en cuestión:

Captura de pantalla 2016-08-08 a las 17.23.47.png

Antes de entrar en el bucle (no lo he puesto) vemos que hay un memoria_old = digitalRead(butPin). Esto es para inicializar el valor de “memoria_old” para hacer un flanco después de que se detecte el primero y no con el valor basura que nos viene de la declaración de memoria_old.

Como dije, al final opté por utilizar hilos (threads) para este propósito porque me estaba dando problemas el cliente de telegram en consola de comandos. Este cliente como dije en la primera parte, no está muy fino y si le maltratas un poco te hace alguna perrería que otra.

Para instalarlo basta acudir al repositorio GitHub que puse en el post de la parte I y seguir las instrucciones. No me voy a meter ahi porque es un coñazo y no viene a cuento. Sólo diré que me tardó LA VIDA en compilar en la raspberry…

Volviendo al tema. En un principio, cuando no hice con hilos, el programa se quedaba trabado en el while en la llamada a la función de ‘telegram-cli’ (porque antes esta llamada no estaba en un hilo, sino en el propio while) que es la función que manda el mensaje como tal al móvil. Se ejecutaba una vez el envío del mensaje, y como hacía muchos envíos seguidos (deduje que sería por eso…) se quedaba ‘pillao’ en algun envío y no volvía a mandar más mensajes.

Se me ocurrió, para solucionar esto, que ‘tal vez’ si hacía la llamada en uno hilo, hacer que si tras un timeout no respondía (es decir, si tras x segundos, el hilo no terminaba su ejecución) yo lo mataría desde el proceso principal.

Para hacer todo esto que he explicado definimos la variable global: “hilo_running”

if (memoria_old != digitalRead(butPin) && hilo_running == 0){
...
}

Si detectamos flanco (primer != del if) y ademas, el hilo que envía los mensajes a telegram NO está funcionando, entonces procedemos con la ejecución del tinglado.

Esto es así, porque si no compruebo que el hilo está ejecutándose y hago una segunda llamada a otro hilo el cliente de telegram se queda tonto y me  puede dejar hilos por ahí danzando en memoria…

Si se cumple que no hay ningun hilo anterior ejecutando procedo con la creación de un hilo:

err = pthread_create(&hiloEscribirMensajes, NULL, &escribirMensajes, NULL);
if (err == 0){
    hilo_running = 1;
    contador = 1;
}
memoria_old = digitalRead(butPin);

Compruebo que el hilo se ha creado bien (error == 0) y si es así, pongo hilo_running a TRUE (1) y contador lo igualo a 1 para algo que vamos a ver en un momento.

Además de eso hago que memoria_old sea igual al valor actual de la entrada digital para detectar un posible nuevo flanco positivo/negativo.

Luego entraremos en detalle en el hilo, de momento seguimos en el proceso principal (main):

if (memoria_old != digitalRead(butPin) && hilo_running == 1){
    memoria_old = digitalRead(butPin);
}

Esto lo pongo aquí para por si está ejecutandose el hilo que envía los mensajes y se pulsa de nuevo al timbre (detecta otro flanco) para dejar memoria_old con el mismo valor y que no vengan problemas de que, al acabar la ejecución del hilo, justo la entrada digital este en la posicion invertida a como estaba cuando se llamó al primer hilo, lo que provocaría que se ejecutase otro hilo de seguido. Con esto, esa situación se previene.

if (contador != 0){
    contador++;
    if (hilo_running == 0)
       contador = 0;
}

Si contador es diferente de 0 significará que habremos iniciado un “temporizador” ya que ha habido una ejecución de un hilo. Si resulta que de repente el hilo ya no está running… no me interesará hacer un timeout del hilo ya que sabremos con certeza que no hay ninguno corriendo (ya sea porque ha terminado de ejecutarse o porque le hayamos matado desde el main), así que pondremos de nuevo contador a su estado inicial: 0.

if (contador > 25){
    if (hilo_running == 1){
       err = pthread_cancel(hiloEscribirMensajes);
       if (err == 0){
           hilo_running = 0;
       }else{
           printf("**** ERROR EN LA CANCELACION DEL THREAD!\n");
       }
    }
    contador = 0;
}

delay(1000);

Aqui es donde hacemos el timeout del hilo, por si tarda mucho en acabar de ejecutarse.

Como hay un delay(1000) en cada iteracion del bucle infinito 25 serán más o menos 25 segundos de margen de tiempo para que se termine de ejecutar el hilo (es ajustable y posiblemente baje este valor ya que está a modo de prueba).

Lo que hacemos es que si el contador es mayor que 25 (segundos) y el hilo estaba en ejecución, matamos al hilo (pthread_cancel) y si sucede algún error lo imprimimos por pantalla a modo debug.

Además de eso, reseteamos el contador a 0.

Vamos con el programa que ejecuta el hilo:

void *escribirMensajes(void *arg)
{
        system("telegram-cli -W -e \"msg ****** TIMBREE!\"");
        delay(2500);
        system("telegram-cli -W -e \"msg ****** TIMBREE!\"");
        delay(2500);
        system("telegram-cli -W -e \"msg ****** TIMBREEEE!!\"");
        delay(3500);
        system("telegram-cli -W -e \"msg ****** TIMBREEEE!!\"");
        delay(8000);

        printf("SALIENDO DEL THREAD DE LOS MENSAJESSS\n");
        hilo_running = 0;

        return NULL;
}

No creo que tenga mayor complejidad este hilo, si acaso por la cadena que se le pasa a system (que básicamente ejecuta una instrucción de bash.

telegram-cli -W -e "msg ****** TIMBREE!"

Como tal, la instrucción en bash que manda un mensaje al contacto ****** es esta de aquí arriba (en la parte de programación tiene las ” escapadas con ‘\’ para que las escriba en la terminal bien).

Y aquí es donde radica el mayor problema del programa y que realmente NO he solucionado aun… Por eso tiene delays por en medio. Es debido a que hacer muchas llamadas al cliente de telegram, hace que se bloqueen algunas y se quedan perdidas por ahí en memoria, ejecutandose en segundo plano …

Si logro encontrar la solución a este problema ya lo actualizaré por aquí. Pero de momento tiene que ir así… con esos delays…

El tema del hilo soluciona ‘un poco’ la papeleta porque al menos, no se bloquea la ejecución de llamadas al cliente de telegram… Se me ocurrió lo de incluir hilos porque asumí (mal) que al matar al hilo, mataría también las ejecuciones de system() que tiene dentro, pero esto parece que no es asi …

Así pues, podríamos decir que está aun madurando el programa aún… y que está algo verde igual pero bueno, de momento funciona y es más que suficiente… Supongo que podré ajustar más los tiempos hasta encontrar el punto óptimo en el que no se bloquee el cliente.

Veremos a ver si actualizo este post con mejoras para el sistema del timbre….

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s