Alumno: Manuel de la Peña
D.N.I.: 53.430.012-T
Asignatura: Computación Ubícua
Máster de Investigación en Ingeniería del Software y Sistemas Informáticos
Curso: 2016-2017
Universidad Nacional de Educación a Distancia (U.N.E.D.)
Para acceder en modo online a este documento, por favor visite el siguiente enlace
Estudiar y proponer la integración de información sensorial sobre una plataforma de servicio para el Internet de las Cosas (IoT).
La práctica consiste en la utilización de las plataformas para el Internet de las Cosas para integrar información sensorial (preferiblemente con el sensor definido en la PEC2, MIVELOCIDAD1) y proponer una aplicación sobre la plataforma elegida con esta información.
Se puede utilizar cualquiera de las siguientes plataformas OpenSource:
- Kaa: Independiente de plataforma - C SDK https://www.kaaproject.org
- Macchina.io: Linux - JavaScript/C++ https://macchina.io
- Iotivity: Independiente de plataforma - C/C++ https://www.iotivity.org
- SiteWhere: Linux - Java http://www.sitewhere.org
También es posible utilizar otro tipo de plataforma no OpenSource como puede ser principalmente Autodesk Fusion Connect, AWS (Amazon Web Services), Google Cloud IoT, Microsoft Azure IoT, IBM Watson IoT o ThingWorx, teniendo en cuenta las limitaciones correspondientes a cada caso en las versiones "free".
La solución constará de 2 desarrollos independientes: por un lado la aplicación Android desarrollada con anterioridad, para representar los cambios de velocidad y posición del GPS del dispositivo móvil en el que se instala, y por otro lado el desarrollo de una plataforma IoT donde se almacenarán y representarán las métricas enviadas por los dispositivos que instalen la aplicación.
Para consultar la documentación relativa a la aplicación Android desarrollada con anterioridad, actualizada con el desarrollo necesario para comunicarse con la plataforma IoT, puede seguirse el siguiente enlace.
En el escenario del trabajo propuesto, y por simplicidad, se ha optado por desarrollar una plataforma IoT específica para el trabajo, que constará de tres piezas, todas alojadas en un PaaS (Platform as a Service) representando la plataforma IoT:
- API REST para manejar los recursos asociados a métricas: envío y consulta de métricas.
- Almacenamiento persistente de métricas.
- Interfaz de usuario para la visualización de las métricas almacenadas.
Cada pieza será representada por un microservicio, de modo que éste pueda ser evolucionado y escalado de manera independiente. Será la plataforma IoT la que ofrezca las capacidades de Registro y Descubrimiento de servicios de manera transparente al desarrollador: simplemente por estar desplegadas las aplicaciones en la plataforma, éstas tendrán visibilidad las unas con las otras.
Para la implementación de la plataforma se ha obtado por realizar un desarrollo propio a medida, en
lugar de utilizar una plataforma ya consolidada como podría ser Kaa Platform
. La principal razón
de utilizar este enfoque es el de desarrollar la plataforma desarrollada de manera específica para la
lectura de métricas desde los sensores, sin tener que aprender a utilizar, configurar y operar un
sistema de terceros por completo. Por ello, se ha elegido utilizar un PaaS como es WeDeploy,
que permite desplegar servicios en su plataforma, gestionando dichos servicios como repositorios Git.
La motivación más importante es la que se refiere a la infraestructura. Mientras que con otras
plataformas como Kaa
o Macchina.io
es necesaria la instalación y configuración de la máquina base
que dará soporte a la plataforma, con WeDeploy nos olvidamos completamente de la infraestructura,
ayudando al desarrollador de aplicaciones, en este caso de IoY, a dedicar el tiempo a lo que realmente
importa: construir y escalar aplicaciones.
WeDeploy proporciona un acceso a APIs muy intuitivas que ayudan a la creación de aplicaciones modernas, de una manera más rápida. Desde aplicaciones sencillas a una completa arquitectura orientada a microservicios, WeDeploy permite elegir entre una docena de lenguajes, frameworks, o stacks completos de aplicaciones, así como lanzar entornos preparados para producción en cuestión de minutos.
Con WeDeploy es posible responder a las necesidades de los usuarios de una manera más rápida y eficiente:
- Despliegue de aplicaciones más rápido.
- Distribución automática del tráfico entrante entre múltiples instancias.
- Autenticación de usuarios con unas pocas líneas de código.
- Almacenamiento seguro y consumo de información en tiempo real.
- Lanzamiento de aplicaciones sin tiempos de caída.
- Construcción y despliegue de microservicios.
A la hora de construir aplicaciones altamente escalables, es necesario considerar muchos elementos, como por ejemplo, cuellos de botella en el rendimiento, resiliencia y escalabilidad de la base de datos, autenticación, autorización, alojamiento estático, por citar unos cuantos. WeDeploy permite enfrentarse a todos los retos de un backend en un único lugar.
Independientemente de tener una aplicación sencilla, o un conjunto complejo de microservicios, la infraestructura cloud gestionada que supone WeDeploy propociona las herramientas para manejar la visibilidad, el escalado y la resolución de nombres (DNS) de las aplicaciones.
WeDeploy proporciona automatización para la actualización de servicios y sistemas sin tiempo de
caída ni interrupciones al usuario. Los despliegues de los servicios pueden ser realizados utilizando
distintos algoritmos: rolling-update
, blue-green
o canary
. Si la actualización falla, es posible
volver atrás de una manera muy sencilla (un click).
Los servicios distribuidos crean problemas distribuidos. Por ello WeDeploy incluye la generación automática de endpoints DNS, un API para el descubrimiento de servicios, una capa de transporte (L4) de proxy de IPs virtuales para soportar la comunicación interna de alta velocidad, y una capa de aplicación (L7) de balanceo de carga para los servicios expuestos hacia el exterior.
Con WeDeploy es posible marcar los servicios como públicos o privados en cuanto al acceso externo.
WeDeploy está configurado en alta disponibilidad y facilita del mismo modo que los servicios estén disponibles en alta disponibilidad del mismo modo.
Los servicios críticos requieren de monitorización, auto-curado, y tolerancia a fallos, tanto para ellos mismos como para la plataforma e infraestructura sobre la que corren. WeDeploy ofrece múltiples capas de protección. Para consehuir el auto-curado, por ejemplo, los servicios son monitorizados y relanzados si fallan. Incluso servicios de código legado que no soportan distribución o replicación pueden ser automáticamente relanzados para maximizar el tiempo de uso, así como disminuir el número de interrupciones del servicio.
WeDeploy permite escalar de manera fácil los servicios. El escalado horizontal es trivial con Docker Swarm, siempre y cuando los servicios lo soporten. Es posible además cambiar el número de instancias en cualquier momento, incluso basándose en el número de sesiones concurrentes, mediante el uso del servicio de Balanceo de Carga.
WeDeploy ofrece dos interfaces para facilitar la monitorización y la gestión de los proyectos y
servicios. Por un lado, el Dashboard
, o cuadro de mandos, que permite monitorizar el dimensionamiento
de los recursos, y la salud de los servicios en ejecución, entre otros, mediante el uso de un navegador
web, gráficos en tiempo real, y herramientas interactivas de depuración.
Además, WeDeploy proporciona un CLI (Command-line Interface
) para gestionar lose proyectos y
servicios desde la comodidad de un terminal. Este CLI es potente, a la vez que scriptable, con varios
plug-ins para interactuar con los proyectos.
En cuanto al modelo de datos que manejará la plataforma, se pretende almacenar aquellos datos enviados por las aplicaciones que comuniquen con la misma, mediante el API expuesto por uno de los microservicios antes mencionados. Para ello, se definirá el siguiente modelo de datos, con las consiguientes relaciones entre entidades del modelo:
- Un Sensor podrá enviar 1 ó N Métricas desde 1 ó N Aplicaciones.
- Una Métrica sólo puede pertenecer a 1 Sensor, pero podrá ser enviadad desde 1 ó N Aplicaciones.
De este modo, un sensor en una aplicación podrá enviar N métricas; una métrica de un sensor podrá ser enviada desde N aplicaciones; y una métrica enviada desde una aplicación podrá ser leída de un único sensor.
Por tanto, se establece una relación ternaria entre Sensor, Aplicación y Métrica, donde la clave primaria vendrá definida por el identificador del sensor, el identificador de la aplicación, y los identificadores de la métrica, que en este caso será la marca de tiempo asociada al envío de la métrica.
Únicamente recogeremos el identificador del sensor, por tanto la entidad sólo tendrá un campo de tipo
String
almacenando dicho ID único.
Para el sensor representado por la aplicación Android, el identificador se obtiene de la siguiente manera:
private String getUniqueDeviceId() {
TelephonyManager telephonyManager =
(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
final String deviceId = telephonyManager.getDeviceId(); // identificador del dispositivo
final String simSerialNumber = telephonyManager.getSimSerialNumber(); // número de serie de la SIM
final String androidId = android.provider.Settings.Secure.getString(
getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); // identificador de Android
UUID deviceUuid = new UUID(
androidId.hashCode(), ((long)deviceId.hashCode() << 32) | simSerialNumber.hashCode());
return deviceUuid.toString();
}
Otros sensores que quieran contribuir sus métricas a la plataforma tendrán que calcular el identificador del sensor de alguna manera, por ejemplo en base al hardware del sensor.
El dispositivo emitirá señales indicando su posición actual, expresada en coordenadas latitud y longitud, el valor de su métrica, el identificador de la métrica, las unidades en que se expresa la métrica, el identificador de la aplicación que lo envía, y la fecha de obtención del dato, de modo que éstos serán enviados a la plataforma IoT por dispositivo, y almacenados en ella con cada envío.
El sensor enviará las coordenadas de su ubicación puesto que al estar instalado en un dispositivo móvil como es un terminal Android, éste podrá moverse y cambiar su ubicación.
Para obtener más información sobre los microservicios desarrollados, por favor consultar los siguientes enlaces, relativos a cada una de los elementos software del proyecto:
Para los microservicios alojados en WeDeploy se han elegido tres tecnologías diferentes: para el API
REST se ha escogido el lenguaje Java en su versión 8, implementado mediante Spring Boot; para la
aplicación de interfaz de usuario que representará las métricas almacenadas, se ha escogido utilizar
HTML5, CSS3 y Javascript del lado del cliente; y para el almacenamiento persistente NoSQL se ha
utilizado ElasticSearch
, que es el almacenamiento ofrecido de forma predefinida por el PaaS WeDeploy.
El único microservicio que tiene un sistema de Build es el del API, puesto que los otros dos servicios se refieren a contenido estático no compilado. Para acceder a la documentación de este microservicio de API por favor consulte el siguiente enlace.
Para agrupar los tres microservicios que compondrán el stack de la aplicación, API REST, datos e interfaz de usuario, se ha creado un único proyecto en blanco, en el que se han creado un directorio por cada uno de los microservicios a desarrollar.
Para consultar la estructura y organización del código de cada microservicio, consulte el fichero
README.md
de cada servicio individual.
Un requisito imprescindible en toda aplicación es la escritura de buenos tests. Se consideran como buenas prácticas de escritura de tests las siguientes:
- Un buen test tiene una única razón para fallar.
- Un buen test verifica una única cosa del código a probar.
- Un buen test evita la lógica condicional.
- Un buen test tiene un nombre que describe de manera clara el caso de prueba. Por contra, no se puede confiar en un test cuya implentación no tiene nada que ver con el nombre del método de test.
- Un buen test crea/abre los recursos que necesita antes de su ejecución, y los cierra o borra al final de su ejecución.
- Un buen test no define de manera explícita sus dependencias (hardcoded dependencies).
- Un test que falla de manera constante es inútil.
- Un test que no puede fallar no aporta valor, pues crea una falsa sensación de seguridad.
Debido a la simplicidad del proyecto, no se han escrito tests unitarios para los microservicios.
Respecto a las pruebas de integración, se han escrito tests que prueban las llamadas HTTP al microservicio del API Java, verificando que los código de respuesta HTTP son los adecuados para cada prueba.
Para el lenguaje de programación de estos tests se ha elegido Spock
, que es un framework de testing
y especificación para aplicaciones Java y Groovy, inspirado en JUnit, jMock, RSpec, Groovy, Scala,
Vulcans, entre otros.
Estos tests de integración, que prueban las llamadas HTTP al API, se encuentran en este directorio, encontrándose la documentación asociada a dichos tests igualmente en el siguiente enlace.
Se han realizado pruebas exploratorias (o Exploratory Testing
) sobre la aplicación, de modo que
todos los controles han sido extensamente probados, utilizando diferentes prácticas: valores límite,
valores incorrectos, valores nulos en los campos, etc.
A continuación se presentan las diferentes pantallas de la aplicación, con la información necesaria para utilizar la aplicación con fluídez.
En cada cambio de posición realizado por el dispositivo Android, siempre y cuando la aplicación esté abierta y en primer plano, se enviará una métrica a la plataforma IoT.
Manual de uso de la aplicación Android
A continuación se presentan las URLs de los diferentes elementos que componen la plataforma:
- API (todas las métricas): https://sensorsapi-mdelapenya.wedeploy.io/sensors
- API (métricas de un sensor): https://sensorsapi-mdelapenya.wedeploy.io/sensors/ffffffff-e137-0800-d291-847505cc2b1f
- Interfaz de Usuario: https://sensorsui-mdelapenya.wedeploy.io
Accediendo a la URL https://sensorsapi-mdelapenya.wedeploy.io/sensors, la aplicación representando el API responderá a la petición con el resultado de consultar al almacenamiento persistente sin filtros, de modo que devolverá todas las métricas almacenadas. La respuesta de la petición estará en formato JSON.
Accediendo a la URL https://sensorsapi-mdelapenya.wedeploy.io/sensors/:sensorId, donde :sensorId
representa el identificador de sensor de interés, la aplicación del API responderá a la petición con
el resultado de consultar al almacenamiento persistente filtrando por la columna sensorId
, de modo
que devolverá todas las métricas almacenadas para el sensor especificado como parámetro. La respuesta
de la petición estará en formato JSON.
Si no hubiese ninguna métrica almacenada para dicho identificador, lo que indica que el sensor no existe en la plataforma, un mensaje de error 404 de HTTP será retornado en la respuesta.
Accediendo a la URL https://sensorsui-mdelapenya.wedeploy.io se mostrará el interfaz de usuario que mostrará las métricas almacenadas en la plataforma. Nada más acceder a la aplicación, se cargarán todas las métricas disponibles, en un formato tabular.
Al lado del botón de buscar, a la derecha, se encuentran dos iconos. Uno de ellos representando un grid, y otro un pin. Seleccionando el icono de grid se mostrará el formato tabular antes mencionado, mientras que seleccionando el icono de pin se mostrarán todas las métricas en un mapa.
Este mapa aparecerá centrado en función a todas las métricas almacenadas, en el centro geométrico de
todas ellas. Cada métrica será representada por un pin
rojo, que al ser clicado mostrará en una
ventana emergente la información de la métrica.
Si utilizamos la caja de búsqueda, introduciendo un identificador de sensor que no exista, y pulsamos el botón de buscar, se mostrará un mensaje de información indicando que no existen métricas para el sensor seleccionado.
Para instalar la aplicación Android, será necesario seguir el siguiente tutorial:
Manual de instalación de la aplicación Android
La plataforma se encuentra desplegada actualmente en WeDeploy, por tanto no es necesario instalarla de manera local.
Cualquier dispositivo que quiera almacenar sus métricas en la plataforma, únicamente tendrá que enviar
peticiones HTTP POST
a la misma, siguiendo la especificación definida por el API REST.
Por ejemplo, una simple petición curl
sería suficiente para enviar una métrica, siempre y cuando se
envíen los datos adecuados en formato JSON:
curl -v -H "Content-Type: application/json" -X POST -d '{"sensorId":"abcdefghijk","applicationId":"sensors-curl","latitude":"40.98765","longitude":"-1.12345","metric":"24", "metricUnits":"Celsius","metricName":"temperature","timestamp":"1489055420416"}' https://sensorsapi-mdelapenya.wedeploy.io/sensors
Por tanto, para enviar una métrica será necesario por tanto enviar una cabecera indicando que el
Content-type
a utilizar durante el intercambio de datos será JSON, el verbo HTTP a utilizar será
POST, y la URL que recibirá la petición será la definida por el recurso /sensors
en la plataforma
https://sensorsapi-mdelapenya.wedeploy.io
. En lo que a los datos se refiere, es necesario enviar:
- el identificador del sensor
- el identificador de la aplicación
- las coordenadas en formato latitud y longitud
- el valor de la métrica
- las unidades de la métrica
- el nombre de la métrica
- una marca de tiempo de la petición
Spring Boot: https://spring.io/guides/gs/actuator-service Spring Boot, construyendo servicios REST: https://spring.io/guides/tutorials/bookmarks/#_building_a_rest_service Spring Boot, sirviendo contenido web: https://spring.io/guides/gs/serving-web-content