Domotizando X – Riiiiiing – (… done)

Finalmente encontre la solución al problema que tenía. Resulta que escribir desde una terminal el comando que manda un mensaje por telegram hacía que si se hacían muchas llamadas seguidas, el cliente petase.

Intente arreglarlo con threads y el resultado “mejoro” algo pero habia que poner unos delays bastante elegantes.

El comando “screen” de linux me solucionó la papeleta.

La verdad es que he hecho bastante en el tema de domótica de casa desde que puse el último post pero bueno, me centraré un poco en el tema del timbre, ya habrá tiempo para entrar en otros temas 😉

La cosa es que quería mantener el cliente de telegram ejecutando constantemente en la raspberry. Yo no tengo pantalla así que siempre accedo por SSH con lo que para ejecutar el cliente de telegram…. tenia que hacerlo via SSH.

El problema de conectarse por ssh a un dispositivo es que en el momento que te desconectes cierra todo lo que tuvieras en ejecución…. stenyak me recomendó utilizar “screen” para solucionar ese problema.

Así pues, después de investigar cómo funcionaba, conseguí entenderlo 😛 (soy un poco lentito pa estas cosas si…) y ejecutando con screen el cliente….

Captura de pantalla 2016-08-26 a las 16.57.58.png

Captura de pantalla 2016-08-26 a las 16.56.47.png

se queda en segundo plano y yo puedo cerrar la terminal… una maravilla.

Vale, pero ¿y que? ahora como se puede hacer para usar *ese* cliente que tengo en segundo plano? pues esta todo pensado!! A screen se le puede pasar cadenas de texto para que las ejecute sencillamente haciendo:

Captura_de_pantalla_2016-08-26_a_las_17_01_15.png

Si se escribe desde la terminal directamente sólo hay que tener en cuenta lo que va entre “”. Yo tengo ‘system’ porque estoy ejecutandolo en un programa en C.

Y qué es lo guapo de esto?

Pues que se pueden hacer mil llamadas seguidas (es decir, escribir tantos comandos seguidos como ese) y NO PETA el cliente de telegram 😉 Una maravilla.

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. Solamente 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.

Para solucionar esto, se me ocurrió que ‘tal vez’ si hacía la llamada en uno hilo, si tras un timeout no respondía (es decir, si tras x segundos, el hilo no terminaba su ejecución) hacer un kill 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 además 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 ejecutado procedo con la creación de un nuevo 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, pondremos el contador a 0.

Vamos con el programa del 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….

Domotizando X – Riiiing! – (Parte 1: Hard)

Cuando entras a vivir en una casa normalmente el timbre te viene puesto; este era mi caso. No obstante, decidimos quitarlo por un par de motivos. Primero, es feo y saca el tipico ruido de timbre que estas a medianoche esperando al repartidor de pizzas y te da un ataque al corazón. Segundo, teníamos intenciones de poner una mirilla inteligente con un botón de llamada integrada para recibir en el movil la notificación de que había alguien en la puerta.

La segunda parte la llevamos a cabo y pusimos una mirilla inteligente; pero algún vecino se nos quejó… en parte normal y en parte… no sé, a mi no me parecería mal que un vecino pusiera una mirilla de este tipo en mi rellano… así que manías y paranoias de cada uno, supongo…

La cosa es que después de esta situación, estabamos sin timbre y hasta AYER no hicimos nada al respecto para remediarlo.

Se nos ocurrió que podíamos coger la idea de la mirilla original (aunque hayamos eliminado la mirilla) y llevarla al timbre. Así pues me puse manos a la obra porque tenía todos los materiales necesarios… Tengo mucha historia electrónica sin usar por ahi… jejeje.

La idea era utilizar un modulo de RF (de estos mandos para abrir puertas de garaje) conectado a la raspberry para que la raspberry emitiera un mensaje al movil avisando que han llamado al timbre. Problemas de esto: el módulo RF lo tengo (lo pillé en banggood). La conexión con la raspberry es trivial… solo hay que tomarse la molestia de hacerlo. El verdadero problema me supuso la interconexión Raspberry – Movil en un principio. Posteriormente te das cuenta que existe mucha gente que se le ha ocurrido ya la idea … xD y localizas repositorios como este:

Que solucionan bastante la papeleta 😉
Probé en una distro Ubuntu el repositorio y funcionaba, no se si bastante bien, pero funcionaba, pese a algunos problemillas que tuve.
Así pues empecé con el hardware:

Si desmontamos el mando nos encontramos con que lleva un par de pilas de boton de 3V y lo que hacen los botones es lo de casi siempre… utilizar una chapita que se comba cuando le pulsas para unir 2 pistas del circuito integrado. La solución para insertar aquí el timbre resulta evidente:

IMG_5282.JPG

El tema de las pilas, lo dejaré de momento, pero sospecho que podría alimentarlo del propio cable del timbre… Ya investigaré (o no…).

Posteriormente hay que conectar la raspberry a una salida del relé (el ‘A’ en nuestro caso):

IMG_5283.JPG

Como vemos tengo 4 canales en total, utilizo solo 1… pues 3 reservas… ya se me ocurrirán funcionalidades para meter en la raspberry, que no cunda el pánico 😉

Hecho esto pasé a programar algo para leer las entradas. Tenía la GPIO 17 disponible así que conecté el relé ahí.

Realmente comentí un error de 1º de electrónica … conecté el común del relé a la salida de 3.3V (TRUE) de la raspberry y una salida del relé a la GPIO 17… Esto, cuando el relé está conectando el comun (mis 3.3V) con GPIO17 (la entrada a la raspberry) para este caso concreto, evidentemente leeré un 1 PERO cuando está abierto el circuito (relé cambia de posición), GPIO17 está al aire y estar al aire NO es necesariamente un FALSE (0V), de hecho… a mí me seguía dando un TRUE aunque hubiera ‘desactivado’ el relé…

Así pues, lo que había que hacer realmente era conectar el COMÚN del relé a la GPIO17 y cada uno de los otros 2 extremos del relé a 0V y 3.3V, quedando así:

IMG_5294.JPG

Podemos ver de la salida del módulo del led azul que el común es el azul que va a la GPIO17 (tapada por los cables rojo y naranja en la imagen :/) y luego los cables verde y blanco van a GND (0V) y 3.3V respectivamente.

Y así sí, teníamos buenas lecturas desde la raspberry !

IMG_5285

Así teníamos el hardware ya preparado para funcionar… nos falta el software!

La parte de software la intentaré describir en el siguiente post, no obstante, partí de la librería wiringPi y en concreto de algún ejemplo que me baje de:

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

Ya sabéis que yo suelo usar C… está python que se supone es más facil pero… bueno, prefiero lo conocido que me voy a pelear menos, jejejejej

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

Gracias a stenyak y a los maravillosos hackits/solveits de este año he empezado a usar VIM… joder es una herramienta realmente buena! cuánto tiempo de mi vida he perdido con el nano xDD???

Para hacer el programa del timbre empecé partiendo de un proceso únicamente, pero me daba algún que otro problema y se quedaban muchas llamadas al cliente de telegram ejecutandose por ahí en segundo plano en la raspberry.

Para solucionar estos problemas empecé peleando con el comando ‘system’ de C pero no tenía mucho que hacer… finalmente opté por hacer uso de hilos.

Digamos que aún tengo en fase beta el programa del timbre (joder…. pensé que no me causaría tantos quebraderos de cabeza….). Va bastante bien tal y como está ahora, pero estoy pensando en algunas mejoras que le pueden ir bien. Explicaré cuando tenga acabado 100% (o 98%, que nunca dejo bien bien un programa :P).