27 octubre 2011

Gestionando, de forma artesanal, una flota de vehículos


Allá por Marzo de 2009, tenía en la cabeza reutilizar mi vieja Qtek 9100 con sus capacidades GPS y su arcaico e inestable Windows Mobile, para ejecutar una aplicación del proyecto OpenDTM/OpenGTS, a fin de enviar las coordenadas via GPS a un servicio en Internet que me permitiera saber dónde está mi coche en cada momento.

Por un lado, uno de los problemas que planteaba a nuestros lectores de aquella época, radicaba en la privacidad que ofrecían ese tipo de servicios en los que puedes enviar de forma gratuita, la posición de tu dispositivo y monitorizar si se ha llevado el coche la grúa, o algún amigo de lo ajeno. Es decir, ¿por qué el administrador, la empresa patrocinadora del servicio, o en caso de tener una seguridad deficiente, cualquiera con cierta curiosidad, pueden saber qué recorrido hago para ir a trabajar, dónde aparco todos los días o dónde he estado yo el último fin de semana?

Así pues, y como además me llamaba mucho la atención la idea, decidí montármelo yo mismo. Lo primero que elegí fue el software que iba a desplegar en casa para poder almacenar las coordenadas, así como su visualización en un mapa. El proyecto libre que más me gustó fue OpenGTS. Ahora tocaba elegir un dispositivo que fuera compatible al 100% con el proyecto y que vendieran en España. A través de la propia web, dí con el SANAV GC-101FA. En La Casa del GPS lo distribuían por unos 250 euros. Debido a que en esa época estaba potenciando un foro de coches creado por un amigo, propuse a la gente de La Casa del GPS, la posibilidad de vender un montón de ellos a los miembros de un foro y acordé un precio más conveniente con ellos. No os creáis que salió mucho más barata la broma, pero bueno. Si me roban el coche y no lo encuentro, el desembolso para hacerme con otro vehículo, seguro que es mayor.

En los estudios llevados a cabo por La Casa del GPS, el operador más rentable (en España) para utilzar con este tipo de dispositivo es Simyo. Incluso configurando el equipo para que envíe cada minuto su posición, costaba menos de 5 euros al mes hace dos años. Así pues, con la compra del GC-101FA, adquirí una tarjeta SIM de Simyo con un plan de datos. En estos dos últimos años, creo que el mes que más he pagado ha sido 3,3 euros, así que es todo correcto.

La instalación
  • Antes del do-it-yourself, probé el servicio al que tenía derecho con la compra del dispositivo y, sinceramente, amén de las trabas que hemos comentado anteriormente, la interfaz no me gustó en exceso.
  • En mi caso, la plataforma elegida fue mi CentOS Linux. Seguí los pasos dispuestos en el tutorial de instalación y configuración del proyecto OpenGTS. Me parece una tontería repetiros aquí los pasos. La documentación es bastante buena y como veréis requiere, entre otras cosas, de un servidor web Tomcat para que la aplicación funcione.
  • En mi caso, tengo Tomcat en la red interna y, para evitar publicar el servicio completo a Internet, tuve que hacer una sección en un Apache actuando como proxy inverso hacia el Tomcat cuando se llama a determinada localización. Nada que no haya explicado también otras veces en SbD.
  • El dispositivo GPS se configura, o mediante un cable USB y un software que viene con él, o mediante SMS, enviando un código de comando y determinados parámetros para que envíe la localización detectada al servidor correspondiente.
  •  Una vez que está correctamente parametrizado, las peticiones recibidas por Tomcat desde el dispositivo tienen el siguiente formato: GET /proxyquesea/Data?imei=[IMEI_del_GC-101FA]&rmc=[Posición_en_formato_$GPRC]. En este post viene explicado estupendamente los detalles del formato GPRC. Como bien podéis imaginar, si alguien falsea las peticiones conociendo las rutas y el IMEI del dispositivo GPS, podría generar posiciones aleatorias enviadas por mi coche y falsearían la posición donde se encuentra el mismo. No hay autenticación de ningún tipo en la petición; son meras GET en las que distinguimos el vehículo gracias al IMEI sumistrado como parámetro.
  • El GC-101FA trae una batería compatible con la de un móvil Nokia 8210 y tiene un par de horas de autonomía. Sin embargo, para monitorizar un vehículo en modo 24x7, es necesario suministrarle corriente de forma permanente. Así enviará la posición del mismo cada minuto sin problemas con la duración de la pequeña batería interna. Además, el dispositivo debería ir oculto dentro del vehículo, por lo que lo mejor es conectarlo a una toma de mechero del coche directamente a la batería. Otra opción es hacerlo a través de la caja de fusibles. Para ello, tomaremos la corriente mediante un fusible que sepamos que nos entrega energía de forma permanente, aunque no exista contacto bajo llave. Este es un blog de seguridad, por lo que las clases de electricidad y mecánica del automóvil, si alguien se anima y necesitáis ayuda, me lo comentáis en un correo y os explico cómo proceder para dar con un fusible válido. OJO: Añadir un dispositivo que está permanentemente conectado genera un consumo fijo esté o no el coche andando, por lo que la vida útil de la batería disminuirá. Este disclaimer tengo que ponerlo, aunque también os digo que en mi caso tengo varios cacharros conectados siempre y no he tenido problemas de momento.
  • La aplicación en el servidor Tomcat, se despliega en un fichero .war, y recibe las peticiones web del dispositivo, almacenando la información relativa a la posición enviada por el mismo en el formato GPRC (como la latitud, longitud, altitud, etc,...) en una base de datos MySQL dentro de la misma máquina (por defecto).
  • El GC-101FA es capaz de guardar además la altura a la que está el dispositivo (o en mi caso el coche). Utilidad para mí no tiene ninguna, pero siempre es interesante el poder ver de qué altura era el puerto por el que pasaste si no tienes la wikipedia a mano. Sin embargo, OpenGTS no implementaba la funcionalidad necesaria para quedarse con este dato, aunque la base de datos sí que lo contemplaba en su parámetro "altitude". Así que, ya que estaba, me pegué un rato navegando entre todo ese código Java para implementar lo necesario y poder parsear el parámetro de la altura y que lo insertara en mi base de datos también. Una vez hecho esto, lo empaqueté en un .war nuevo y lo desplegué en mi tomcat de nuevo. Las modificaciones que hice son tan complicadas como las siguientes en la aplicación gc101:
[root@Carmen gc101]# diff Data.java Data.java.orig
328d327
<         double  altitude  = isValid? StringTools.parseDouble(fld[12], 0.0) : 0.0;
364d362
<         evdb.setFieldValue(EventData.FLD_altitude    , altitude);
  • Luego, el interfaz web que proporciona OpenGTS, procesa las coordenadas GPS almacenadas, resolviendo mediante Google Apps, localizaciones entendibles por humanos (es decir, nombre de calle, número, ciudad, etc…), así como calculando la velocidad del dispositivo entre un punto y la posición anterior. Lo podéis ver en la imagen siguiente:

  • Una pena que no exista una aplicación para Iphone que permita acceder a este fantástico interfaz en tiempo real. Para casos en los que aparcas en un lugar en el que, ya sea por la grúa o los amigos de lo ajeno, puedas tener la tranquilidad que al salir de la reunión en la que estás, no tengas que volver a casa en taxi, haciendo una escala en la comisaría para denunciar un robo.
  • Así pues, ya que guardo en una base de datos de mi servidor las coordenadas e información necesaria, me decidí a implementar un sistema que, esté donde esté, pueda saber si todo sigue donde lo dejé. Para ello, aproveché el bot controlable por mensajería instantánea que utilizo para otras mil cosas como encender/apagar el aire acondicionado/calefacción de casa y/o la alarma , o para monitorizar si la roomba está limpiando, entre otras locuras,…  y le añadí una nueva funcionalidad. Ahora si, vía mensajería instantánea, a mi bot le escribo el comando "dnd N" me devuelve las N últimas posiciones registradas por el dispositivo GPS en las que ha estado mi coche. Como envía la posición cada minuto, puedo ver la posición en "formato humano" de los N últimos minutos registrados. Sorprendentemente, Google devuelve la dirección con bastante precisión.


El código perl necesario para lograr esto es el siguiente:

  if ($message =~ /^dnd/i)
  {               
        my $dbh = DBI->connect($dsn, $db_user_name, $db_password);
        my $num=1;
        if ($#fields >= 1 ) {$num=$fields[1];}
        my $tosend="";
        my $sth=$dbh->prepare("select address, deviceID,creationtime,longitude,latitude from EventData order by creationtime desc limit 0,$num");
        $sth->execute();
        my @longs,@lats;
        my $cuantos=$sth->rows;
        my $voypor=0;
        while (my ($donde,$device,$creationtime,$longitude,$latitude)=$sth->fetchrow_array())
        {
            utf8::decode($donde);
            my $dt = DateTime->from_epoch( epoch => $creationtime, time_zone => "Europe/Madrid" );
            if ($voypor > 0)
            {
                 if ( (@longs[$voypor-1] ne $longitude) && (@lats[$voypor-1] ne $latitude) ) 
                 {#No son iguales que la anterior, meto esa posicion en el array
                       my $dmy = $dt->dmy;
                       my $hms = $dt->hms;
                       $tosend.="El $dmy a las $hms el dispositivo $device estaba en $donde\n";
                       @longs[$voypor]=$longitude;
                       @lats[$voypor]=$latitude;
                 }
            }
            else
            {#Es la 0, pa dentro
                  my $dmy = $dt->dmy;
                  my $hms = $dt->hms;
                  $tosend.="El $dmy a las $hms el dispositivo $device estaba en $donde\n";
                  @longs[$voypor]=$longitude;
                  @lats[$voypor]=$latitude;
            }
      $voypor++;
    }

  • Ya puestos, por si no tengo claro dónde estoy a nivel de dirección, y ya que desde la mensajería instantánea, no puedo ver el mapa como para hacerme una idea, ideé otro mecanismo que, gracias a la API de Google, me envíe un enlace web con un mapa con las posiciones requeridas. Para eso, ejecuto el comando "dndm N" y así pido un mapa de las últimas N posiciones.



En el bot, el código necesario que tuve que hacer fue:


            
       if ($message=~ /^dndm/i)
       {#Donde con Mapa
           if ( ($cuantos > 1) && ($cuantos <= 5)) {$zoom=15;}
           elsif ( ($cuantos >5 ) && ($cuantos <= 10)) {$zoom=14;}
           elsif ( ($cuantos >10 ) && ($cuantos <= 15)) {$zoom=13;}
           elsif ( ($cuantos >15 ) && ($cuantos <= 20)) {$zoom=12;}
           elsif ( ($cuantos >20 ) && ($cuantos <= 25)) {$zoom=11;}
           else {$zoom=10;}
           my $urlbase="http://maps.google.com/maps/api/staticmap?zoom=$zoom&size=640x640&maptype=roadmap&markers=color:green";
           my $puntos; 
           for (my $i=0;$i<$cuantos;$i++)
           {
               $puntos.="|$lats[$i],$longs[$i]";
           }    
           my $url=$urlbase.$puntos."&path=color:0xff0000ff|weight:".$puntos."&sensor=true";
           my $urlapi = 'http://tinyurl.com/api-create.php?url=';
           my $ua = LWP::UserAgent->new;
           my $response = $ua->get($urlapi.$url);
           if ($response->is_success) 
           {
               $tosend.=$response->content;
           } 
           else
           { 
               $tosend.=$url;
           }
       }

  • Al pinchar en el enlace que nos envía el bot, podemos ver una representación en google maps como la siguiente:


12 comments :

fossie dijo...

Muy buen trabajo. Lo ideal, como tu indicas, es montarselo uno mismo así no tienes problemas de "seguridad" con servicios de terceros aunque eso de que las peticiones se hagan por un simple GET habría que mirarlo para intentar asegurarlo un poco más.

Lo del bot de mensajería para que te vaya informando me ha parecido genial aunque ya puestos habría sido un puntado que el sistema te enviase un SMS cuando el coche (el dispositivo) se empezara a mover sin tu estar dentro de él. Vamos, cuando te lo roban o se lo lleva la grua. Sería acojonante estar en una reunion y recibir un SMS donde diga "Me estoy moviendo solo... estoy circulando por la calle tal..." jeje

Genial!

fon dijo...

yo creo que al ser un sistema hecho específicamente para él, el GET es más que suficiente, el problema sería igualmente, que si tienes, qué se yo.. un audi A8 nuevecito o un M5 A96 y te lo roban, si te han hackeado la centralita del coche, digo yo que se habrán molestado es ponerte un inhibidor de GPS de estos del Dealextreme no? xD

Lorenzo_Martinez dijo...

Muchas gracias por tu idea! La verdad es que lo que planteas es posible, aunque requiere que haya "otro cacharro" (o que el mismo tenga la posibilidad) que si no es capaz de hacer un pairing bluetooth con otro dispositivo, y "se mueva", avise que se está moviendo...
El problema de todo esto, además es que las coordenadas de las posiciones que se envían, incluso estando el dispositivo quieto, pueden diferir en varios metros, por lo que los falsos positivos serían bastante frecuentes, si se hace por posiciones. Otra cosa es que el cacharro actual mande en un parámetro dentro del GET, un flag que permita decidir en tu "espacio de usuario", es decir, el servidor... si el margen de error es suficientemente amplio. Se me ocurre así de golpe, que haciendo peticiones a la api de google, si detecta diferencias en la "dirección de la calle en la que está", avise de la forma que sea al dueño :)
Le daré una pensada al tema a ver qué se puede hacer... Muchas gracias

Lorenzo_Martinez dijo...

Efectivamente, el mecanismo es fácil de bypassear utilizando un inhibidor de frecuencias. Hablamos ya de ello aquí: http://www.securitybydefault.com/2011/05/inhibiendo-tu-seguridad.html

Sin embargo, también es cierto que es una medida más. Si alguien te lo roba sin saber que tienes un localizador dentro, y no lleva inhibidores, puede que lo encuentres.

Si un grupo organizado y profesional "levantando" coches, se le mete el tuyo entre ceja y ceja,.. date por perdido, porque no lo vuelves a ver!

Aluziner dijo...

Excelente post, gracias por compartir tus alucines con nosotros.

Borja Berastegui dijo...

Eh...

Uh...

Hum...

Cásate conmigo Lorenzo :D

F*ck. Estos posts me flipan, enhorabuena de nuevo, ya sabes ;)

fc4stillo dijo...

Que buen trabajo. Aunque lo compartas, es un "camello" hacer la misma hazaña. Te felicito. Eres un loco !

Zonaopengts dijo...

Visita http://zona-opengts.blogspot.com/ para que estés mas informado acerca del proyecto OpenGTS

Borja Ferrer dijo...

Tio, eres un maquina, me encantan tus posts, de verdad, cada vez que leo uno imagino como debe ser la "sala de los ordenadores" de tu casa... hahahahahahah me encantan tus ideas, es lo que todos siempre hemos querido hacer, pero tu lo tienes y con tus manitas!!! Dios, tiene k ser estupendo!!
Me ha encantado la idea del GPS para el coche, pues hay ya muchas empresas que lo hacen para tu "supervehiculo", y te cobran una pasta!
La verdad es que el reaprovechamiento de aparatos antiguos como moviles con GPS para tareas de este tipo es una excelente idea... quiza ahora los "viejos cacharros" no sean muy programables, pero quien te dice que dentro de unos años, retocar un iphone3 para que haga lo mismo que el gps pero con mas capacidades no sea cosa de 2 duros!
Sigue ahi tio, me encantan tus ideas!

B.

Jorge dijo...

Comparto el comentario de Borja, me encantaría tener tiempo para juguetear con todas estas cosas?
Entiendo que son muchas horas de sueño verdad?
Algún consejo para rascar tiempo??

Carlos Gonzalez dijo...

CARLOS GONZALEZ - FREELANCE PROFESSIONAL.

Expert in OpenGTS. Software Development, Web Solutions. Consultant at LBS (Location Based Services).
Solutions in GPS Tracking System.

Contact me for more information.

http://www.cgonzalezdev.com

Thanks!

Carlos Gonzalez dijo...

CARLOS GONZALEZ - FREELANCE PROFESSIONAL.

Expert in OpenGTS. Software Development, Web Solutions. Consultant at LBS (Location Based Services).
Solutions in GPS Tracking System.

Contact me for more information.

http://www.cgonzalezdev.com

Thanks!