Logo-Spanish

GR

 

 

 

QA AUTOMATION ENGINEER

 

Proyecto Remote Starter

De mi colaboración en el Blog de mi empresa

¡Es temporada de HACKD de nuevo en MeetMe! Para aquellos que no están familiarizados con el concepto, los hackatones son eventos que algunas compañías, escuelas y otras organizaciones llevan a cabo; donde los trabajadores, alumnos, etc., trabajan en los proyectos que ellos quieran como nuevas tecnologías, inventos, ideas, etc., que normalmente no tienen tiempo para trabajar en ellos. Yo tenía una idea desde hace tiempo en la que quería trabajar pero por falta de experiencia y conocimiento (acá entre nos, poca confianza en mi mismo) no me había animado a llevar a cabo.

MeetMe ofrece HACKD cada 2 meses y durante uno de los más recientes decidí finalmente trabajar en este proyecto que yo llamo "Really Remote Starter" (Encendido realmente remoto)

EL PROBLEMA

Hace 3 años vivía al Noroeste de México, cerca de Arizona, Estados Unidos. Desde entonces me moví a la costa este de Estados Unidos. Basicamente me movi de aquí:

desert

...a aquí:

winter

 

Encontré que en éste clima necesito sentarme en mi carro por un tiempo en lo que agarra temperatura de funcionamiento el motor. Estar sentado en el carro a la intemperie durante este tiempo no es muy cómodo ya que, aun cuando la calefacción está prendida, ésta no envía aire caliente, hasta que el motor toma temperatura.

LA IDEA

Para el final del primer invierno, buscaba desesperadamente un arrancador remoto para mi carro. Pensé "Estaría muy bien arrancar mi carro desde la comodidad de mi casa u oficina y luego de un tiempo, caminar hacia él y subirme, ya estando calientito adentro e irme". Cuando eventualmente lo compré caí en cuenta rápidamente que no siempre iba a ser tan útil.

En la oficina, el estacionamiento está localizado en la parte trasera del centro de negocios y se llena rápidamente. Te puede tomar unos buenos 5 a 10 min caminar hasta tu carro. Además, en otros casos como, estacionamientos de malls, cines, etc., el arrancador remoto básico es practicamente inservible, ¿Porqué? Porque los arrancadores remotos y las alarmas tienen controles de RF (Radio Frecuencia) que son muy limitados en términos de alcance.

En mi otro carro, en México, tengo una alarma de gama alta, que usa un control remoto dos vías de Radio Frecuencia, la cual promete una milla de alcance. Bueno, sí tiene una milla de alcance, en un lugar como este:

Si empezamos a agregar carros, paredes y otras barreras, el alcance disminuye dramáticamente. Entonces se me ocurrió la idea de hacer que mi arrancador remoto funcionara desde donde sea, sin restricción de distancia.

LA SOLUCION

Hasta este punto, yo quería encender mi carro desde donde sea, con mi telefono, enviándole al carro algún tipo de señal. No estaba seguro exactamente como lograría eso, asi que me puse a ver algunos videos de Youtube y tutoriales escritos. Encontré que no era el primero en intentar algo parecido, y tambié encontré que al parecer todos los que lo han intentado, por algun motivo, lo estaban intendando por medio de bluethoot. Tiene sentido, la mayoría de los smartphones tienen bluethoot y puedes comprar módulos bluethoot tanto para arduino como para raspberry pi y todas las otras plataformas. Pero eso no era suficiente para mi, porque eso realmente no resuelve mi problema. Aunque bluethoot podría tener mejor alcance que RF, todavía tiene restricción de alcance. Yo quería algo en donde no importara que tan lejos estés de tu carro.

Entonces la idea del WIFI me salto a la vista. "¿Que tal si pongo un módulo WIFI en el controlador?" No, eso tampoco funcionaría. Tendría que tener covertura WIFI en todo momento y no hay WIFI en todas partes; además esta el problema de las redes protejidas con contraseña, entre otros. Lo mismo sucede con 3G o 4G. No hay covertura 100% en todas partes, y se convertiría en una solución muy cara ya que los planes con esta covertura suelen ser mucho mas caros.

Pero, ¿Qué tal si le envío un mensaje SMS a mi arrancador?. Meditémoslo un momento. La covertura es prácticamente 100%, solo en lugares remotos es deficiente, por lo tanto un SMS puede ser recibido practicamente donde sea. Además, hay planes muy básicos prepagados que te pueden dar muy buen precio. ¡Lo tengo!

El fin de semana de HACKD se venía acercando, hice un poco de investigación acerca de que controlador usar, hay muchas opciones, no sólo el arduino y el raspberry pi, pero decidí usar el arduino básicamente por el precio y era el nivel de complejidad correcto.

PASOS

Después de decidir por que tarjeta usar y como usarla, conseguí todo el material que pensé sería necesario.

BOM

  • Arduino Uno Rev 3 (link)
  • Modulo GPRS (Geeetech SIMCOM SIM900 Quad-band GSM GPRS Shield ) (link)
  • Proto y cables (link
  • Kit de Soldadura (link)
  • Multimetro (link)
  • Mas cables
  • Regulador de voltaje (link)
  • Switches (link)

* Todos los links son sólo por referencia, puedes obtener otros modelos, estilos, marcas, precios, etc., Tampoco necesitas comprar nada de Amazon, puedes obtener todo de Ebay o de alguna tienda especializada en electrónicos.

* Regulador de voltaje. En la documentación de Arduino dice que trabaja con 5V a 20V, pero que puede ser inestable a menos de 7V y lo puedes quemar por encima de los 12V. El voltaje común de un carro es de 12V así que para evitar el riesgo de quemarlo, necesité bajar el voltaje que viene de la batería. Sin embargo, luego de 2 o 3 días funcionando a 5V se volvió inestable. Desde entonces lo cambié a un regulador de voltaje que lo baja a 9V y con esto solucioné el problema.

Bueno, eso es todo lo necesario. Ahora el proceso.

PROCESO

Instalar un arrancador remoto en un carro no es una tarea fácil. Los carros modernos ahora llevan transponders en las llaves los cuales el instalador tiene que averiguar como "brincarlo", necesitas obtener diferentes señales de elementos y piezas diferentes en el carro para preparar diferentes restricciones de seguridad en el sistema, como hacer que el carro se apague luego de un tiempo de estar prendido, para evitar por ejemplo que si olvidas que lo tienes prendido. O hacer que el carro se apague al ser puesto en Drive sin llave. Sólo porque toda esa lógica ya estaba incluida en mi arrancador remoto y el evento era un evento de sólo 3 días, decidí colgar mi proyecto, de la instalación ya existente.

Mi plan para entonces era que yo enviara un SMS desde mi cel hacia el Arduino (recibido mediante el módulo GPRS). Luego, el Arduino enviaría una señal a través de un cable al arrancador remoto, usando su control. Todo este circuito estaría localizado en algun lugar escondido dentro del carro. A continuación el diagrama:

v0.1 diagram

Tomé el control remoto, lo saque de su cubierta y le conecté un cable en cada polo de cada botón.

 remote card remote back remote connected

 Luego conecté cada switch en cada par de cables conectado a cada boton, en los switches que yo compré esto sería en los pins COM y N.O.

switch diagram

Después, ya con los tres switches conectado a los 3 botones del control remoto, conecté uno de sus pins izquierdo al negativo del Arduino. Y cada uno de sus pines derechos necesitan conectarse cada uno a 3 pines de 5V del Arduino. Los cuales usaremos para mandar las señales desde el Arduino al circuito. Al final todo se veía así ya conectado:

  

Todo este circuito tiene que estar conectado a una fuente de corriente continua del carro. Cada carro es diferente así que si alguien más lo intenta tiene que averiguar donde en su carro puede hacer eso. Ya mencioné anteriormente el porqué del regulador de voltaje.

SOFTWARE

El lenguaje que el Arduino maneja, basicamente es C++. Arduino tiene un IDE que podemos utilizar, que se puede bajar de aquí. Yo lo usé para este proyecto y me funcionó perfectamente. También necesitamos una aplicación de Terminal que maneje Serial, para comunicarnos 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í, ellos mencionan algunas opciones diferentes, para diferentes plataformas, yo bajé CoolTerm para mi Mac OSX de aquí y funcionó perfectamente. Hay un poco de configuración que hay que hacer aquí, para comunicarse con el módulo. ¡Ah! También ocupamos una SIM Card con saldo instalada en el módulo.

Pre-configuración de la Terminal

  1. Conectar el Arduino al puerto USB de la computadora (Con el módulo Geeetech montado).
  2. Abrir CoolTerm y dar clic en opciones.
  3. Elegir puerto, regularmente algo como usbmodemfd, si no aparece, clic en Re-Scan Serial Ports en la parte inferior.
  4. Elegir 19200 Baud Rate.
  5. Listo para enviar y recibir comandos.

Hay un segundo "lenguaje" o grupo de comandos que hay que aprender aquí, y éstos son los que se usan en realidad para enviar y recibir los mensajes SMS. Hay todo un montón de comandos, no solo para SMS, hay comandos para hacer y recibir llamadas, para borrar y refrescar SMS y todas las actividades de la tarjeta SIM, incluso hasta navegación por internet. Esa referencia la podemos encontrar aquí

Código 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("\nStart\n");  //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("\nOpen\n");   //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("\nClose\n");   //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 found\n");  // 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; 
}

 

Ese código también lo pueden encontrar aquí y va a estar corriendo en un ciclo sin fin. Arduino básicamente espera constantemente que llegue un SMS a la tarjeta SIM. Una vez que el SMS llega, dependiendo del texto del mensaje, Arduino envia un doble pulso al botoón indicado por medio de los cables conectados entre el remoto y el Arduino. Al terminar Arduino borra el mensaje recibido, para evitar que se llene el espacio de la memoria SIM.

Después de "subir" el código a nuestro Arduino podemos mandar SMS manualmente a nuestra instalación y ver si funciona correctamente. Este es un pequeño video de cuando lo estaba probando:



Este es un video de prueba con el modulo ya conectado al carro:


Tengo que agradecer por esta parte del código a mis amigos Bob Dauth y Diana Shkolnikov, quienes me ayudaron mucho con C++ porque yo no tenía experiencia previa con C++. Después de todo esto, el proyecto estaba casi terminado. Sin embargo, yo quería una app que con presionar un botón yo pudiera abrir o cerrar los seguros de mi carro, o encenderlo y apagarlo. Le pedí ayuda a mi amigo David Breneisen que me ayudara con eso. En menos de media hora el me resolvió el problema con una simple app que hacía el trabajo. Aquí un screenshot:

 app screenshot

En resumen, lo que hace es enviar un SMS con el contenido deseado cuando presionas el botón indicado. Además, te muestra una notificación cuando el mensaje ha sido enviado. Debido a que son varios archivos, pueden encontrar este código aquí. Eso fue todo para nuestro proyecto en esa ocasion.



Tuve la oportunidad de usarlo todo un invierno y ¡Fue genial!

Luego, para el siguiente HACKD, quería mejorarlo. Me plantee lo siguientes objetivos:

  1. Quitar el numero de teléfono del código de la app y poner una página de configuración donde el usuario tenga la oportunidad de editar el número.
  2. Hacer mejores botones en la app que tengan íconos en vez de texto.
  3. Obtener confirmación del estado del carro via SMS después de recibir una orden.
  4. Agregar una alerta, desde el carro cuando el carro ha sido abierto.

Este ultimo sería el reto mas grande, porque necesitaba conectar mas cosas al carro. Quería que el carro me reportara cuando ha arrancado o la puerta esta abierta o cerrada porque hubo ocasiones en que mi plan de telefonía había expirado y mis SMS no salían, sin darme cuenta que el carro no había arrancado, y salía al frío solo para darme cuenta que el carro no había arrancado. O al revés, el SMS fue enviado, pero el plan del carro expiró y el Arduino no recibía los mensajes.

Para estos nuevos retos tuve que construir un circuito más complejo:

second diagram

Tengo que agradecer aquí a mi amigo de México, Carlos Pinto, quien es un Ingeniero en Electronica y me ayudo a armar este circuito. Una pequeña descripción:

1. Los iconos en la esquina superior izquierda son los switches de las puertas. Éstos switches envían la señal a la computadora para avisarle si una puerta está abierta. Hay un testigo en los tableros de los carros que se prende al estar la puerta abierta. Éstos 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 uno al otro.

2. Al centro (Doors Relay), es básicamente un convertidor de señal. Ese relay toma la señal negativa de los switches de las puertas y manda una señal positiva a un 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 exactamente lo que era antes, solo la conexión al carro para encender el Arduino y las señales para enviar y recibir los pulsos al remoto del arrancador. Luego, necesitamos actualizar nuestro código en el Arduino de la siguiente manera:

 

// 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("\nStart\n");
      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("\nOpen\n");
        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("\nClose\n");
          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 found\n");  // 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;
}

 

 Este código tambien esta en mi Github y tengo que agradecer a Drew Denardo por ayudarme con este código y actualizar la app a la nueva version que ahora se ve de la siguiente manera:

new app main view new app settings view

El código para esta version de la app también se puede obtener de aquí.

Despúes de terminar y presentar la nueva version de mi arrancador remoto en el evento de HACKD, me di cuenta de un problema en la forma en la que esta programado actualmente: Me envía un SMS cuando una puerta ha sido abierta o cerrada, incluso cuando yo la abro, o cierro. Obviamente, no necesito un SMS que me avise si mi puerta está abierta o cerrada cuando soy yo quien lo está haciendo. Necesito agregar la lógica para que esto pase si, y solo si no estoy yo realizando la acción. Pero creo que eso tendrá que ser para el siguiente HACKD, a la mejor.