Proyecto Hackd: Encendido Realmente Remoto

Nota: Este es un repost te mi articulo original, fechas y otros datos se pueden referir a cosas en el pasado. Algunas cosas pueden estar desactualizadas. Haré mi mejor esfuerzo en actualizarlo pero podría dejar una que otra cosa desactualizada por error o para dejar la narrativa intacta de cuando escribí originalmente el post.

De mi post en el blog de mi antigua compañía

¡Es temporada de HACKD de nuevo en MeetMe! Para aquellos que no estan familiarizados con el concepto, los hackatones son eventos que algunas compañías, escuelas y otras organizaciones realizan donde permiten a sus empleados, estudiantes, etc., trabajar en proyectos personales como nuevas tecnologías, inventos, ideas, etc., para los cuales ellos normalmente no tienen tiempo. Personalmente he tenido un proyecto pendiente en el que he querido trabajar pero por falta de experiencia y conocimiento (basicamente falta de confianza en mi mismo) y tiempo, no me había animado a llevar a cabo.

MeetMe ofrece eventos HACKD cada dos meses y durante uno de los más recientes decidí finalmente trabajar en este proyecto, al cual yo llamo “Encendido Realmente Remoto”.

El problema

Hace aproximadamente 3 años, (Actualización del post original. ¡Ya son 6 años!) Solía vivir en el Noroeste de México, cerca de Arizona, Estados Unidos. Desde entonces me moví con mi esposa a la costa este de Estados Unidos. Así que básicamente me moví de aquí:
desierto
…a aquí:
nieve
Encontré que en este clima necesitaba ir a mi carro, encenderlo y sentarme a esperar un rato a que tomara temperatura. Estar sentado en el carro en este tipo de frio no es muy cómodo. Incluso si enciendes la calefacción, no sirve para nada hasta que el motor toma temperatura correcta de trabajo.

Para el final del primer invierno, quería desesperadamente un encendido remoto para mi auto. Pensé, “Estaría muy bien encender mi auto desde la comodidad de mi casa u oficina y luego solo caminar a mi auto, con el interior calientito y arrancar”. Luego, cuando le instalé un encendido remoto a mi carro, me di cuenta rápidamente que no iba a servir mucho.

En la oficina, el estacionamiento está localizado al final del centro de negocios, y se llena rápidamente. Me puede tomar unos buenos 5 a 10 minutos caminar hasta mi auto. Además en otros casos como estacionarse en centros comerciales, cines, etc. convierten al encendido remoto en algo practicamente inservible. ¿Porqué? Los encendidos remotos y las alarmas automotrices tienen controles remotos con señales RF, las cuales son muy limitadas en cuanto a alcance.

En mi otro carro, en México, tengo instalada una alarma de alto desempeño, con un control remoto RF 2-vias que promete una milla de alcance. Pues… si tiene una milla de alcance… en un lugar así:
parking_lot_empty
Si empezamos a agregar carros, paredes y otras barreras, el alcance se reduce dramáticamente. Entonces fue cuando se me ocurrió la idea de hacer un encendido remoto que pudieras usar sin restriccion de distancia, desde donde sea.

La idea

Quería encender mi auto desde donde sea con mi teléfono celular, enviando a mi carro algun tipo de señal. No estaba seguro exactamente como lograr esto, así que me puse a investigar, vi varios videos de Youtube y leí varios tutoriales. Me dio gusto encontrar que no era el unico ni el primero en intentar esto y noté que la gran mayoría quería usar Bluetooth.

Tiene sentido. Nuestros celulares tienen Bluetooth integrado y puedes usar un Arduino o Raspberry Pi con un módulo Bluetooth (actualización, ya hay varios modelos de RPI que tienen Bluetooth integrado) y voilá. Pero eso no era suficiente para mi porque eso no resolvía mi problema. Aunque Bluetooth podría tener mas alcance que RF, todavia tiene restricción de distancia. Yo queria algo que no importara que tan lejos estuviera yo de mi auto. Entonces pensé acerca de WIFI “¿Qué tal si pongo un módulo WIFI en el Arduino o Raspberry Pi?” No, eso tampoco iba a funcionar. Me iba a pelear con la cobertura WIFI en todas partes y luego habría que pelear con señales protegidas por contraseña, etc.

Lo mismo pasa con 3G o 4G no hay cobertura 100% en todas partes, y se convertiría una solución bastante cara porque los planes 3G/4G son bastante caros. ¿Pero que tal si le envío un mensaje SMS a mi encendido remoto?

Meditémoslo un momento: La cobertura celular es prácticamente 100% (solo en ciertos lugares remotos es deficiente) y los mensajes SMS pueden ser enviados o recibidos básicamente donde sea. Además, los planes muy basicos, son muy baratos. ¡Lo tengo!

La solución

Entonces el fin de semana de HACKD se acercaba. Investigué un poco más acerca de que controlador usar, hay muchas opciones, no solo el Arduino o el Raspberry Pi, pero decidí usar el Arduino básicamente por el precio en ese momento y era el nivel de complejidad del controlador correcto.

Pasos

Luego de decidir que usar y como usarlo, conseguí todo lo que necesitaría.

BOM

Regulador de voltaje. La documentación de Arduino dice que trabaja de 5V a 20V, pero puede volverse inestable bajo 7V y lo puedes freír por encima de 12V. El voltaje mas común en autos es 12V así que necesitaría convertir el voltaje hacia abajo para protejer el Arduino. Sin embargo, luego de usarlo 2 o 3 días a 5V, se volvió inestable. Cambié el regulador desde entonces a uno de 9V y resolvió el problema.
Bueno, eso es todo lo que necesitaba. Ahora el proceso.

Proceso

Instalar un encendido remoto a un auto moderno no es tarea facil. Los autos en estos tiempos llevan transponders en las llaves los cuales el instalador tiene que ver como “brincarlos”, necesitas obtener diferentes señales de diferentes elementos y piezas diferentes en el auto para preparar diferentes restricciones de seguridad en el sistema, como hacer que el carro se apague, luego de un tiempo de estar encendido. O hacer que el auto se apague inmediatamente si intentas manejarlo sin llave, etc. Como toda esa lógica ya estaba incluida en mi encendido remoto ya pre-instalado y el hackaton eran sólo 3 dias, decidí colgar mi proyecto de la instalación ya existente.

Mi plan para entonces era que yo enviara un SMS desde mi teléfono celular hacia el Arduino (recibido mediante el módulo GPRS). Luego, el Arduino enviaría un pulso, mediante un cable al encendido remoto, usando su control remoto. Todo este circuito estaría localizado en algun lugar escondido dentro del tablero del auto. A continuación el diagrama.
diagram
Tomé uno de los controles remotos del encendido remoto, lo saque de su cubierta y le conecté un cable en cada polo de cada botón.
remote1
remote2
remote3
Luego conecté un switch a cada botón. En los switches que yo use, uno iba al pin COM y otro al pin N.O.
relay_diagram
Después ya con los tres switches conectados a los 3 botones del control remoto, conecté uno de sus pines izquierdos al negativo del Arduino. Y cada uno de sus pines derechos necesitan conectarse cada uno a tres pines 5v del Arduino. Los cuales usaremos para mandar las señales desde el Arduino al circuito, al final, todo se veia así ya conectado:
all_connected1
all_connected2
Este módulo necesita estar conectado a una fuente de poder continua del carro. Cada carro es diferente, asi que si alguien lo intenta, les dejo de tarea averiguar (usando su multímetro) encontrar un cable que tenga corriente todo el tiempo, incluso con el auto apagado. Recuerden usar el regulador de voltaje mencionado anteriormente.

Software

El lenguaje que Arduino usa es un subset de C++. Arduino tiene un IDE que podemos utilizar, descargable de aquí. Yo lo usé para este proyecto y ayuda muy bien. Además necesitamos una Terminal Serial para comunicar con el Arduino y el módulo Geeetech SIMCOM SIM900 Quad-band GSM GPRS, para enviar y recibir mensajes SMS. En la documentación del módulo localizada aquí, ofrecen algunas opciones diferentes para diferentes plataformas, Yo bajé CoolTerm para mi Mac OSX de aquí y funcionó perfectamente. Hay algo de configuración que se tiene que hacer para comunicarse con el Arduino y el módulo GPRS. ¡Ah! También necesitas una SIM card instalada en el modulo y con un plan con SMS activo.

Pre-configuración de la terminal

  1. Conectar el Arduino al puerto USB de la computadora con el módulo Geetech montado.
  2. Ir a CoolTerm y dar clic en opciones.
  3. Elegir el puerto, normalmente algo como usbmodemfd, si no aparece, dar clic en Re-Scan Serial Ports en la parte de abajo.
  4. Elegir 19200 Baud Rate.
  5. Listo para enviar y recibir comandos y leerlos.
Hay un segundo “lenguaje” o set de comandos que aprender aquí, y esos son los que se usan para realmente mandar y recibir los mensajes SMS. Es todo un mundo de comandos, no sólo para SMS, hay comandos para hacer llamadas, recibirlas, guardar, borrar, refrescar mensajes SMS, y todo lo demás que se puede hacer con una SIM Card, incluso navegar por internet. Esa referencia la podemos encontrar aquí.

Código de Arduino

// Setup to talk to the Serial Terminal when connected to the computer
#include <SoftwareSerial.h>
SoftwareSerial GPRS(7, 8);
unsigned char buffer[256]; 
int count=0;      


// Iniciating communication with the Serial Terminal and the PINS that are going to send the pulses to the remote
void setup()
{
 GPRS.begin(19200);                  
 Serial.begin(19200);            
 pinMode(2, OUTPUT);
 pinMode(3, OUTPUT);
 pinMode(4, OUTPUT);
}


void loop()
{
 delay(10000);
 if (GPRS.available())  // If there's data in the SIM Card
 {
  delay(5000);
  readPrint();
  clearBufferArray();

  delay(1000);
  GPRS.println("AT+CMGR=1");  //Get the message received
  delay(2000);

  readPrint();

// After getting the content of the message we look for the text
  String str1 = (const char*)buffer;
  int index = str1.lastIndexOf(""");
  String text = str1.substring(index+1, str1.length()-1);
  String str2 = "Turn On";
  String str3 = "Open";
  String str4 = "Close";
  if (text.indexOf(str2) != -1)  //If text was Turn On
  {
     Serial.write("nStartn");  //Send text "Start" to the Serial Terminal
//Then do the double pulse to the PIN 2
     for (int x=0; x<2;x++)
     {
     digitalWrite(2, HIGH);
     delay(800);
     digitalWrite(2, LOW);    
     delay(1500);
     } 
  }
  else
  {
    if (text.indexOf(str3) != -1)  //If text was Open
  {
     Serial.write("nOpenn");   //Send text "Open" to the Serial Terminal
//Then do the double pulse to the PIN 3
     for (int x=0; x<2;x++)
     {
     digitalWrite(3, HIGH);
     delay(600);
     digitalWrite(3, LOW);    
     delay(600);
     } 
  }
  else
  {
  if (text.indexOf(str4) != -1)   //If text was Open
  {
     Serial.write("nClosen");   //Send text "Close" to the Serial Terminal
//Then do the double pulse to the PIN 4
     for (int x=0; x<2;x++)
     {
     digitalWrite(4, HIGH);
     delay(600);
     digitalWrite(4, LOW);    
     delay(600);
     } 
  }
  else
  Serial.write("nnot foundn");  // If none was found print "not found" to the Serial Terminal
 }
}

  clearBufferArray();

  delay(1000);
  GPRS.println("AT+CMGD=1,4");  //Delete all messages in the SIM Card
  delay(1000);

    readPrint();
    clearBufferArray();
 }
}

//This function reads and puts together everything on the SIM Card and prints it to the Serial Port
void readPrint()
{
     while(GPRS.available())           
   {
     buffer[count++]=GPRS.read();    
     if(count == 256)break;
    }
   Serial.write(buffer,count);           
}


void clearBufferArray()              // function to clear buffer array
{

 for (int i=0; i<count;i++)
   { buffer[i]=NULL;}                  
  count = 0; 
}
Este código también lo pueden encontrar en mi Github aquí y va a estar corriendo en un ciclo sin fin en el Arduino. Básicamente espera por la SIM card que reciba un mensaje SMS. Una vez que el SMS llega, envía un doble pulso (necesitado por los botones del remoto) al botón deseado del control remoto, dependiendo del contenido del texto del SMS recibido. Después de eso, borra todos los mensajes para evitar llenar la SIM Card.

Después de subir el código al Arduino, podemos enviar mensajes SMS manualmente a nuestra instalación y debe funcionar correctamente. Este es un pequeño video de cuando estaba probándolo:

Este es un video de la instalación ya conectada al auto:

Tengo que agradecer por esta parte del código a mis compañeros y amigos Bob Dauth y Diana Shkolnikov, que me ayudaron mucho con C++ porque nunca había trabajado con él y no tenía nada de experiencia. Luego de eso, estaba casi listo. Sin embargo, quería una app que con presionar un botón enviara la señal, en lugar de entrar a la aplicación de mensajes y tener que escribir un SMS desde cero. Para eso, mi amigo y tambien compañero David Breneisen me ayudó y en menos de media hora, me armó una app, he aquí un screenshot:
first_app_screenshot
Basicamente, lo que hace es enviar un SMS cuando presionas uno de los botones. Además muestra un mensaje confirmando que el SMS fue enviado. Debido a que son muchos archivos, pueden encontrar el código de esta app aquí. Para el final del evento, todo esto estaba listo. El resultado final:

Lo usé todo ese invierno y ¡fue hermoso! Ahora, para este más reciente HACKD, quería mejorarlo. Me puse las siguientes metas:
  1. Quitar el numero de teléfono del código en la app y crear una página de configuración, donde el usuario pueda cambiar el número facilmente.
  2. Mejorar los botones, usando íconos en vez de texto.
  3. Obtener alertas del carro, cuando el carro haya sido encendido, cerrado o abierto, luego de haber recibido un mensaje SMS.
Este ultimo representa el reto más grande, porque necesitaba conectar más cosas al auto. Quería que el auto me reportara cuando ha arrancado o si alguna puerta fue abierta o cerrada porque hubo ocasiones en que mi plan de telefonía había expirado y mis SMS no salían y salía al frío pensando que mi carro había arrancado para encontrarme que estaba apagado. O al revés el SMS si fue enviado pero el plan en el Arduino estaba vencido y no lo recibía, teniendo el mismo resultado. Para estos nuevos retos, tuve que construir un nuevo, mas complejo, circuito, representado en el siguiente diagrama:
new_diagram
Tengo que agradecer aquí a mi amigo en México, Carlos Pinto, él es un Ingeniero en Electrónica y me ayudo a diseñar este circuito. Un poco de descripción.
  1. Los íconos en la esquina superior izquierda son switches en las puertas, estos switches envían la señal a la computadora del auto, para avisarle si una puerta está abierta. Hay un testigo en los tableros de los autos que se prende al estar la puerta abierta. Estos son los responsables. Necesitamos conectar esos sensores al Arduino de alguna manera para obtener esa señal. Hay algunas consideraciones que hacer, estas son señales negativas y necesitamos diodos para enviarlas por un solo cable, pero evitar que la señal se vaya de un sensor a otro.
  2. Al centro (Doors Relay), es básicamente un convertidor de señal. Ese relay toma la señal negativa de cualquiera de las puertas y envía una señal positiva al regulador de voltaje.
  3. La señal de las puertas es convertida a 12V, es por eso que necesitamos el regulador de voltaje a 5V (convertimos a 5V porque eso es lo que el Arduino soporta).
El resto del circuito es basicamente lo mismo que en el anterior, solo la conexión del auto al Arduino y los switches que envían las señales al control remote del encendido remoto. Luego necesitamos editar el codigo del Arduino a lo que sigue:
// Setup to talk to the Serial Terminal when connected to the computer
#include <SoftwareSerial.h>
SoftwareSerial GPRS(7, 8);
unsigned char buffer[256];
int count = 0;

// Setting up inicial door state
int last_door_value = -1;
int current_door_value = -1;

int total_delay = 0;

// Iniciating communication with the Serial Terminal and the PINS that are going to send and receive the pulses to the remote
void setup()
{
  GPRS.begin(19200);
  Serial.begin(19200);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, INPUT);
}


void loop()
{
  current_door_value = digitalRead(5);

  if (last_door_value == -1) {
    // This will initialize our "What was the last thing we read?" variable
    last_door_value = current_door_value;
  }

  delay(1000);

  total_delay += 1000;

// This will send the SMS letting me know that a Door has been opened or closed
  if (current_door_value != last_door_value) {
    if (current_door_value == 0) {
      GPRS.println("AT+CMGF=1");
      delay(100);
      GPRS.println("AT+CMGS = "+12674671270"");
      delay(100);
      GPRS.println("Door Closed");
      delay(500);
      GPRS.println((char)26);
      delay(500);
      GPRS.println();
      delay(500);
      readPrint();
      clearBufferArray();
      delay(3500);
    } else {
      GPRS.println("AT+CMGF=1");
      delay(100);
      GPRS.println("AT+CMGS = "+12674671270"");
      delay(100);
      GPRS.println("Door Opened");
      delay(500);
      GPRS.println((char)26);
      delay(500);
      GPRS.println();
      delay(500);
      readPrint();
      clearBufferArray();
      delay(3500);
    }
    last_door_value = current_door_value;
  }

// Next several lines are for receiving the SMS and sending the signal to the Arduino to Start the car, Close or Open the door locks
  if (total_delay > 5000 && GPRS.available())
  {
    total_delay = 0;
    delay(5000);
    readPrint();
    clearBufferArray();

    delay(1000);
    GPRS.println("AT+CMGR=1");
    delay(2000);

    readPrint();

    String str1 = (const char*)buffer;
    int index = str1.lastIndexOf(""");
    String text = str1.substring(index + 1, str1.length() - 1);
    String str2 = "Start";
    String str3 = "Open";
    String str4 = "Close";
    if (text.indexOf(str2) != -1)
    {
      //     Serial.write("nStartn");
      for (int x = 0; x < 2; x++)
      {
        digitalWrite(2, HIGH);
        delay(800);
        digitalWrite(2, LOW);
        delay(1500);
      }
      GPRS.println("AT+CMGF=1");
      delay(100);
      GPRS.println("AT+CMGS = "+12674671270"");
      delay(100);
      GPRS.println("Started");
      delay(500);
      GPRS.println((char)26);
      delay(500);
      GPRS.println();
      delay(500);
      readPrint();
      clearBufferArray();
      delay(3500);

    }
    else
    {
      if (text.indexOf(str3) != -1)
      {
        //     Serial.write("nOpenn");
        for (int x = 0; x < 2; x++)
        {
          digitalWrite(3, HIGH);
          delay(600);
          digitalWrite(3, LOW);
          delay(600);
        }
        GPRS.println("AT+CMGF=1");
        delay(100);
        GPRS.println("AT+CMGS = "+12674671270"");
        delay(100);
        GPRS.println("Unlock Succesful");
        delay(500);
        GPRS.println((char)26);
        delay(500);
        GPRS.println();
        delay(500);
        readPrint();
        clearBufferArray();
        delay(3500);
      }
      else
      {
        if (text.indexOf(str4) != -1)
        {
          //     Serial.write("nClosen");
          for (int x = 0; x < 2; x++)
          {
            digitalWrite(4, HIGH);
            delay(600);
            digitalWrite(4, LOW);
            delay(600);
          }
          GPRS.println("AT+CMGF=1");
          delay(100);
          GPRS.println("AT+CMGS = "+12674671270"");
          delay(100);
          GPRS.println("Lock Succesful");
          delay(500);
          GPRS.println((char)26);
          delay(500);
          GPRS.println();
          delay(500);
          readPrint();
          clearBufferArray();
          delay(3500);
        }
        else
          Serial.write("nnot foundn");  // If none was found print "not found" to the Serial Terminal
      }
    }

    clearBufferArray();

    delay(1000);


    GPRS.println("AT+CMGD=1,4");  //Delete all messages in the SIM Card
    delay(1000);

    readPrint();
    clearBufferArray();
  }
}

void readPrint()  // This function reads and puts together everything on the SIM Card and prints it to the Serial Port
{
  while (GPRS.available())
  {
    buffer[count++] = GPRS.read();
    if (count == 256)break;
  }
  Serial.write(buffer, count);
}


void clearBufferArray()              // function to clear buffer array
{

  for (int i = 0; i < count; i++)
  {
    buffer[i] = (unsigned char)0;
  }
  count = 0;
Éste código también está en mi Github y en esta ocasión tengo que agradecer a Drew Denardo también amigo y compañero de trabajo por ayudarme con este código además editando el código de la app de Android que ahora se ve así:
new_screenshot1
new_screenshot2
El código para esta versión de la app también puede ser vista en mi Github aquí. Luego de presentar y terminar la nueva versión en el HACKD me dí cuenta que de la manera que está programado actualmente, me envía un SMS cuando una de las puertas es abierta, incluso si yo la abrí. Obviamente no necesito que me notifique si el que abrió la puerta fui yo. Necesito agregar algun tipo de logica para decirle cuando dejarme saber, y cuando no. Pero supongo que eso será para el siguiente HACKD, ¿No?

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.