Infraestructura de eventos para la Internet de las cosas. - RUIdeRA ...

vista, como lo son el hardware, el software, la metodología en el desarrollo de ...... Uno de los problemas principales de la Smart City es el conocido como «isla ...
6MB Größe 22 Downloads 140 vistas
UNIVERSIDAD DE CASTILLA-LA MANCHA ESCUELA SUPERIOR DE INFORMÁTICA

GRADO EN INGENIERÍA INFORMÁTICA

TRABAJO FIN DE GRADO

Infraestructura de eventos para la Internet de las cosas. Roberto Requena Camacho

Septiembre, 2014

I NFRAESTRUCTURA DE EVENTOS PARA LA I NTERNET DE LAS COSAS .

UNIVERSIDAD DE CASTILLA-LA MANCHA ESCUELA SUPERIOR DE INFORMÁTICA Tecnologías y Sistemas de Información TECNOLOGÍA ESPECÍFICA DE INGENIERÍA DE COMPUTADORES

TRABAJO FIN DE GRADO

Infraestructura de eventos para la Internet de las cosas.

Autor: Roberto Requena Camacho Director: Dr. Félix Jesús Villanueva Molina

Septiembre, 2014

Roberto Requena Camacho Alcázar de San Juan – España E-mail: [email protected] Teléfono: 653 683 383 c 2014 Roberto Requena Camacho

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". Se permite la copia, distribución y/o modificación de este documento bajo los términos de la Licencia de Documentación Libre GNU, versión 1.3 o cualquier versión posterior publicada por la Free Software Foundation; sin secciones invariantes. Una copia de esta licencia esta incluida en el apéndice titulado «GNU Free Documentation License». Muchos de los nombres usados por las compañías para diferenciar sus productos y servicios son reclamados como marcas registradas. Allí donde estos nombres aparezcan en este documento, y cuando el autor haya sido informado de esas marcas registradas, los nombres estarán escritos en mayúsculas o como nombres propios.

i

TRIBUNAL:

Presidente: Vocal: Secretario:

FECHA DE DEFENSA:

CALIFICACIÓN:

PRESIDENTE

Fdo.:

VOCAL

SECRETARIO

Fdo.:

Fdo.:

iii

Resumen El Internet de las Cosas, como paradigma para la conexión de los objetos cotidianos a Internet, está suponiendo una revolución en cuanto a la forma en que se interactúa con el entorno. Su uso permite aprovechar con mayor eficiencia las posibilidades que este nos ofrece. Este hecho, está dando lugar a un auge en el esfuerzo que se realiza para desarrollar tecnologías y estándares que soporten las características que requieren este tipo de escenarios. Gracias al Internet de las Cosas, está apareciendo la tecnología necesaria para recopilar, transmitir y gestionar información relevante dentro de los distintos procesos que ocurren en ciudad. Hecho que permite el desarrollo del paradigma de las Ciudades Inteligentes o Smart Cities. A partir del cual, se pretende que una ciudad mejore en la toma de decisiones referentes a los planos: económico, operativo, social y ambiental. Estos a menudo, se activan a partir de la aparición de una serie de eventos, ante los que la Smart City tiene que reaccionar. La recopilación y transmisión de la información que se genera en la ciudad, necesita de la cooperación de numerosas tecnologías, estándares, dispositivos, etc. siendo la Smart City la encargada de proporcionar la abstracción necesaria sobre estos elementos, con el fin de proporcionar servicios de valor a ciudadanos e instituciones. En este Trabajo Fin de Grado se presenta una infraestructura para el Internet de las Cosas, que utiliza un modelo de comunicación basado en la publicación/suscripción de eventos, como medio para transmitir la información recopilada por los dispositivos de una red de sensores, hacia una red externa. De forma que, queda accesible a cualquier consumidor que se encuentre conectado a ella. En concreto, los resultados obtenidos con este proyecto, pretenden formar parte de uno de los métodos para recopilar información del entorno, que tendría una Smart City. A partir de la puesta en escena de la infraestructura, en un escenario real, se ha podido comprobar que realiza correctamente sus funciones. Proporciona los servicios de middleware muy básico, a través del cual las aplicaciones pueden consultar la información que los sensores han recopilado del entorno, sin necesidad de que estas tengan que lidiar con las tecnologías subyacentes.

V

Abstract Nowadays a revolution in the way people interact with the environment due to development of Internet of Things is taking place; this could be seen like a paradigm in where everyday objects are connected to Internet. This process allows people to take advantage of environment possibilities in a more efficient way. In this sense, technologies and standards need to be created in order to support this characteristics scenario. In a similar way, the Smart City paradigm, which will enable cities to take economic, operative, social and environment decisions in a best way, is growing up. This is possible through Internet of Things, which establishes the basis for the appearance of technologies to collect, transmit and manage massive information that appears in cities. In the city, information is organized in processes and events that activate it. Therefore, the city must be able to respond and manage these events. To collect and transmit information produced by cities, cooperation between technologies, standards and devices is needed. So the City will be responsible of making the abstraction over these elements in order to provide services to citizens and organizations. In this sense, this Final Degree Project presents an event-based infrastructure for Internet of Things. Which uses a publish/subscribe model similar to the way of transmission of sensory information towards a higher transport level network. This system enables any consumer to obtain this information. Specifically, this project aims to be part of one of the methods the Smart City will have in order to collect and transmit information. Once the infrastructure has been tested in a real scenario, it’s correct operation will have been checked. This infrastructure provides services of a very basic middleware, through applications that can obtain environmental information collected by sensors, without the need of taking care about underlying technologies.

VII

Agradecimientos Ya han pasado cinco años desde que comencé la carrera universitaria y durante su trascurso, mi vida y mi forma de pensar han cambiado de manera significativa, debido en gran parte a las amistades realizadas en este periodo de tiempo y, por supuesto, a las personas que ya estaban en mi vida. Así que, tras la realización de este proyecto, que representa el último obstáculo en el camino, es bueno disponer de una parte del mismo en la que escribir unas lineas completamente personales. En primer lugar, quiero mostrar mi más sincero agradecimiento a toda mi familia. En especial a mis padres, Lorenzo y Ana, ya que a partir de su educación y su forma de ver la vida, han logrado inculcarme un gusto por el estudio, la cultura y el trabajo bien hecho, que sin duda me ayudarán a lo largo de mi vida. Y por supuesto, gracias a su soporte económico, que tanto esfuerzo les ha costado y sin el cual, no hubiese sido posible siquiera empezar la carrera. En menor grado pero también destacable, ha sido el apoyo, tanto moral como logístico, recibido por mis tíos Luismi y Minerva. Por otra parte, quiero mencionar a María, Alba, José Puche, José Duro, Carlos y Antonio, personas que comenzaron siendo compañeros de clase, y que después de cinco años y tras muchas experiencias vividas, son amigos de los que no me voy a olvidar a pesar de que se separen nuestros caminos. A todos ellos, gracias. Gracias por hacer más ameno el día a día y más llevadera la rutina. Y como no, gracias por lo buenos momentos de esparcimiento que hemos tenido. Por último, agradecer a mi tutor, Felix, el tiempo que me ha dedicado a pesar de tener una agenda bien completa. Debido a sus logros personales y a su forma de dar clase, pensé que sería una buena experiencia realizar el proyecto con él, y así ha sido. Roberto Requena Camacho

IX

A mis padres, por soportar el día a día sin rendirse y sacarlo todo adelante.

xi

Índice general

Resumen

V

Abstract

VII

Agradecimientos

IX

Índice general

XIII

Índice de cuadros

XVII

Índice de figuras

XIX

Índice de listados

XXI

Listado de acrónimos

XXIII

1. Introducción

1

1.1. IoT y las ciudades inteligentes . . . . . . . . . . . . . . . . . . . . . . . .

2

1.1.1. Aspectos tecnológicos . . . . . . . . . . . . . . . . . . . . . . . .

2

1.1.2. Civitas, un middleware para las Smart Cities . . . . . . . . . . . .

4

1.2. Paradigma de programación basado en eventos . . . . . . . . . . . . . . .

5

1.2.1. MQTT y MQTT-SN, protocolos para el I OT . . . . . . . . . . . . .

5

2. Objetivos

9

2.1. Objetivo general . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9

2.2. Objetivos específicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9

2.2.1. Diseño e implementación de una librería MQTT-SN . . . . . . . .

10

2.2.2. Diseño e implementación de una pasarela software . . . . . . . . .

10

2.2.3. Diseño e implementación de una librería MQTT . . . . . . . . . .

10

2.2.4. Diseño de un suscriptor en una red externa . . . . . . . . . . . . .

11

2.2.5. Diseño y validación de escenarios de test . . . . . . . . . . . . . .

11

XIII

3. Antecedentes

13

3.1. Internet de las Cosas . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13

3.1.1. Tecnologías de identificación, captura y comunicación . . . . . . .

16

3.1.2. Importancia del middleware . . . . . . . . . . . . . . . . . . . . .

18

3.1.3. Internet de las Cosas, un paradigma libre . . . . . . . . . . . . . .

19

3.2. Smart Cities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

23

3.2.1. Tecnologías de la Smart City . . . . . . . . . . . . . . . . . . . . .

24

3.2.2. Middlewares . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29

3.2.3. Civitas: Plataforma de soporte a las ciudades inteligentes . . . . . .

29

3.2.4. Smart City en España . . . . . . . . . . . . . . . . . . . . . . . . .

32

3.2.5. Proyectos Europeos en el marco de la Smart City . . . . . . . . . .

34

3.2.6. Plataformas y aplicaciones Open Source para la Smart City . . . . .

35

3.3. Programación orientada a eventos . . . . . . . . . . . . . . . . . . . . . .

38

3.3.1. Topologías . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

3.3.2. MQTT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

40

3.3.3. Otras tecnologías . . . . . . . . . . . . . . . . . . . . . . . . . . .

46

3.4. Conclusiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

49

4. Metodología de trabajo

51

4.1. Metodología de trabajo . . . . . . . . . . . . . . . . . . . . . . . . . . . .

51

4.1.1. eXtreme Programming (XP) . . . . . . . . . . . . . . . . . . . . .

52

4.1.2. Test Driven Development (TDD) . . . . . . . . . . . . . . . . . . .

53

4.2. Planificación del proyecto . . . . . . . . . . . . . . . . . . . . . . . . . . .

55

4.3. Herramientas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

55

4.3.1. Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

56

4.3.2. Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

57

4.3.3. Lenguajes de programación . . . . . . . . . . . . . . . . . . . . .

59

5. Arquitectura y desarrollo

61

5.1. Etapa 1: Despliegue mínimo de la plataforma . . . . . . . . . . . . . . . .

62

5.1.1. Establecimiento de una red 802.15.4 . . . . . . . . . . . . . . . . .

64

5.1.2. Intercambio de paquetes . . . . . . . . . . . . . . . . . . . . . . .

69

5.2. Etapa 2: Instalación y configuración de Mosquitto . . . . . . . . . . . . . .

74

5.2.1. Instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

75

5.2.2. Configuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

77

5.3. Etapa 3: Librería MQTT . . . . . . . . . . . . . . . . . . . . . . . . . . .

78

xiv

5.3.1. Estudio de la especificación . . . . . . . . . . . . . . . . . . . . .

78

5.3.2. Creación del archivo de cabecera . . . . . . . . . . . . . . . . . . .

85

5.3.3. Implementación del protocolo . . . . . . . . . . . . . . . . . . . .

87

5.4. Etapa 4: Pasarela transparente . . . . . . . . . . . . . . . . . . . . . . . .

101

5.4.1. Estructura del código . . . . . . . . . . . . . . . . . . . . . . . . .

102

5.4.2. Archivo principal tGatewayServer.cpp (transparent Gateway Server) 113 5.5. Etapa 5: Librería MQTT-SN y el software de traducción . . . . . . . . . . .

119

5.5.1. Estudio de la especificación . . . . . . . . . . . . . . . . . . . . .

120

5.5.2. Creación de los archivos de cabecera . . . . . . . . . . . . . . . .

125

5.5.3. Implementación . . . . . . . . . . . . . . . . . . . . . . . . . . . .

128

5.6. Etapa 6: Suscriptores externos . . . . . . . . . . . . . . . . . . . . . . . .

154

6. Resultados

157

6.1. Infraestructura de comunicación . . . . . . . . . . . . . . . . . . . . . . .

157

6.2. Repositorio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

159

6.3. Coste del proyecto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

159

6.3.1. Coste hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . .

160

6.3.2. Coste software . . . . . . . . . . . . . . . . . . . . . . . . . . . .

160

6.3.3. Coste de la mano de obra . . . . . . . . . . . . . . . . . . . . . . .

160

6.4. Publicación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

161

7. Conclusiones y propuestas

163

7.1. Conclusiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

163

7.2. Propuestas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

166

7.3. Conclusiones personales . . . . . . . . . . . . . . . . . . . . . . . . . . .

168

A. Manual de usuario de la librería MQTT v3.1.0

171

A.1. Conexión TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

171

A.2. Conexión MQTT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

172

A.3. Publicación MQTT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

172

A.4. Suscripción MQTT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

174

A.5. Valores de retorno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

175

A.6. Clientes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

175

B. Manual de usuario de la librería MQTT-SN v1.2

177

B.1. Instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

177

B.2. Configuración inicial . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

177

xv

B.3. Registro de topics MQTT-SN . . . . . . . . . . . . . . . . . . . . . . . . .

178

B.4. Publicación MQTT-SN . . . . . . . . . . . . . . . . . . . . . . . . . . . .

179

B.4.1. Publicación con Q O S -1 . . . . . . . . . . . . . . . . . . . . . . . .

180

B.5. Valores de retorno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

181

B.6. Clientes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

181

C. Manual sobre cómo programar Waspmote

183

C.1. IDE de Waspmote: Descarga e instalación . . . . . . . . . . . . . . . . . .

183

C.2. Cargar un nuevo programa en Waspmote . . . . . . . . . . . . . . . . . . .

184

D. Instalación y configuración de CUnit

189

D.0.1. Instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

189

D.0.2. Ejemplo de uso . . . . . . . . . . . . . . . . . . . . . . . . . . . .

190

Referencias

193

xvi

Índice de cuadros

3.1. Características de redes inalámbricas. Fuente: [tel11] . . . . . . . . . . . .

26

3.2. Middlewares. Fuente: [VSV+ 13] . . . . . . . . . . . . . . . . . . . . . . .

30

3.3. Distintas tecnologías de comunicación ofrecidas por Libelium. . . . . . . .

37

3.4. Comparativa entre brokers MQTT. Fuente: [MQT]. . . . . . . . . . . . . .

46

3.5. Comparativa entre XMPP y MQTT. . . . . . . . . . . . . . . . . . . . . .

50

5.1. Formato de la cabecera fija. Fuente: [Loc10]. . . . . . . . . . . . . . . . .

79

5.2. Tipos de mensajes y su numeración. Fuente: [Loc10]. . . . . . . . . . . . .

80

5.3. Codificación de las distintas Q O S. Fuente: [Loc10]. . . . . . . . . . . . . .

80

5.4. Flags de conexión del mensaje CONNECT. Fuente: [Loc10]. . . . . . . . .

81

5.5. Códigos de retorno al mensaje CONNECT y su significado. Fuente: [Loc10].

82

5.6. Codificación de una cadena de caracteres en MQTT. Fuente: [Loc10]. . . .

82

5.7. Descripción de los mensajes MQTT. Fuente: [Loc10]. . . . . . . . . . . . .

88

5.8. Formato de la cabecera MQTT-SN. Fuente: [SCT13]. . . . . . . . . . . . .

121

5.9. Valores de los códigos que representan los tipos de mensajes MQTT-SN. Fuente: [SCT13]. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

121

5.10. Campo flags de la cabecera variable. Fuente: [SCT13]. . . . . . . . . . . .

122

5.11. Formato de los mensajes que envían los sensores de la infraestructura. . . .

133

6.1. Lineas de código implementadas por componentes de la infraestructura. . .

160

6.2. Costes Hardware. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

160

6.3. Costes de la mano de obra. . . . . . . . . . . . . . . . . . . . . . . . . . .

161

6.4. Coste total del proyecto . . . . . . . . . . . . . . . . . . . . . . . . . . . .

161

XVII

Índice de figuras

1.1. Cadena de valor tecnológica de la Smart City . . . . . . . . . . . . . . . .

4

1.2. Modelo de distribución de eventos para uno y varios subscriptores. . . . . .

6

1.3. Figura esquemática del proyecto . . . . . . . . . . . . . . . . . . . . . . .

7

3.1. Paradigma del I OT como el resultado de las convergencia de diferentes puntos de vista. Fuente: [AIM10a] . . . . . . . . . . . . . . . . . . . . . . . .

14

3.2. Esquema de un Sistema RFID. . . . . . . . . . . . . . . . . . . . . . . . .

17

3.3. Arquitectura de alto nivel de tecnologías M2M en el marco de las Smart Cities. Fuente: [tel11] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

27

3.4. Esquema del framework Civitas. Fuente: [RAB+ 14] . . . . . . . . . . . . .

31

3.5. A la izquierda la Smart Parking Sensor Board junto con Waspmote, instalada en una plaza de aparcamiento. A la derecha uno de los paneles informativos. Fuente: [Bie13] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34

3.6. Mapa interactivo que muestra la disponibilidad de plazas de aparcamiento. Fuente: [Bie13] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34

3.7. Distintas topologías de los sistemas basados en eventos. Fuente: [LP+ 03] .

41

3.8. Arquitectura MQTT-SN. Fuente: [SCT13] . . . . . . . . . . . . . . . . . .

44

3.9. Tipos de pasarelas. Fuente: [SCT13] . . . . . . . . . . . . . . . . . . . . .

45

4.1. Etapas del proyecto. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

55

4.2. Diagrama de Gantt del proyecto. . . . . . . . . . . . . . . . . . . . . . . .

56

5.1. Arquitectura y componentes de la infraestructura. Fuente: elaboración propia. 62 5.2. Escenario bajo el que se trabaja utilizando el firmware Meshlium ZigBee AP. Fuente: [Lib13a]. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

63

5.3. Acceso a configuración de parámetros de Meshlium. . . . . . . . . . . . .

65

5.4. Chequeo de parámetros de Meshlium. . . . . . . . . . . . . . . . . . . . .

66

5.5. Captura de paquetes en Meshlium, acceso via Manager System. . . . . . . .

71

5.6. Comprobación del correcto funcionamiento de Mosquitto. . . . . . . . . .

77

5.7. Flujo de datos para una publicación con Q O S nivel 2. Fuente: elaboración propia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

84

XIX

5.8. Ejemplo de flujo de datos ordenado. Fuente: elaboración propia. . . . . . .

85

5.9. Máquina de estados para detectar la secuencia de inicio de mensaje. Fuente: Elaboración propia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

109

5.10. Escenario de actuación del mensaje CONNECT. Fuente: elaboración propia. 130 5.11. Escenario de actuación del mensaje CONNECT con las características last will and testament. Fuente: elaboración propia. . . . . . . . . . . . . . . .

130

5.12. Escenario de actuación del mensaje REGISTER. Fuente: elaboración propia. 131 5.13. Escenario de actuación del mensaje PUBLISH con Q O S 0 y 1. Fuente: elaboración propia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

132

5.14. Escenario de actuación del mensaje PUBLISH con Q O S 2. Fuente: elaboración propia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

133

5.15. Escenario de actuación del mensaje PUBLISH con Q O S -1. Fuente: elaboración propia. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

134

5.16. Mecanismo creado para la realización de los suscriptores externos. . . . . .

155

5.17. Visualización de las coordenadas publicadas por los sensores. . . . . . . . .

156

6.1. Arquitectura y componentes de la infraestructura. Fuente: elaboración propia. 158 C.1. Como encender Waspmote. Fuente: [Lib13d]. . . . . . . . . . . . . . . . .

184

C.2. Seleccionar placa adecuada. Fuente: [Lib13d]. . . . . . . . . . . . . . . . .

185

C.3. Seleccionar puerto adecuado. Fuente: [Lib13d]. . . . . . . . . . . . . . . .

185

C.4. Guardar un Sketch. Fuente: [Lib13d]. . . . . . . . . . . . . . . . . . . . . .

186

C.5. Cargar un Sketch 1. Fuente: [Lib13d]. . . . . . . . . . . . . . . . . . . . .

186

C.6. Cargar un Sketch 2. Fuente: [Lib13d]. . . . . . . . . . . . . . . . . . . . .

187

D.1. Estructura del framework CUnit. . . . . . . . . . . . . . . . . . . . . . . .

190

xx

Índice de listados 5.1. Código de Libelium ejemplo 802_01 - configure XBee basic parameters. . .

65

5.2. Código de Libelium ejemplo 802_02 - send packets. . . . . . . . . . . . . .

69

5.3. Código de Libelium ejemplo 802_11b - complete example receive. . . . . .

72

5.4. Archivo de cabecera tras codificar el formato de lo mensajes de MQTT. . .

86

5.5. Suite para los test MQTT. . . . . . . . . . . . . . . . . . . . . . . . . . . .

90

5.6. Test para el escenario CONNECT/DISCONNECT. . . . . . . . . . . . . .

91

5.7. Manejador de conexión con el broker. . . . . . . . . . . . . . . . . . . . .

92

5.8. Prototipos de las funciones necesarias para el escenario CONNECT/DISCONNECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

92

5.9. Función de inicialización del manejador de conexión . . . . . . . . . . . .

94

5.10. Implementación del mensaje CONNACK. . . . . . . . . . . . . . . . . . .

95

5.11. Implementación del mensaje DISCONNECT. . . . . . . . . . . . . . . . .

96

5.12. Implementación del mensaje CONNECT. . . . . . . . . . . . . . . . . . .

98

5.13. Código de la función xbee_init() . . . . . . . . . . . . . . . . . . . . . . .

106

5.14. Código principal de xbee_getPacket() . . . . . . . . . . . . . . . . . . . .

108

5.15. Código ejemplo de xbee_parsePacket() . . . . . . . . . . . . . . . . . . . .

111

5.16. Código de la primera versión del archivo WaspMqttSN.h . . . . . . . . . .

126

5.17. Código de la función obtain_sensorMac() . . . . . . . . . . . . . . . . . .

135

5.18. Test del escenario CONNECT/DISCONNECT . . . . . . . . . . . . . . .

135

5.19. Código de las funciones del escenario CONNECT/DISCONNECT . . . . .

137

5.20. Código de las funciones de conversión del escenario CONNECT/DISCONNECT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

138

5.21. Test del escenario REGISTER . . . . . . . . . . . . . . . . . . . . . . . .

139

5.22. Código de las funciones de la librería del escenario REGISTER . . . . . .

141

5.23. Código de las funciones de la pasarela del escenario REGISTER . . . . . .

143

5.24. Test del escenario PUBLISH . . . . . . . . . . . . . . . . . . . . . . . . .

144

5.25. Código de las funciones del escenario PUBLISH . . . . . . . . . . . . . .

146

5.26. Código de las partes de traducción del escenario PUBLISH . . . . . . . . .

148

5.27. Test del escenario PING . . . . . . . . . . . . . . . . . . . . . . . . . . .

151

XXI

5.28. Código de las funciones del escenario PING . . . . . . . . . . . . . . . . .

152

5.29. Código de las partes de traducción del escenario PING . . . . . . . . . . .

153

A.1. Cliente MQTT que publica utilizando distintos niveles de Q O S . . . . . . .

173

A.2. Cliente MQTT que se suscribe a un topic y después cancela esta suscripción. 174 B.1. Ejemplo de configuración de cliente. . . . . . . . . . . . . . . . . . . . . .

178

B.2. Ejemplo de registro de topic name de un cliente. . . . . . . . . . . . . . . .

179

B.3. Ejemplo de publish con Q O S 1. . . . . . . . . . . . . . . . . . . . . . . . .

180

B.4. Ejemplo de publish con Q O S -1. . . . . . . . . . . . . . . . . . . . . . . .

180

D.1. Código de ejemplo de uso de CUnit . . . . . . . . . . . . . . . . . . . . .

191

xxii

Listado de acrónimos AMQP

Advanced Message Queuing Protocol

API

Application Programming Interface

C/S

Cliente/Servidor

EPC

Electronic Product Code

E/S

Entrada/Salida

GNU

GNU is Not Unix

GPL

General Public License

GPRS

General Packet Radio Service

HTML

HyperText Markup Language

HTTP

Hypertext Transfer Protocol

ICT

Information and Communications Technologies

IDE

Entorno de Desarrollo Integrado

IDL

Interface Description Language

IoT

Internet of Things

IP

Internet Protocol

IPSO

IP for Smart Objects Alliance

JVM

Java Virtual Machine

LSB

Least Significant Byte

MAC

Media Access Control

MSB

Most Significant Byte

M2M

Machine-to-Machine

NFC

Near Field Communications

OTA

Over The Air Programming

POE

Power Over Ethernet

P2P

Peer-to-Peer

QoS

Quality of Service

XXIII

RFID

Radio-Frequency IDentification

SASL

Simple Authentication and Security Layer

SCADA

Supervisory Control and Data Acquisition

TCP

Transmision Control Protocol

TDD

Test Driven Development

TIC

Tecnologías de la Información y la Comunicación

TFG

Trabajo Fin de Grado

uID

Unique/Universal/Ubiquitous IDentifier

UTF

Unicode Transformation Format

VoIP

Voice over IP

WISP

Wireless Identification and Sensing Platforms

XML

eXtensible Markup Language

XMPP

eXtensible Messaging and Presence Protocol

XP

eXtreme Programming

xxiv

Capítulo 1

Introducción

L

evolución en eficiencia, comunicaciones, coste, etc. de las tecnologías de la información está permitiendo que sean abordables nuevos paradigmas hasta hace unos años impensables. Uno de estos paradigmas es el Internet de las Cosas (en adelante I OT, del inglés Internet of Things), el cual se entiende como la conexión de los objetos más cotidianos a Internet y se ha convertido en un concepto de actualidad con una gran proyección de futuro. Uno de los hechos más recientes que nos hacen ver la importancia que el I OT está adquiriendo es que Google está apostando fuerte en este sector, la empresa Estadounidense ha adquirido recientemente por 3.200 millones de dólares a Nest Labs, una empresa que está detrás de los termostatos y detectores de humo inteligentes, en lo que no es sino uno de los muchos ejemplos de que habrá grandes inversiones en este campo en los próximos años. A

También es importante mencionar la relevancia que el I OT está tomando en España, donde en los últimos años se han creado startups como Carriots1 o Bitcarrier2 , además de proyectos de investigación como Smart Malaga, Barcelona o SmartSantander, este último ha sido reconocido a nivel Europeo por sus buenos resultados y su realización ha convertido a Santander en la primera ciudad inteligente integral de Europa. Por último, es muy importante mencionar a la empresa Libelium3 , que también es española y que tiene un reconocido prestigio internacional en la industria de los sensores. A lo largo del documento se hablará de esta empresa y de sus productos, ya que algunos de ellos han sido utilizados en este Trabajo Fin de Grado (TFG). Pero, ¿en qué consiste el I OT? Puede verse como un paradigma en el que los objetos cotidianos tienen la capacidad de conectarse a la red, enviar datos a través de ella y/o recibir algunos de estos datos, interpretarlos y actuar consecuentemente para nuestro beneficio. Un ejemplo sencillo podemos verlo en el campo de la domótica, donde por ejemplo, desde nuestro smartphone podemos encender el horno, controlar el termostato de la calefacción o cualquier tarea del hogar que pueda automatizarse. Si ampliamos este concepto y hacemos que estos u otros objetos usen esta tecnología para conectarse a Internet, las posibilidades de uso de este paradigma se multiplican. Todo esto hace pensar que el I OT transformará nuestro 1

https://www.carriots.com http://www.bitcarrier.com 3 http://www.libelium.com/es/ 2

1

2

CAPÍTULO 1. INTRODUCCIÓN

entorno y los objetos cotidianos para hacerlos mucho más inteligentes, con el objetivo de hacernos la vida más cómoda e, incluso, contribuirá a que seamos más eficientes a la hora de gestionar nuestro tiempo o nuestros recursos [AIM10b]. De esta forma, se prevé una especial importancia en el desarrollo de sistemas informáticos que usen o que estén basados en el I OT.

1.1 IoT y las ciudades inteligentes Uno de los principales campos de aplicación del I OT son las Smart Cities o ciudades inteligentes. En la Smart City cualquier proceso que se lleve a cabo a diario en una ciudad, puede verse beneficiado dado que está apareciendo la tecnología necesaria para recopilar, transmitir y gestionar la información que se considere importante para ese proceso, y después interpretar esta información y actuar en consecuencia para lograr un beneficio común. Si se piensa en la Smart City desde un punto de vista social, esta puede verse como un tipo de desarrollo urbano basado en la sostenibilidad, que es capaz de responder adecuadamente a las necesidades básicas de instituciones, empresas, y de los propios habitantes, tanto en el plano económico, como en los aspectos operativos, sociales y ambientales [SKP+ 11]. Una Smart City cuyos servicios se aprovechasen de forma correcta, impulsaría el crecimiento económico sostenible y «teóricamente» la prosperidad para sus ciudadanos, ya que sus dirigentes dispondrían de las herramientas necesarias para analizar los datos que les permitirían tomar mejores decisiones, anticiparse a los problemas para resolverlos de forma proactiva y coordinar los recursos para actuar de forma eficiente. Es importante entender el factor social que llevan asociado las Smart Cities, así como sus posibles beneficios para la población, organizaciones e instituciones, pero para comprender la importancia de este TFG es necesario centrarse en los aspectos tecnológicos de las Smart Cities: qué tecnologías se usan, qué problemas surgen, posibles soluciones, etc.

1.1.1

Aspectos tecnológicos

Desde un punto de vista tecnológico, el concepto de I OT aplicado al campo de las ciudades inteligentes, presenta una serie de retos que deben ser abordados desde diferentes puntos de vista, como lo son el hardware, el software, la metodología en el desarrollo de servicios, la seguridad, etc. Para tener una visión amplia de las tecnologías que forman parte de una Smart City, se define de forma resumida, lo que se puede denominar como «cadena de valor tecnológica» de la Smart City [tel11]: En primer lugar se encuentra la etapa de recolección de datos de la ciudad. Esta tarea se realiza utilizando redes de sensores, actuadores y diferentes dispositivos de captura de datos que permitan la recolección de información. Entre estos dispositivos hay

1.1. IOT Y LAS CIUDADES INTELIGENTES

3

que incluir los móviles de las personas, diferentes aparatos del entorno del hogar, los vehículos, así como los dispositivos de medida situados en infraestructuras fijas, como mobiliario urbano, edificios, sistemas de canalización y tuberías, estaciones meteorológicas y así un largo etc. La forma que utilizan estos dispositivos para comunicarse con otros que estén fuera de su red, es haciendo uso de la infraestructura desplegada para Internet. Este escenario es, por definición, un entorno de I OT. En segundo lugar se realiza la transmisión de los datos recopilados de la ciudad a través de las redes de comunicación. Esto se lleva a cabo mediante una combinación de infraestructura inalámbrica, móvil y fija dependiendo de las necesidades de movilidad, ancho de banda y latencia de la aplicación en concreto. En algunos casos las redes inalámbricas y móviles serán las únicas de las que se disponga y sus arquitecturas pueden ser muy variadas. Por regla general, los sensores transmitirán la información a través de protocolos ligeros a coordinadores o gateways que a su vez enrutarán los datos a través de líneas móviles o fijas y lo harán llegar a las bases de datos y plataformas que faciliten la provisión de los servicios. En este punto toman especial importancia las comunicaciones entre dispositivos, en lo que se ha denominado M2M (del inglés, Machine-to-Machine). Este tipo de comunicaciones son muy comunes en el entorno de las Smart Cities y están teniendo también un gran impacto gracias al desarrollo de las nuevas redes inalámbricas. Una tercera fase comprende el almacenamiento y el análisis de los datos. Se trata de almacenar en una plataforma central los datos recopilados en el entorno de la ciudad al mismo tiempo que se facilita su procesamiento posterior mediante diferentes sistemas analíticos. En cuarto lugar, los datos alimentan una plataforma de provisión de servicios que facilita la prestación de los servicios en el ámbito de la Smart City. Se trata de una plataforma horizontal y escalable, que permite ofrecer servicios de una manera segura y con garantías de privacidad. La plataforma en el seno de la cual se desarrolla este TFG, es el middleware Civitas (véase Sección 1.1.2). Finalmente se encuentran los servicios de la Smart City, que podrán ser desarrollados por los mismos agentes involucrados en el resto de la cadena, o por otros agentes. Estos servicios se apoyan en todas las tecnologías, infraestructuras y plataformas anteriormente comentadas para ofrecer su valor final al cliente. Hay numerosos ejemplos de servicios finales posibles, tantos como servicios públicos que ha de prestar un Ayuntamiento, aunque no únicamente.

4

CAPÍTULO 1. INTRODUCCIÓN

En la Figura 1.1 puede verse de forma esquemática el proceso que forma esta «cadena de valor tecnológica».

Figura 1.1: Cadena de valor tecnológica de la Smart City

1.1.2

Civitas, un middleware para las Smart Cities

En el seno del grupo de investigación Arco de la Escuela Superior de Informática de la Universidad de Castilla-La Mancha se está desarrollando una plataforma para ciudades inteligentes que pretende abordar todas las etapas anteriormente descritas y que se denomina Civitas [VSV+ 13]. Civitas nace ante la necesidad de una plataforma que gestione la heterogeneidad en cuanto a estándares, protocolos y formatos de representación de datos, de los dispositivos y de las redes que forman parte de las etapas de recolección y transmisión de datos de una Smart City. Como plataforma para las Smart Cities, Civitas necesita ser capaz de adaptarse a nuevas tecnologías, con el fin de adoptar fácilmente nuevas formas de recolectar datos del entorno. La infraestructura que se desarrolla con este TFG pretende formar parte de uno de los métodos de los que dispone Civitas para recopilar información de la ciudad, este modelo de recolección de datos está basado en eventos, que como se verá en la siguiente sección, es ideal para el marco de la Smart City.

1.2. PARADIGMA DE PROGRAMACIÓN BASADO EN EVENTOS

5

1.2 Paradigma de programación basado en eventos El software es uno de los aspectos que más importancia tiene en este TFG, en la ciudad se generan datos que deben ser transferidos a través de los diferentes dispositivos que forman parte de las infraestructuras subyacentes a la Smart City, con el objetivo de que esta pueda utilizarlos para proporcionar sus servicios. Esta parte de generación y transmisión de datos es crucial en el proceso de prestación de servicios de una Smart City, y se corresponde con las dos primeras etapas explicadas en la Sección 1.1.1. A la hora de generar y de recibir información, uno de los paradigmas de programación que mejor se adapta al I OT es la programación orientada a eventos. Este tipo de programación se basa en un modelo de comunicación en el que interactúan dos o más elementos, donde unos son productores de eventos, y otros consumidores de los mismos. Los productores generan información (con un formato preestablecido) y la distribuyen a través de un broker o canal de eventos a uno o varios consumidores. En este contexto, se entiende por broker a un servidor que implementa un protocolo basado en este tipo de paradigma, y que, a grandes rasgos, se encarga de gestionar la misma y distribuir los eventos. Como en todo proceso de comunicación, entre productor y consumidor debe de establecerse un canal para que el mensaje pueda ser enviado/recibido, en este caso se usa un canal de eventos, que no es sino un canal lógico al cual se subscriben los productores/consumidores para enviar o recibir eventos. Los diversos canales de eventos son gestionados por el broker. Las ventajas de este paradigma en cuanto a bajo acoplamiento, escalabilidad, sencillez de gestión, etc. hacen que esté destinado a jugar un rol importante en el I OT. En la Figura 1.2 puede verse un esquema de un modelo basado en eventos, notesé que la complejidad del modelo no varía haya uno o varios elementos de comunicación. El broker recibe las subscripciones por parte de los consumidores, los cuales indican el tipo de eventos en los que están interesados mediante un identificador de canal de eventos (topic), a partir de este momento, todo evento generado por un productor de eventos, es enviado a todos los consumidores subscritos.

1.2.1

MQTT y MQTT-SN, protocolos para el I OT

En el marco de los paradigmas que siguen un modelo basado en la distribución de eventos, una de las plataformas más prometedoras es la definida por IBM en la decada de los 90, asociada al protocolo MQTT [Loc10]. Este protocolo ha sido seleccionado recientemente por OASIS4 , como uno de los protocolos destinados a soportar el paradigma del I OT y por ende, las Smart Cities. Además de esto, desde que IBM liberara la especificación de este protocolo, su uso ha crecido paulatinamente, llegando a estar en auge en la actualidad. En este aspecto cabe destacar la contribución del Eclipse Paho Project, un proyecto que está en 4

OASIS es un consorcio de empresas cuyo cometido es guiar el desarrollo, la convergencia y la adopción de estándares abiertos con el objetivo de globalizar la sociedad de la información.

6

CAPÍTULO 1. INTRODUCCIÓN

Figura 1.2: Modelo de distribución de eventos para uno y varios subscriptores. continuo desarrollo por la fundación Eclipse, cuyo objetivo es implementar clientes MQTT en varios lenguajes de programación, como Java, C o JavaScript, y que publicó su primera versión de las librerías MQTT en Junio de 2014. En esencia, MQTT es un protocolo muy ligero, asíncrono y basado en la publicación/suscripción de mensajes. Sus principios de diseño lo hacen ideal para paradigmas emergentes como M2M, el I OT, las aplicaciones móviles y las redes de sensores. MQTT opera sobre redes TCP/IP. Consecuentemente, este protocolo no puede ser ejecutado directamente sobre una red de sensores ya que estas no tienen porque estar adaptadas a las redes TCP/IP y generalemente tienen su propia pila de protocolos. Para solventar este problema, IBM desarrolló MQTT-SN [SCT13] como una extensión de MQTT adaptada a las peculiaridades de una red de sensores. El objetivo principal de este TFG es la creación de una infraestructura basada en eventos MQTT/MQTT-SN para el I OT, con el fin de proporcionar a Civitas (véase Sección 1.1.2) los datos necesarios acerca de qué está pasando en la ciudad. Para ello se implementará el protocolo MQTT/MQTT-SN en una red de sensores/pasarelas de la empresa Libelium. En la Figura 1.3 puede verse un esquema de la citada infraestructura, en el cual existen tres elementos bien diferenciados: En la parte inferior se encuentra una red de sensores formada por dos tipos de elementos: sensores y pasarelas o gateways. Los sensores se comunican con las pasarelas

1.2. PARADIGMA DE PROGRAMACIÓN BASADO EN EVENTOS

7

Figura 1.3: Figura esquemática del proyecto mediante el protocolo MQTT-SN y su fin último es publicar información del entorno. Las pasarelas por regla general sirven para interconectar dos redes con tecnologías diferentes, en este caso interconectan una red de sensores en la que se usa MQTT-SN sobre 802.15.4 con una red TCP/IP en la que se encuentra el broker MQTT. Con lo cual, la pasarela debe de realizar una conversión entre ambos protocolos. Además de esto, en ocasiones deberá actuar como servidor para los sensores, debido a requisitos del protocolo MQTT-SN. Como puede observarse, esta parte del esquema se corresponde con las dos primeras etapas de la «cadena de valor tecnológica de las Smart City» que se han introducido en la Sección 1.1.1 y que se describen detalladamente en la Sección 3.2.1. En la parte central se encuentra una «nube» representando todo el proceso que se lleva a cabo para gestionar y distribuir los eventos que generan los sensores y que llegan hasta aquí a través de las pasarelas. Por último, en la parte de arriba se encuentran los receptores de la información generada por la red subyacente: usuarios, gobierno, empresas, instituciones y asociaciones, entre otros.

Capítulo 2

Objetivos

E

el siguiente capítulo se presentan los objetivos que se marcaron para el desarrollo de este TFG, a partir de la propuesta de Anteproyecto. Tras finalizar este capítulo, el lector tendrá consciencia de lo que pretende conseguirse con el desarrollo de los mismos, y del ámbito y el alcance de los resultados obtenidos tras su realización. N

2.1 Objetivo general En términos generales, se pretende crear una infraestructura que use un modelo de comunicación basado en la publicación/suscripción de eventos, para el I OT. El objetivo es que los dispositivos de una plataforma sensora puedan publicar información acerca de que está ocurriendo en su entorno, y esta llegue, a través de la infraestructura, a cualquier suscriptor que se encuentre en una red externa. Actuando de esta forma, como un middleware que proporciona la información que genera el I OT en un entorno concreto, ocultando los detalles de las tecnologías que hay por debajo de él. Como base al desarrollo de la infraestructura, se despliega una plataforma sensora de la empresa Libelium, sobre la que se implementará una lógica de comunicación utilizando los protocolos MQTT, MQTT-SN y un software para la pasarela. A su vez, la infraestructura pretende formar parte del framework Civitas, como uno de los métodos que tiene la Smart City para recopilar información de su entorno.

2.2 Objetivos específicos El desarrollo de esta infraestructura conlleva la creación de una serie de elementos software y de su interoperabilidad, a partir de la cual el flujo de información se irá desplazando desde los sensores hasta servidores en redes externas, y en última instancia a los receptores de información. Lograr obtener buenos resultados en la implementación de las distintas partes que hacen funcionar la infraestructura, desembocará inequívocamente en un funcionamiento correcto de la misma. El desarrollo de estas partes se consigue a partir del planteamiento de los objetivos específicos que se exponen en apartados sucesivos. 9

10

2.2.1

CAPÍTULO 2. OBJETIVOS

Diseño e implementación de una librería MQTT-SN

El flujo de eventos que recorrerá la infraestructura se llevará a cabo utilizando los protocolos MQTT-SN y MQTT. MQTT-SN es un protocolo pensado para actuar en redes de sensores, y tendrá la función de realizar la interacción entre la pasarela y los sensores que estén conectados en red a ella. En este caso los sensores son dispositivos Waspmote de la empresa Libelium, se ha elegido esta empresa debido a su prestigio tanto nacional como internacional, a que es una empresa líder en el campo de los sensores y a que tanto el hardware como el software que distribuyen, es libre. Con lo cual, para que pueda escribirse código que haga que estos dispositivos utilicen MQTT-SN, deberá implementarse una librería del protocolo que pueda ejecutarse sobre ellos. Aunque la implementación se va a realizar sobre redes y dispositivos de esta empresa, también forma parte de este objetivo, el realizar todo el software de forma que adaptarlo a distintas tecnologías, se realizase con un esfuerzo y coste mínimos. De forma que, por ejemplo, si las distintas librerías están bien modularizadas, un cambio en la tecnología de acceso al medio tan solo conllevaría modificar la parte del código encargada de la funcionalidad de enviar/recibir datos por la red subyacente, y no el envío o la recepción de cada mensaje.

2.2.2

Diseño e implementación de una pasarela software

Para que los datos que se generan en la red de sensores lleguen a una red de nivel superior, como TCP/IP, es necesaria la participación de unos dispositivos conocidos como pasarelas. En este caso se utiliza la pasarela Meshlium de la empresa Libelium, cuya función será la de mantener comunicación tanto con los sensores como con un broker MQTT, realizando una traducción entre MQTT-SN y MQTT, y viceversa. En concreto deberá implementarse un tipo de pasarela llamado pasarela transparente. Este tipo de pasarelas mantienen una conexión con el «broker» (véase Sección 3.3.2) por cada cliente MQTT-SN conectado.

2.2.3

Diseño e implementación de una librería MQTT

Una de las partes más importantes del software de traducción es la comunicación que se debe de establecer con el broker MQTT, una vez que se hayan traducido los mensajes MQTT-SN. Para establecer esta comunicación y para que la tarea de traducción resulte más sencilla, se implementará una librería para el protocolo MQTT. Con el desarrollo de este objetivo se dotará a la infraestructura de la capacidad de trasladar por completo la información que han recopilado y publicado los sensores, hacía una red TCP/IP en la que se encontrará un broker MQTT, el cual se encargará de distribuir estas publicaciones de eventos, a cualquier suscriptor que se suscriba al canal de eventos en el que han publicado los sensores.

2.2. OBJETIVOS ESPECÍFICOS

2.2.4

11

Diseño de un suscriptor en una red externa

Desarrollada la infraestructura, surge la necesidad de situarla bajo un escenario de actuación real para comprobar que funciona de forma correcta. Para llevar a cabo esta tarea, se va a implementar un mecanismo mediante el cual cualquier dispositivo situado en una red externa, pueda acceder a través de Internet y de un navegador web a la información que publican los sensores, en tiempo real. Esta implementación se realizará con tecnologías web para que sea multiplataforma y se trabajará sobre un escenario en el que los sensores publican su geolocalización, y esta se muestra en un mapa situado en el navegador del suscriptor externo. Notesé, que para cumplir con lo especificado en este objetivo, hace falta disponer de la infraestructura completamente desarrollada, y sus resultados indicarán sin lugar a dudas, no solo un completo conocimiento del ámbito del proyecto y sus posibles aplicaciones, sino también que la infraestructura está preparada para actuar en un entorno real.

2.2.5

Diseño y validación de escenarios de test

Se pretende desarrollar la infraestructura de tal forma, que una vez concluidos los esfuerzos de implementación, se disponga de una serie de escenarios de test que permitan la validación de todas las funcionalidades implementadas.

Capítulo 3

Antecedentes

E

ámbito de aplicación de este proyecto comprende algunos de los paradigmas más prometedores de cara al futuro de las nuevas tecnologías y a su aplicación para nuestro beneficio. Estos paradigmas son el Internet de las Cosas y las ciudades inteligentes o Smart Cities. Como señala la Fundación Telefónica en su último informe sobre Smart Cities [tel11], en un contexto tecnológico, el concepto de Smart City y el de I OT son dos términos que van de la mano ya que ambos tienen en las comunicaciones M2M su fundamento y adelantan el Internet del futuro que permitirá la conexión no sólo de las personas, sino también de los objetos, configurando de esta forma un mundo digital. L

Por otra parte, una de las aproximaciones más prometedoras en este ámbito es la programación orientada a eventos, con lo cual una Smart City necesita incorporar tecnologías de publicación/suscripción de eventos, que le permitan adecuarse a esta situación. En este capítulo se pretende situar al lector en el contexto del proyecto, en primer lugar se tratan los dos grandes ámbitos de aplicación de este TFG, Internet de las Cosas y las Smart Cities, en ambos casos se mostrará su estado actual y cuales son las principales tecnologías involucradas y que rol jugaría la implementación de este proyecto en dichos ámbitos. En tercer lugar se estudia el estado del arte de la programación orientada a eventos y la descripción de los protocolos MQTT y MQTT-SN, de cara a introducir al lector en este paradigma y en los protocolos seleccionados. De igual forma se mostrarán las características de la plataforma seleccionada para la implementación de referencia de dichos protocolos.

3.1 Internet de las Cosas Hoy en día se pueden encontrar múltiples definiciones de I OT dentro de la comunidad de investigación, buscando en la literatura existente sobre este tema a un lector interesado podría resultarle difícil entender lo que este paradigma realmente significa, que ideas básicas están detrás de este concepto y que implicaciones sociales, económicas y técnicas supondría un despliegue completo del I OT. La razón por la que el significado de este concepto sigue estando borroso no es otra que su propio nombre, «Internet de las Cosas», el cual está compuesto sintácticamente por dos términos. El primero de ellos te sitúa en el contexto de la red global Internet, mientras que 13

14

CAPÍTULO 3. ANTECEDENTES

el segundo te lleva a imaginar un conjunto de «objetos» integrados en un framework común. La diferencia principal entre estos dos puntos de vista se debe al hecho de que los stakeholders, el mundo empresarial, la comunidad de investigación y los organismos de estandarización, comienzan a abordar el tema desde diferentes perspectivas, bién desde una perspectiva «orientada a Internet», o bién desde otra «orientada a cosas», dependiendo en cualquier caso de unos intereses, finalidad y trasfondo específicos. Además, la necesidad de un direccionamiento único por «objeto» y la representación y almacenamiento de la información intercambiada, se han convertido en uno de los retos más desafiantes de este paradigma, surgiendo de esta forma una tercera perspectiva, la llamada «orientada a la semántica». En la Figura 3.1 pueden verse los conceptos principales, las tecnologías y estándares destacados, clasificados según la perspectiva/s en la que se encuentran. Viendo la figura queda claro que el I OT es el resultado de la convergencia entre 3 puntos de vista distintos.

Figura 3.1: Paradigma del I OT como el resultado de las convergencia de diferentes puntos de vista. Fuente: [AIM10a] La definición original de I OT derivaba de la perspectiva «orientada a cosas»; el término «cosas» es sencillo, se consideraba como «cosas» a todo aquello que lleve una etiqueta RFID (Radio-Frequency IDentification). De hecho, el termino completo «Internet de las Cosas», se atribuye a The Auto-ID Labs1 , una red global de laboratorios de investigación en el campo de 1

http://autoidlabs.org/

3.1. INTERNET DE LAS COSAS

15

las redes RFID y las tecnologías sensoras emergentes. Estas instituciones, desde su creación, se han encargado de estructurar el I OT, junto con EPCglobal [JHU+ 05]. Su objetivo principal ha sido el desarrollo del EPC (Electronic Product Code) [Bro01], con el propósito de dar soporte al uso de RFID en las redes de área global modernas. Estos estándares se diseñaron con la intención de mejorar la visibilidad de los objetos dentro de un framework común. En un sentido más amplio, el I OT no puede ser simplemente un sistema global de EPCs, donde los únicos objetos son RFIDs; estos serán parte de un todo mucho mayor. Y lo mismo se puede aplicar a la arquitectura alternativa Unique/Universal/Ubiquitous IDentifier (U ID), que se propone en [Sak06], cuya idea principal sigue siendo el desarrollo de soluciones (basadas en middleware en este caso) que logren dotar al I OT de una visibilidad global de los objetos. No obstante, esta alternativa es de alguna manera más completa que la anterior, ya que este paradigma implica tener una visión más amplia que simplemente un identificador de cada objeto. De acuerdo a los autores de [PG09], RFID se mantendrá algún tiempo en la vanguardia de las tecnologías de este campo, debido a su madurez, su bajo coste y a un fuerte apoyo desde el mundo de los negocios. Sin embargo, afirman que con el tiempo el I OT estará formado por una amplia gama de dispositivos, redes y tecnologías (hecho que está teniendo lugar hoy en día). Por otra parte, la tecnología NFC (Near Field Communications) y las redes de sensores/actuadores (WSAN) junto con RFID, están reconocidas como «los componentes atómicos que enlazarán el mundo real con el mundo digital». También vale la pena destacar que la mayoría de los proyectos están siendo llevados a cabo con el objetivo de desarrollar plataformas que permitan el uso de estas tecnologías, como el proyecto WISP (Wireless Identification and Sensing Platforms) [Rad12]. Otras instituciones han insistido en que el concepto de I OT tiene que estar principalmente centrado en las «cosas» y que el camino hacia un despliegue total de este paradigma, debe empezar por un aumento de la inteligencia de dichas «cosas». Surgen, de esta forma, lo que se conoce como Smart Items, que son conjuntos de sensores equipados no solo con capacidad comunicativa inalámbrica y con memoria, sino que también poseen potencial para ser autónomos y tener un comportamiento proactivo, conocimiento del contexto de sus acciones y comunicaciones colaborativas. Un dispositivo de este tipo sería algo similar a los Smartphones y un ejemplo de aplicación, los ambientes inteligentes (del inglés, Smart Environments). Uno de los puntos de vista que va más allá del enfoque RFID, es el propuesto por el consorcio CASAGRAS [DV08]. Sus miembros se centran en “un mundo donde las cosas puedan comunicarse de forma automática entre ellas y con computadores, proporcionando servicios para el beneficio de la humanidad”. CASAGRAS busca dos objetivos: Proponer una visión del I OT como una infraestructura global donde están conectados

16

CAPÍTULO 3. ANTECEDENTES tanto objetos virtuales como físicos. Resaltar la importancia de incluir la infraestructura desplegada para Internet.

Esta definición juega un rol importante ya que une de alguna forma dos de las tres perspectivas en las que se divide el I OT. La «orientada a cosas» y la «orientada a Internet». Dentro de esta última perspectiva encaja la visión de la IPSO (IP for Smart Objects Alliance) [DV08]. Según la cual, la pila IP (Internet Protocol) está formada por protocolos ligeros que ya conectan una gran cantidad de dispositivos y que pueden correr en sistemas empotrados con recursos limitados. Esto garantiza que IP tiene todas las características necesarias para hacer el I OT una realidad. La IPSO, además, expresa que todo pasa por realizar una buena adaptación de IP y por incorporar el estándar IEEE 802.15.4 a la arquitectura IP, como se ve en 6LoWPAN [HCC09] el despliegue de este paradigma sería automático. Internet 0 [GKC04] sigue un enfoque similar, propone reducir la complejidad de la pila IP para conseguir un protocolo que este diseñado para enrrutar «IP sobre cualquier objeto». De acuerdo tanto a los enfoques de IPSO como de Internet 0, el despliegue del I OT pasa por realizar una simplificación del actual IP, para adaptarlo a cualquier objeto y hacer que estos objetos sean direccionables y alcanzables desde cualquier localización. Como se ha dicho anteriormente, existe otra perspectiva dentro del I OT, la «orientada a la semántica». La idea que hay detrás de ella se basa en que el número de objetos involucrados en el Internet del futuro, será extremadamente grande, y en este contexto, las tecnologías semánticas pueden jugar un rol importante. Como por ejemplo, el razonamiento sobre los datos generados o la ejecución semántica de entornos y arquitecturas que adapten los requisitos del paradigma y proporcionen almacenamiento y comunicación escalables dentro de la infraestructura [TSH09].

3.1.1

Tecnologías de identificación, captura y comunicación

«En cualquier momento, en cualquier lugar, cualquier contenido multimedia» ha sido durante muchos tiempo la visión bajo la que se han producido los mayores avances en las tecnologías de comunicación. En este contexto, las tecnologías inalámbricas han jugado un rol fundamental y hoy en día la relación entre radiotransmisores y seres humanos, está cerca del uno por uno [Sri06]. Sin embargo, la reducción en términos de tamaño, peso, energía consumida y coste del radiotransmisor, puede llevarnos a una nueva era donde la relación anterior se vea incrementada en varios ordenes de magnitud. Esto permitirá integrar radiotransmisores en la mayoría de los objetos, y con ello, añadir «cualquier cosa» a la visión comentada anteriormente, la cual conduce inequívocamente al concepto de I OT. En este marco, el componente clave serán los sistemas RFID [Fin10], los cuales están compuestos de uno o más lectores y varias etiquetas RFID. La etiqueta consiste en un microchip que va adjunto a una antena de radio y que sirve para identificar unívocamente al elemento portador de la etiqueta, con esto se puede llegar a almacenar hasta 2KB de datos. El lector

3.1. INTERNET DE LAS COSAS

17

debe de ser capaz de leer los datos almacenados en la etiqueta, lo más normal será contar con un dispositivo que tenga una o más antenas que emitan ondas de radio y que reciban las señales devueltas por la etiqueta RFID. Una vez hecho esto se puede trabajar con un ordenador sobre los datos que se han leído (veasé Figura 3.2).

Figura 3.2: Esquema de un Sistema RFID. . Los sistemas RFID pueden ser usados en un rango de escenarios de aplicación muy amplio, desde aspectos puramente logísticos hasta usos sanitarios o de seguridad. Las redes de sensores también juegan un rol crucial en el I OT. De hecho, pueden cooperar con los sistemas RFID para mejorar el seguimiento de las «cosas», p.e. su localización, temperatura, movimientos, etc. consiguiendo con ello un aumento del conocimiento que se tenga sobre un cierto entorno y así, actuar como un enlace más entre el mundo físico y el digital. El uso de redes de sensores ha sido propuesto en muchos escenarios de aplicación, como en monitorización de entornos medioambientales, sanidad, sistemas inteligentes de transporte, militar y en monitorización de plantas industriales. Este tipo de redes están formadas por un determinado número de nodos sensores (normalmente un número alto), que se comunican de forma inalámbrica con el resto de dispositivos de la red, que pueden ser o nodos «sumideros» (del inglés sinks) o pasarelas. Estas últimas se encargan de enlazar la red de sensores con una red de transporte de nivel superior, como

18

CAPÍTULO 3. ANTECEDENTES

puede ser TCP/IP. La mayor parte de la literatura científica que se ha escrito sobre las redes de sensores, dirige sus esfuerzos a problemas relacionados con su pila de protocolos, como en [ASSC02]. Hoy en día, la mayoría de las soluciones comerciales para las redes de sensores inalámbricas, están basadas en el estándar IEEE 802.15.4, que define las capas física y MAC (Media Access Control). Este estándar no incluye especificaciones de las capas superiores de la pila de protocolos, y estas son necesarias para una integración sin fisuras de los nodos sensores dentro de Internet. El hecho de integrar los sensores en la infraestructura global de Internet supone una dificultad añadida para el despliegue de estas redes, por varias razones: Las redes de sensores están formadas por un gran número de nodos, y esto puede conllevar problemas obvios ya que hoy en día hay escasa disponibilidad de direcciones IP. El paquete más grande en IEEE 802.15.4 tiene una longitud de 127 bytes; lo que conlleva que los frames de la capa de acceso al medio tengan un tamaño de 102 octetos, que incluso puede verse disminuido dependiendo del tipo de seguridad que se use. Estos tamaños son demasiado pequeños si los comparamos con el tamaño típico de un paquete IP. En muchos escenarios los sensores pasan la mayor parte del tiempo en estado «durmiente» con el fin de ahorrar energía y no se pueden comunicar durante este periodo. Esto es absolutamente anómalo para las redes IP. La integración de tecnologías sensoras con las etiquetas RFID, permitirá el despliegue de un gran número de nuevas aplicaciones en el campo del I OT, especialmente en el área de la sanidad [MOA10]. Esta integración de tecnologías da como resultado lo que se conoce como sistemas sensores RFID y permitirán formar redes de sensores RFID (RSN) [BGS+ 08], que consisten en pequeños dispositivos con capacidad de cómputo y basados en RFID, y lectores de RFID, que actúan como los sumideros de la información generada por las etiquetas RFID y proporcionan la potencia necesaria para que funcione la red.

3.1.2

Importancia del middleware

El middleware es una capa de software o un conjunto de subcapas, interpuestas entre los niveles tecnológico y de aplicación. Tiene la característica de ocultar los detalles de las diferentes tecnologías que están por debajo de él, y esto es fundamental para eximir al programador de problemas que no están directamente relacionados con su propósito, que no es otro que el desarrollo de una aplicación especifica que hace uso de las infraestructuras del I OT

En los últimos años se está incrementando la importancia del middleware debido a que juega un rol fundamental a la hora de simplificar el desarrollo de nuevos servicios y en la

3.1. INTERNET DE LAS COSAS

19

integración de nuevas tecnologías junto con la ya existentes. En este contexto, es importante mencionar el proyecto OpenIoT [LTQS+ 12], este proyecto propone una arquitectura que permite el desarrollo de aplicaciones basadas en el cloud-computing2 usando los servicios del I OT. La mayor parte del framework OpenIoT reside en el uso de una infraestructura de virtualización para integrar las diferentes tecnologías de las redes de sensores, dentro de la nube. OpenIoT define una serie de extensiones a estándares bien conocidos como la ontología SSN-XG para las definiciones de las redes de sensores y utiliza servicios RESTful para el acceso a los mismos. El trabajo de Fazio et al. [FPPV12] también hace uso de especificaciones de estándares y protocolos, como Sensor Web Enablement, para hacer frente a los problemas de heterogeneidad en las plataformas sensoras. Según estos autores, se identifican tres niveles de incompatibilidad en las infraestructuras complejas de sensores/actuadores: Nivel de la tecnología del dispositivo. Nivel de comunicación. Nivel de datos. En última instancia, los sensores son accedidos a través de la API REST, la cual se basa en lo que se denomina como Sensor Observation Service Agent que resume, de alguna forma, las distintas observaciones y el sistema sensor. Sin embargo, el uso de protocolos basados en la web (como HTML o XML) para la integración de sensores tiene 3 grandes inconvenientes: Limita la clase y el tipo de dispositivos a usar, ya que la comunicación basada en texto demanda una cantidad considerable de ciclos de CPU para parsear los mensajes del protocolo. La vida útil de la batería de los dispositivos se reduce en gran medida. No es muy recomendable para las comunicaciones con una baja velocidad de transferencia (como 802.15.4) ni en sus formas comprimidas (RESTFul, CoAP, etc). La infraestructura que presenta este TFG, proporciona los servicios de un middleware básico, utilizando los protocolos MQTT y MQTT-SN para construir una capa de abstracción sobre una de las tecnologías del I OT, en concreto para un tipo de redes de sensores.

3.1.3

Internet de las Cosas, un paradigma libre

La importancia y el papel que juegan tanto el software, como los estándares libres en el I OT es doble [Pul13]: 2

Cloud-computing o computación en la nube. Se conoce con este nombre al paradigma que permite ofrecer servicios de computación, de almacenamiento y/o de software como servicios de pago por uso librando al usuario de los problemas de escalabilidad y mantenimiento.

20

CAPÍTULO 3. ANTECEDENTES Por un lado, la gran variedad de dispositivos conectados a Internet, hará imposible o muy difícil para cualquier empresa o incluso un grupo de empresas, generar el código necesario para los millones de sistemas diferentes que se unen al I OT. La única forma de que esto funcione será utilizando software libre, por lo que los fabricantes sólo tendrán que adaptarse a su dispositivo favorito. Un ejemplo de esta forma de proceder puede verse en lo que ha ocurrido con algunos de los códigos más exitosos en el campo de los teléfonos móviles. La otra razón que da una ventaja al software libre, es una revolución silenciosa que ha tenido lugar durante los últimos años, y que ha consistido en que las grandes empresas de electrónica han adoptado Linux empotrado para sus dispositivos, por razones obvias como: • Menor coste. • Fiabilidad. • Capacidad de personalización. • Disponibilidad de herramientas, etc. Esto significa que el software libre para el I OT va a integrarse mucho más fácilmente con estos dispositivos, ya que ambas partes son libres (asumiendo licencias compatibles).

Debido a estos motivos, la infraestructura que se desarrolla con este TFG se basa en tecnologías y estándares libres, para proporcionar sus servicios. En la práctica se encuentran múltiples tecnologías libres que ejemplifican todo esto [Pul13]. Arduino Arduino3 es una plataforma electrónica para la creación de prototipos, basada en software y hardware libres, flexibles y fáciles de usar. Arduino puede tomar información del entorno utilizando toda una gama de sensores, a través de sus pines de entrada y puede afectar aquello que le rodea controlando una serie de actuadores. El microcontrolador de la placa se programa mediante el lenguaje de programación Arduino (basado en Wiring) y el entorno de desarrollo Arduino (basado en Processing). Arduino está sirviendo como base a numerosas aplicaciones del I OT: sistemas de automatización del hogar, sistema para detectar terremotos, sistemas que avisan por Twitter cuando se produce algún evento, etc. Uno de los grandes hitos de Arduino ha sido la conexión de los teléfonos móviles con placas de esta marca, de forma que mediante el ADK (Android Open Accesory Development Kit) de Google, se permite la comunicación del sistema operativo Android con dispositivos hardware Arduino. 3

http://arduino.cc/

3.1. INTERNET DE LAS COSAS

21

Rasberry Pi The Raspberry Pi4 es un ordenador del tamaño de una tarjeta de crédito que se puede conectar a una televisión o a un teclado. Es un PC en miniatura con procesador ARM que se puede utilizar para muchas de las cosas que un PC convencional puede hacer. Ha sido desarrollado por la Fundación Raspberry Pi de Reino Unido con la intención de estimular la enseñanza de la informática básica en las escuelas. OpenPicus Open Picus5 es una compañía italiana que fabrica hardware para el I OT Los módulos están enriquecidos con un sistema operativo de software libre potente, pero ligero, y tiene embebido una pila de software TCP/IP, así como un servidor Web embebido. La compañía produce principalmente dos productos: Flyport, un sistema modular programable con conectividad a Internet y un IDE libre para crear, compilar y descargar aplicaciones para los módulos. Accada Accada [GDFSB09] es un prototipo de plataforma Open Source RFID desarrollada por el Auto-ID Lab de la ETH Zurich/University St. Gallen, de Suiza. Ha sido diseñada para permitir a los usuarios finales, a integradores de sistemas y a los investigadores experimentar con protocolos de red EPCglobal para el desarrollo de nuevas aplicaciones. La plataforma incluye un módulo de lectura que puede ejecutarse en un dispositivo EPC o separado. Accada implementa el Protocolo EPCglobal (ERP). Contiki Contiki [D+ 06] es un sistema operativo de código abierto para el I OT que permite a sistemas pequeños, que funcionan con baterías de baja potencia, comunicarse con Internet. Contiki se utiliza en una amplia variedad de sistemas tales como la monitorización de los niveles de ruido de la ciudad, el alumbrado de la calle, los medidores de energía eléctrica conectados en red, el control industrial, el control de la radiación, el monitoreo del sitio de construcción, sistemas de alarma, y control remoto de las viviendas. Contiki cuenta con una amplia comunidad de desarrolladores a nivel internacional, con contribuciones desde Atmel, Cisco, ETH, Redwire LLC, SAP, SICS, Thingsquare, y muchos otros. ThingSpeak ThingSpeak6 es una plataforma abierta de aplicaciones diseñada para permitir conexiones entre las personas y los objetos. Esta compuesto por una aplicación Open Source para el I OT y 4

http://www.raspberrypi.org/ http://www.openpicus.com/ 6 https://thingspeak.com/ 5

22

CAPÍTULO 3. ANTECEDENTES

una API para almacenar y recuperar datos de los objetos usando HTTP sobre Internet o vía una red de área local. Con ThingSpeak, se pueden crear aplicaciones de sensores, aplicaciones de seguimiento o de localización, y una red social de las «cosas» con las actualizaciones de su estado. El API de ThingSpeak está disponible en GitHub para su descarga e instalación en un servidor propio, así mismo también se puede tomar el código fuente para modificarlo y contribuir con nuevas características. La licencia de ThingSpeak es la GPLv3 para el uso como Open Source, aunque también se puede obtener una licencia de ioBridge para aplicaciones de código cerrado. OpenBeacon El proyecto OpenBeacon7 es una plataforma abierta para aplicaciones RFID, que operan a frecuencia 2,4 GHz, banda ISM. OpenBeacon se basa en software libre y en un módulo muy flexible y de bajo costo reprogramable, Rfmodule Open Source. El código del firmware y los esquemas del hardware están disponibles bajo licencias GPL. Grupo IoT eclipse.org iot.eclipse.org es el grupo de Eclipse encargado del desarrollo de tecnologías relaccionadas con el I OT (servicios, frameworks, protocolos, etc). Estas tecnologías tienen como objetivo establecer una pila de protocolos libre, con el fin de hacer que el desarrollo del I OT sea más sencillo. Incluyen un marco de desarrollo M2M, con el lenguaje de programación Lua, protocolos de comunicación como MQTT y OMA-DM y herramientas de desarrollo como Lua Development Tools. También tienen disponible toda una comunidad de desarrolladores en la que se puede participar de forma activa, y un entorno para testear las implementaciones de los distintos usuarios, denominado Sandbox. Proyecto Eclipse Paho Paho es otro de los proyectos desarrollados por la Fundación Eclipse en el ámbito del I OT Su objetivo es proporcionar implementaciones escalables y en varios lenguajes de programación, de los protocolos MQTT y MQTT-SN. Con el objetivo de apoyar las aplicaciones existentes y emergentes en este paradigma, en concreto con MQTT ya que está en proceso de estandarización por el OASIS consortium [CCB14]. La versión 1.0 de sus implementaciones fue publicada en Junio de 2014, y ya forma parte de la nueva versión del IDE de Eclipse. Esta versión cuenta con: Implementaciones MQTT para: • C (Posix/Windows) 7

http://www.openbeacon.org/

3.2. SMART CITIES

23

• C (Embebido) • C++ • Java (J2SE) • Java (Android Service) • JavaScript • Python • Go Implementaciones MQTT-SN para: • C (Embebido)

3.2 Smart Cities El Proyecto Epic de la UE8 en relación a la definición de este paradigma, señala que la actual crisis económica, junto con las crecientes expectativas de los ciudadanos, está aumentando la presión sobre las ciudades para que estas proporcionen mejores infraestructuras y servicios más eficientes. Esta tendencia ha contribuido a la creciente popularidad y el uso del concepto Smart City cuyas definiciones varían ampliamente y van desde el uso discreto de nuevas tecnologías como RFID, el I OT o el Big Data9 ; a una concepción más holística de inteligencia, como un desarrollo urbano que se basa en realizar una gestión sostenible de los recursos y así poder responder a las necesidades básicas de los ciudadanos, instituciones y empresas en los planos: económico, operativo, social y ambiental. Mientras que la primera definición es ampliamente utilizada por las empresas TIC de todo tipo, la segunda aproximación es la que ha adoptado la Comisión Europea, la cual desde principios de 1995 trata de mejorar los servicios públicos, las transacciones e interacciones con los ciudadanos y las empresas, a través de la financiación y el despliegue de una amplia gama de iniciativas [Pul13]. Desde otro punto de vista, una Smart City es un ecosistema complejo en el que intervienen numerosas tecnologías y múltiples agentes que las implementan, operan y usan, con el fin de proporcionar una serie de servicios. Por ello, para entender bien el valor de estos servicios, es necesario entender que puede ofrecer la tecnología. Desplegar una Smart City lleva asociada la creación de una serie de infraestructuras y es necesario disponer de mecanismos de gestión de la información generada y de diferentes plataformas, todo integrado bajo una perspectiva global. Para ampliar la definición dada en la Sección 1.1, en el siguiente apartado se expone la «cadena de valor tecnológica» de la Smart City. En el resto de apartados de esta sección se 8

European Union Platform for Inteligent Cities. http://www.epic-cities.eu/ Conjunto de datos de gran volumen, de gran velocidad y procedente de gran variedad de fuentes de información que demandan formas innovadoras y efectivas de procesar la información. 9

24

CAPÍTULO 3. ANTECEDENTES

profundiza en áreas de las ciudades inteligentes que tienen relevancia para el desarrollo de este TFG, como son los proyectos europeos, los middlewares, las plataformas de software libre existentes, el framework Civitas y la situación de las Smart Cities en España.

3.2.1

Tecnologías de la Smart City

La «cadena de valor tecnológica» de la Smart City puede definirse en cinco pasos [tel11]: En primer lugar se encuentra la etapa de recolección de datos de la ciudad. En segundo lugar se realiza la transmisión de los datos recopilados a través de las redes de comunicación. Una tercera fase comprende el almacenamiento y el análisis de los datos. En cuarto lugar, los datos alimentan una plataforma de provisión de servicios. Finalmente se encuentran los servicios de la Smart City. Etapa de recolección de datos El primer paso para formar una Smart City es llevar a cabo un despliegue masivo de instrumentación que permita conocer que está pasando en la ciudad. Este despliegue incluye sensores y otros dispositivos de captura de datos con los que se pueda recolectar información. Los sensores son dispositivos capaces de convertir magnitudes físicas como la temperatura, la luminosidad, la presión atmosférica, etc. en valores que puedan ser tratados según convenga. Los hay de diferentes tipos: de recursos (luz, agua, gas), de seguridad (detectores de humo, sensores de gases), de iluminación, de presencia (infrarrojos, por vibración, fotoeléctricos, etc), de condiciones climatológicas (humedad, presión atmosférica), de infraestructuras de transportes, de movimiento (acelerómetro) y de posición (GPS). Aunque estos son los más importantes, la gama es más amplia y abarca la mayoría de las magnitudes físicas. En la actualidad los dispositivos de captación de datos han evolucionado, permitiendo la digitalización y la conexión a Internet de los mismos. Gracias a esto es posible poner a disposición del público una gran cantidad de información en tiempo real y así plantear novedosos servicios en el marco de la Smart City. En la mayoría de los casos, estos dispositivos han adoptado el adjetivo de «smart» ya que utilizan tanto la información del entorno que les rodea como la información de su propio funcionamiento. Una estructura de red que use estos dispositivos para formar redes de sensores, se le denomina «ambiente inteligente» y tiene varias características clave: La capacidad de realizar procesamientos gracias al microprocesador que tienen. La capacidad de almacenar información en la memoria que incorporan.

3.2. SMART CITIES

25

La facilidad de enviar datos gracias a un módulo de transmisión inalámbrica. Hoy en día, existen multitud de redes de sensores cuyos datos pueden ser consultados a través de Internet, pero el problema radica en que cada red utiliza sus propios estándares, protocolos y formatos de representación de datos. Por este motivo es importante disponer de una plataforma que ayude a gestionar esta heterogeneidad. Hay que destacar que en un proyecto de Smart City es especialmente importante que los sensores tengan las siguientes características: Sean de fácil instalación. Se auto-identifiquen. Se auto-diagnostiquen. Sean fiables. Se coordinen con otros nodos. Incorporen software que les permita tratar digitalmente la señal. Utilicen protocolos de control y de red estándares. Tengan un bajo consumo que les permita estar activos mucho tiempo. Tengan un fácil mantenimiento. También es importante que los nodos sensores pueden re-programarse de forma inalámbrica. En este sentido, la metodología Over The Air Programming (OTA) es la que suele usarse. Otro grupo de tecnologías que pertenecen a este punto de la cadena, son las tecnologías de identificación, entre las que se encuentran: RFID, códigos BiDi y QR y los smartphones. Sobre RFID se habló en la Sección 3.1. Los códigos BiDi y QR son elementos que contienen información codificada y que permiten consultar información ampliada sobre múltiples objetos y elementos, a través del teléfono móvil. Por su parte, los smartphones actúan como dispositivos de captura de datos en el ámbito urbano. En definitiva, estas tecnologías permiten «sentir» la ciudad, sus infraestructuras, vehículos, habitantes, ambiente, etc. Etapa de transmisión de datos En la comunicación que se debe llevar a cabo en una Smart City , no solo tienen que poder comunicarse los dispositivos entre sí, si no que también debe existir una comunicación entre personas y entre personas y dispositivos. De forma que, en la etapa de transmisión de datos juegan un papel fundamental las redes de comunicación. Estas redes por carácter general son muy heterogéneas, por lo que la interoperabilidad y la transparencia son aspectos muy importantes en ellas.

26

CAPÍTULO 3. ANTECEDENTES

En este ámbito las redes inalámbricas son las que ayudan de forma más significativa a transmitir los datos obtenidos del entorno. Hoy en día hay multitud de tecnologías inalámbricas que buscan satisfacer los requisitos de este tipo de comunicación, pero no existe una tecnología que sea la que mejor funciona en todos los ámbitos, sino que cada una tiene una serie de características que hacen de ella una solución adecuada para un determinado entorno (en el Cuadro 3.1 puede verse una comparativa de algunas de estas redes). En cualquier caso, las comunicaciones en la Smart City suelen plantearse a diferentes niveles. En el nivel inferior se van recogiendo datos de los sensores en unos elementos que suelen llamarse repetidores. En un segundo nivel, los repetidores se comunican con pasarelas, cuyo cometido es transferir los datos a una red de transporte de nivel superior. En estos niveles se pueden utilizar, por ejemplo, redes mesh (con tecnología inalámbrica Zigbee, por ejemplo) y luego, para conectar con la red de transporte superior se suelen usar tecnologías celulares, como GPRS o 3G, y si las pasarelas están conectadas a redes fijas, tecnologías como ADSL o fibra óptica. Nivel físico y MAC ZigBee

802.15.4

Wavenis

Propietario

WiFi low power 802.11b/g WiMAX GSM/GPRS

Se basa en IEEE 802.16

Radio de acción

Bit-rate 250Kbps (2.4GHz) 10-100m interior 200Kbps (868MHz) 1Km exterior 40Kbps (915MHz) 200m interior Desde 10Kb/s 1Km LOS Hasta 100Kb/s 50-70m interior 40-100Kbps

3

// PAN ( Personal Area Network ) Identifier uint8_t PANID [2]={0 x33 ,0 x32 }; // 16−byte Encryption Key char∗ KEY = " WaspmoteLinkKey ! " ;

4 5 6

3

http://www.libelium.com/development/waspmote/sdk applications/

66

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

Figura 5.4: Chequeo de parámetros de Meshlium.

8 9 10 11 12

14 15 16 17

void setup () { // open USB port USB . ON (); USB . println ( F ( " 802 _01 example " )); // init XBee xbee802 . ON (); // wait for a second delay (1000);

29

// / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / // 1. set channel // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / xbee802 . setChannel (0 x0C ); // check at commmand execution flag if( xbee802 . error_AT == 0 ) { USB . println ( F ( " Channel set OK " )); } else { USB . println ( F ( " Error setting channel " )); }

31

// / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /

19 20 21 22 23 24 25 26 27 28

5.1. ETAPA 1: DESPLIEGUE MÍNIMO DE LA PLATAFORMA 32 33 34 35 36 37 38 39 40 41

43 44 45 46 47 48 49 50 51 52 53

55 56 57 58 59 60 61 62 63 64 65

67 68 69 70 71 72 73 74 75 76 77

// 2. set PANID // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / xbee802 . setPAN ( PANID ); // check the AT commmand execution flag if( xbee802 . error_AT == 0 ) { USB . println ( F ( " PANID set OK " )); } else { USB . println ( F ( " Error setting PANID " )); } // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / // 3. set encryption mode (1: enable ; 0: disable ) // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / xbee802 . s etEncr yption Mode (0); // check the AT commmand execution flag if( xbee802 . error_AT == 0 ) { USB . println ( F ( " encryption set OK " )); } else { USB . println ( F ( " Error setting security " )); } // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / // 4. set encryption key // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / xbee802 . setLinkKey ( KEY ); // check the AT commmand execution flag if( xbee802 . error_AT == 0 ) { USB . println ( F ( " encryption key set OK " )); } else { USB . println ( F ( " Error setting encryption key " )); } // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / // 5. write values to XBee module memory // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / xbee802 . writeValues (); // check the AT commmand execution flag if( xbee802 . error_AT == 0 ) { USB . println ( F ( " write values OK " )); } else { USB . println ( F ( " Error writing values " )); }

67

68

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO USB . println ( F ( "−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−" ));

79 80

}

82

void loop () { // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / // 1. get channel // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / xbee802 . getChannel (); USB . print ( F ( " channel : " )); USB . printHex ( xbee802 . channel ); USB . println ();

83 84 85 86 87 88 89 90

// / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / // 2. get PANID // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / xbee802 . getPAN (); USB . print ( F ( " panid : " )); USB . printHex ( xbee802 . PAN_ID [0]); USB . printHex ( xbee802 . PAN_ID [1]); USB . println ();

92 93 94 95 96 97 98 99

107

// / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / // 3. get encryption mode (1: enable ; 0: disable ) // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / xbee802 . g etEncr yption Mode (); USB . print ( F ( " encryption mode : " )); USB . printHex ( xbee802 . encryptMode ); USB . println ();

109

USB . println ( F ( "−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−" ));

111

delay (3000);

101 102 103 104 105 106

112

}

Listado 5.1: Código de Libelium ejemplo 802_01 - configure XBee basic parameters. Es importante mencionar: El módulo XBee debe ser configurado con los valores por defecto para los parámetros baud rate (BD=7) y AP (AP=2). Para que la configuración de los parámetros sea persistente cuando se apague el dispositivo, es necesario ejecutar la función writeValues(). De no ser así, cuando se corte la alimentación no se almacenarán estos valores en la memoria. Tras cargar y ejecutar el código, este deberá proporcionar una salida similar a esta:

5.1. ETAPA 1: DESPLIEGUE MÍNIMO DE LA PLATAFORMA

69

B# 802 _01 example Channel set OK PANID set OK encryption set OK encryption key set OK write values OK ------------------------------channel : 0 C panid : 3332 encryption mode : 00 -------------------------------

Donde podrá verse que los parámetros han sido cambiados con éxito, lo que indicará que Waspmote y Meshlium ya están bien configurados para proceder al envío y recepción de paquetes entre ellos.

5.1.2

Intercambio de paquetes

Desde Waspmote a Meshlium Una vez realizados los pasos anteriores, para enviar paquetes desde Waspmote a Meshlium tan solo hay que cargar en el dispositivo otro de los ejemplos de la API de Libelium, en este caso el código 802_02 - send packets (véase Listado 5.2). 1 2

4 5 6 7

9 10 11 12 13 14 15 16

18 19 20 21 22 23 24

26

#include < WaspXBee802 .h > #include < WaspFrame .h > // Pointer to an XBee packet structure packetXBee ∗ packet ; // Destination MAC address char∗ MAC_ADDRESS = " 0013 A2004052414C " ; void setup () { // init USB port USB . ON (); USB . println ( F ( " 802 _2 example " )); // init XBee xbee802 . ON (); } void loop () { // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / // 1. Create ASCII frame // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / // create new frame frame . createFrame ( ASCII , " WASPMOTE_XBEE " ); // add frame fields

70

frame . addSensor ( SENSOR_STR , " XBee frame " ); frame . addSensor ( SENSOR_BAT , PWR . getBatteryLevel ());

27 28

// / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / // 2. Send packet // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / // set parameters to packet : packet =( packetXBee ∗) calloc (1 ,sizeof( packetXBee )); packet −>mode = UNICAST ; // Choose transmission mode

30 31 32 33 34 35

// set destination XBee parameters to packet xbee802 . s e t D e s t i n a t i o n P a r a m s ( packet , MAC_ADDRESS , frame . buffer , frame . length , MAC_TYPE );

37 38 39

// send XBee packet xbee802 . sendXBee ( packet );

41 42

// check TX flag if( xbee802 . error_TX == 0 ) { USB . println ( F ( " ok " )); } else { USB . println ( F ( " error " )); }

44 45 46 47 48 49 50

// free variables free ( packet ); packet = NULL ;

52 53 54

// wait for five seconds delay (5000);

56 57 58

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

}

Listado 5.2: Código de Libelium ejemplo 802_02 - send packets. Lo único que debe cambiarse es la dirección MAC destino de los paquetes a enviar, el resto de opciones no es necesario tratarlas en este ejemplo, aunque la API de Libelium es flexible y ofrece varias posibilidades a la hora de enviar paquetes 802.15.4 (como crear frames propios o directamente introducir en el paquete datos de aplicación). Tras cargar y ejecutar este código, si todo ha ido bien el dispositivo mostrará por el puerto serie impresiones con la palabra «ok», mientras que si el mensaje no se ha enviado, mostrará la palabra «error». A pesar de que el puerto serie nos muestre que el paquete se ha enviado, no necesariamente significa que la pasarela lo haya recibido. Para comprobar de forma segura si Meshlium ha

5.1. ETAPA 1: DESPLIEGUE MÍNIMO DE LA PLATAFORMA

71

recibido el paquete, se puede obrar de dos formas: Accediendo a él mediante el Manager System, dirigiéndose a la pestaña Sensor Networks, apartado Capturer, comprobando que el botón Sensor Parser Available esté en verde y viendo si existen datos en la base de datos (véase Figura 5.5). Accediendo a Mehslium a través de SSH [Lib13c], deteniendo el daemon sensorParser, que se encarga de almacenar los paquetes entrantes en la base de datos local: sensorParser . sh stop

Y ejecutando el siguiente comando: capturer S0 38400

Los datos recibidos desde Waspmote serán mostrados por consola. meshlium :~# sensorParser . sh stop meshlium :~# capturer S0 38400 setting speed 38400 ttyS0 chosen ... Press Ctrl + c to close the program [ Aqui ira apareciendo el contenido de los paquetes entrantes ]

Figura 5.5: Captura de paquetes en Meshlium, acceso via Manager System.

Desde Meshlium a Waspmote Una vez que se haya comprobado que Meshlium recibe de forma correcta los paquete de Waspmote, hay que realizar la comunicación inversa, desde Meshlium a Waspmote. En este

72

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

caso es necesario utilizar dos programas, uno para que Waspmote se mantenga a la espera de recibir paquetes y otro para que Meshlium los envíe. Recepción en Waspmote: De nuevo, el código necesario para que Waspmote se mantenga a la espera de recibir mensajes puede encontrarse en la API que nos proporciona Libelium para programar los dispositivos. En esta ocasión el código necesario es el contenido en el ejemplo 802_11b - complete example receive (véase Listado 5.3) 1 2

4 5 6 7

9 10 11 12 13 14 15 16

18 19 20 21 22 23 24 25 26 27

29 30 31 32 33 34

#include < WaspXBee802 .h > #include < WaspFrame .h > // pointer to the packet to send packetXBee ∗ packet ; unsigned long previous =0; uint8_t destination [8]; void setup () { // init USB port USB . ON (); USB . println ( F ( " 802 _11b example " )); // init XBee xbee802 . ON (); } void loop () { // Wait message for 20 seconds previous = millis (); while( ( millis ()− previous ) < 20000 ) { // check available data in RX buffer if( xbee802 . available () > 0 ) { // parse information xbee802 . treatData (); // check RX flag after ’ treatData ’ if( ! xbee802 . error_RX ) { // check available packets while( xbee802 . pos >0 ) { /∗ Available info in ’ xbee802 . packet_finished ’ structure ∗/

36

// Treat this data in your own

38

// 2.6. Free variable

5.1. ETAPA 1: DESPLIEGUE MÍNIMO DE LA PLATAFORMA free ( xbee802 . packet_finished [ xbee802 . pos −1]); xbee802 . packet_finished [ xbee802 . pos −1]= NULL ;

39 40

// 2.7. Decrement packet counter xbee802 . pos−−;

42 43

}

44

}

45

51

} // Condition to avoid an overflow ( DO NOT REMOVE ) if ( millis () < previous ) { previous = millis (); } } /∗ end while ∗/

53

delay (5000);

46 47 48 49 50

54

73

}

Listado 5.3: Código de Libelium ejemplo 802_11b - complete example receive. Si se modifica la condición del bucle «while», se estará modificando la cantidad de tiempo que el dispositivo se mantiene a la espera de mensajes, antes de proceder a seguir con la ejecución del resto del código. Cuando se recibe información en Waspmote, esta se almacena en determinadas estructuras de la API, en este caso se almacenan en la estructura «xbee802.packet_finished», cuyos campos más importantes son: • xbee802.packet_finished->lenght: longitud total del paquete recibido. • xbee802.packet_finished->data: todos los datos recibidos accesibles byte a byte. • xbee802.packet_finished->macSH: contiene los bytes mas significativos de la MAC origen del paquete. • xbee802.packet_finished->macSL: contiene los bytes menos significativos de la MAC origen del paquete. En lugar del comentario de la linea 35 del listado anterior, deberá escribirse el código especifico que se necesite para tratar la información recibida. Envío desde Meshlium: Para conseguir un intercambio completo entre ambos dispositivos, solo queda explicar como realizar el envío de paquetes desde Meshlium a Waspmote. Para conseguir este propósito hay que usar el archivo ZigBeeSend.c contenido en la ruta /var/ManagerSystem/plugin/b_SensorData/b0_capturer/bin/ de la pasarela. Para usar este archivo son necesarias dos acciones: • Detener el daemon sensorParser.sh sensorParse . sh stop

74

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO • Compilar el archivo fuente ZigBeeSend.c gcc -o ZigBeeSend ZigBeeSend . c - lpthread

Hecho esto, hay tres formas para enviar paquetes usando el ejecutable generado: • Usando la dirección MAC 802.15.4 destino. ./ ZigBeeSend - mac 00 XXXXxxXXXXXXxx >

• Usando la dirección de red (MY). ./ ZigBeeSend - net 1234 >

• Realizando una transmisión broadcast. ./ ZigBeeSend -b >

Tras ejecutar el archivo con alguna de estas opciones, se mostrará la siguiente información por pantalla: Preparing the module ... Sending message ... Restoring original values ...

Esto es así debido a que el módulo XBee residente en Meshlium está configurado como Router AT y sus parámetros de red están accesibles vía comandos AT, en la primera fase de este envío, se prepara el módulo (usando estos comandos) para enviar con las opciones que hayamos elegido, después se envía el mensaje y por último, se restaura el estado del módulo XBee a sus valores originales. Para comprobar que la recepción en Waspmote ha sido satisfactoria, basta con imprimir información relevante de la estructura packet_finished por el puerto serie del dispositivo. O, por ejemplo, encender los LEDs cada vez que se reciba un mensaje. Esta parte queda a elección del desarrollador. La información de este apartado ha sido sacada de la Sección 15.8 de [Lib13c].

5.2 Etapa 2: Instalación y configuración de Mosquitto Mosquitto ha sido el broker elegido para cargar con el peso de la gestión y distribución de eventos de la infraestructura, entre los distintos suscriptores. Esta elección se debe en su mayor parte, a la eficiencia en cuanto al número de clientes conectados y los recursos consumidos que proporciona este broker. Esta etapa es necesaria antes de comenzar la implementación. Mosquitto es un servidor o broker de los protocolos MQTT y MQTT-SN, escrito en C y creado por la fundación Eclipse junto con IBM. La razón para estar escrito en C es, según sus

5.2. ETAPA 2: INSTALACIÓN Y CONFIGURACIÓN DE MOSQUITTO

75

creadores, permitir que el servidor se ejecute en máquinas que no tengan capacidad suficiente para ejecutar una Java Virtual Machine (JVM). Además, al hacerlo de esta forma, Mosquitto también puede ejecutarse en dispositivos empotrados. La implementación actual de este software tiene un ejecutable con un tamaño de unos 120kB y consume alrededor de 3MB de RAM con 1.000 clientes conectados. Además, hay informes que contienen test satisfactorios con 100.000 clientes conectados y un envío de mensajes moderado [mos14]. Datos que representan un magnífico rendimiento. Mosquitto implementa todas las características descritas en las especificaciones de los protocolos, junto con tres más: Puede actuar como puente entre otros servidores MQTT, incluyendo otras instancias de Mosquitto. Esto permite construir redes de servidores MQTT, pudiendo dotar a estas redes de diferentes topologías (véase Sección 3.3.1), dependiendo de que requisitos nos pida el sistema que estemos construyendo. Esta característica proporciona escalabilidad a cualquier solución que utilice Mosquitto. Puede ser configurado para usar MQTT sobre SSL/TLS. Proporcionando de esta forma, conexiones seguras entre máquinas. Esto es importante debido a que MQTT no tiene seguridad por si mismo, es el broker debidamente configurado el que proporcionará servicios de seguridad como cifrado, autenticación y control de acceso. De un primer estudio de MQTT, puede verse que a partir de la versión 3.1 provee autenticación de cliente mediante usuario y contraseña, sin embargo, sin el broker bien configurado este mecanismo no proporciona seguridad alguna, ya que este debe tener indicado en su archivo de configuración, una ruta hacia un archivo donde se encuentre la relación usuario-contraseña. Además, si no se utiliza encriptado de red, los datos viajarán sin cifrar y serán vulnerables. Para hacer más seguro el intercambio de mensajes, Mosquitto permite el uso de certificados SSL/TLS. Si la opción require_certificate está activada en el archivo de configuración, el cliente deberá proveer un certificado válido para conectarse a Mosquitto, si no está activada, la autenticación del cliente queda en manos del mecanismo de seguridad basado en usuario y contraseña que proporciona MQTT. Añade la posibilidad de restringir el acceso a determinados topics, a ciertos usuarios. Es decir, control de acceso.

5.2.1

Instalación

La instalación de Mosquitto depende del sistema operativo sobre el que quiera utilizarse, en este caso se necesita instalar Mosquitto sobre una máquina con Debian GNU/Linux. Para ello, tan solo hay que instalar ciertos paquetes de los repositorios oficiales de la distribución, ya que Mosquitto viene incluido en ellos. Esto mismo ocurre en la mayoría de distribuciones

76

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

GNU/Linux,

como Fedora, openSUSE o Ubuntu.

Con el gestor de paquetes que se prefiera, basta con realizar una búsqueda del patrón «mosquitto» y ver los elementos que se listan, para poder utilizar el servidor con todas sus funcionalidades tan solo es necesario el paquete mosquitto, si además se quiere disponer de clientes MQTT, deben instalarse los paquetes mosquitto-clients y libmosquitto1. El resto de paquetes no son necesarios para este caso en concreto. Listado de paquetes con aptitude: # aptitude search mosquitto p libmosquitto - dev i A libmosquitto1 p libmosquittopp - dev p libmosquittopp1 i mosquitto i mosquitto - clients p mosquitto - dbg p python - mosquitto p python3 - mosquitto

-

MQTT version 3.1 client library , development files MQTT version 3.1 client library MQTT version 3.1 client C ++ library , development files MQTT version 3.1 client C ++ library MQTT version 3.1 compatible message broker Mosquitto command line MQTT clients debugging symbols for mosquitto binaries MQTT version 3.1 Python client library MQTT version 3.1 Python 3 client library

Una vez que se instale Mosquitto, este pasará a ejecutarse como un daemon del sistema, utilizando una configuración por defecto (p.e. esperando conexiones MQTT en el puerto 1883, sin persistencia y sin seguridad), para comprobar si Mosquitto funciona de forma correcta pueden usarse los clientes que se han instalado previamente: Primero se comprueba si Mosquitto se está ejecutando en el sistema: # / etc / init . d / mosquitto status [ ok ] mosquitto is running .

En caso de que no estuviera en ejecución, Mosquitto puede iniciarse de dos formas: ejecutando el comando anterior pero con la orden start, o a través del comando «mosquitto», del cual puede obtenerse información consultando la página de manual que se habrá instalado con los paquetes anteriores. Después en una terminal se ejecuta un suscriptor: $ mosquitto_sub -t hello / world

Con esto se consigue que el suscriptor se mantenga a la espera de publicaciones en el topic «hello/world» (opción -t). Por último se ejecuta un publicador en otra terminal: $ mosquitto_pub -t hello / world -m ‘‘ Hello World ! ’ ’

Si todo ha ido bien, la publicación habrá llegado a Mosquitto y este la habrá distribuido a los suscriptores del topic en cuestión, apareciendo el mensaje «Hello World!»

5.2. ETAPA 2: INSTALACIÓN Y CONFIGURACIÓN DE MOSQUITTO

77

(opción -m) en la terminal anterior (véase Figura 5.6).

Figura 5.6: Comprobación del correcto funcionamiento de Mosquitto.

5.2.2

Configuración

El archivo de configuración de Mosquitto se denomina mosquitto.conf y puede residir en cualquier sitio, siempre que Mosquitto tenga permisos de lectura sobre él. Por defecto, Mosquitto no necesita un archivo de configuración y usará valores predeterminados, en el caso de necesitar usar un archivo de configuración, se tendrá que ejecutar el comando «mosquitto» utilizando la opción -c seguida de la ruta hacia el archivo. Un archivo de ejemplo, con explicaciones detalladas de todas las opciones de configuración y de como utilizarlas, se encuentra disponible en: /etc/mosquitto/mosquitto.conf. Para este proyecto se ha usado Mosquitto indicándole un archivo de configuración concreto, la mayor parte de las opciones se han dejado por defecto, sólo se han modificado dos aspectos: Persistencia: activando la opción persistence se consigue que Mosquitto almacene en un archivo, la información referente a conexiones, suscripciones, publicaciones, etc. Para que cuando Mosquitto se reinicie recupere de este archivo los datos y vuelva a su estado anterior. Esta información se almacena en el archivo cada cierto intervalo de tiempo, especificado en la opción autosave_interval (en segundos). La ruta y el nombre del archivo de persistencia se indican en las opciones persistencia_file [file name] y persistence_location [path]. Logs: con la opción log_dest file [path] se especifica la ruta y el archivo de log en el que queremos guardar esta información. Con la opción log_type [debug | error | warning | notice | information] se indica a Mosquitto que tipo de información debe mandar al archivo de log. Deberá añadirse una nueva linea por cada tipo de información. Es importante mencionar, que Mosquitto abre el puerto 1883 para aceptar conexiones MQTT no seguras, y el 8883 para las conexiones de MQTT sobre SSL/TLS. Por defecto Mosquitto estará disponible en todas las interfaces de red, salvo que se le indique lo con-

78

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

trario mediante la opción bind_address y acepta conexiones desde cualquier dirección IP y puerto.

5.3 Etapa 3: Librería MQTT Una vez realizadas las etapas anteriores, el proceso de desarrollo del proyecto se centra en la implementación de la librería MQTT, esta librería está destinada a ser ejecutada en la pasarela, como parte del software de traducción entre los protocolos MQTT-SN y MQTT. Esta etapa se divide, a su vez, en tres fases o tareas, que son: Estudio de la especificación del protocolo, fase importante en la que se estudia la sintaxis, semántica y temporización de MQTT. Creación de un archivo de cabecera para la librería, que recopile y organice todos los datos útiles, sacados de la especificación, de cara a la implementación. Implementación del protocolo, en la que se implementan los distintos tipos de mensajes y características de MQTT, siguiendo la metodología de desarrollo TDD. En los siguientes apartados se explican en profundidad estas fases.

5.3.1

Estudio de la especificación

Los elementos clave de un protocolo son: sintaxis, semántica y temporización. La sintaxis se refiere a la estructura del formato de los datos, es decir, el orden en el cual se presentan. La semántica se refiere al significado de cada campo de bits. Y la temporización define cuando se deberían enviar los datos y con que rapidez deberían ser enviados. Todos estos aspectos se comprenden tras realizar un estudio de la especificación de MQTT [Loc10]. Convirtiéndose esta fase, en una de las más importantes antes de comenzar con la implementación de los mensajes. La especificación está dividida en 3 partes: 1. Formato de los mensajes, donde se detallan las distintas partes que puede tener un paquete MQTT. 2. Detalles específicos de cada mensaje, donde de trata en profundidad cada uno de ellos. 3. Flujo de mensajes, donde se explica como deben ser los intercambios de paquetes entre cliente y servidor. En esta sección interesan las partes 1 y 3, la parte 2, al contener información específica sobre como debe formarse cada mensaje, deberá ser consultada durante la fase de implementación de los mensajes.

5.3. ETAPA 3: LIBRERÍA MQTT

79

Formato de los mensajes Los mensajes MQTT pueden estar formados por 3 partes: cabecera fija, cabecera variable y payload. La cabecera fija es obligatoria en todos los mensajes, de hecho en ocasiones será lo único que contengan, mientras que otros necesitarán la cabecera variable y el payload. Todos los valores de los campos de los mensajes deben ir codificados siguiendo un orden big-endian, es decir, los bytes de mayor orden preceden a los de menor. Una palabra de 16-bit se representa con el Most Significant Byte (MSB), seguido del Least Significant Byte (LSB). bit byte 1 byte 2

7 6 5 4 Message Type

3 2 1 DUP flag QoS level Remaining Length

0 RETAIN

Cuadro 5.1: Formato de la cabecera fija. Fuente: [Loc10]. El formato de la cabecera fija puede verse en el Cuadro 5.1. Message Type es un valor sin signo de 4-bit, el valor que deberá adoptar este campo depende del tipo de mensaje que se esté codificando (véase Cuadro 5.2). El resto de bits del byte 1 contienen los campos DUP, Q O S y RETAIN, que representan los flags del mensaje: DUP: Este flag se activa cuando el cliente o el servidor intentan redistribuir un mensaje PUBLISH, PUBREL, SUBSCRIBE o UNSUBSCRIBE. Se aplica a los mensajes con una Q O S mayor que cero. Cuando el flag DUP está activo, la cabecera variable debe incluir un identificador de mensaje. QoS: Este flag indica el nivel de garantía para la distribución de un mensaje PUBLISH. Ocupa dos bits y se codifica como puede verse en el Cuadro 5.3. RETAIN: Este flag solo se usa en los mensajes PUBLISH. Cuando un cliente envía una publicación a un servidor, si este flag está activo, el servidor debe mantener el mensaje incluso después de que haya sido repartido a todos los suscriptores. Cuando se establezca una nueva suscripción a un topic, el último mensaje retenido en ese topic, deberá ser enviado al suscriptor con el flag RETAIN activo. El campo remaining length indica el número de bytes que le quedan al mensaje, incluyendo los datos de la cabecera variable y del payload. Este campo comienza en el byte 2 de la cabecera fija y puede llegar a ocupar hasta cuatro bytes, dependiendo del tamaño restante del mensaje. La cabecera fija queda fuera de la cuenta de bytes que debe indicar remaining length, y aunque este campo ocupe más de dos bytes, siempre es parte de la cabecera fija. Como ya se ha dicho anteriormente, algunos mensajes MQTT contienen una cabecera variable, que se encuentra entre la cabecera fija y el payload. A continuación se describen los campos de esta cabecera, en el orden en que deben aparecer en los mensajes:

80

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO Mnemonico Reserved CONNECT CONNACK PUBLISH PUBACK PUBREC PUBREL PUBCOMP SUBSCRIBE SUBACK UNSUBSCRIBE UNSUBACK PINGREQ PINGRESP DISCONNECT Reserved

Numeración 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Cuadro 5.2: Tipos de mensajes y su numeración. Fuente: [Loc10]. QoS 0 1 2 3

bit 2 0 0 1 1

bit 1 0 1 0 1

Descripción At most once At least once Exactly once Reserved

Cuadro 5.3: Codificación de las distintas Q O S. Fuente: [Loc10]. Nombre del protocolo: Debe estar presente en la cabecera variable de los mensajes CONNECT. Este campo es una cadena de caracteres codificada en formato UTF (Unicode Transformation Format), que representa el nombre del protocolo, capitalizado así: «MQIsdp». Versión del protocolo: También debe estar presente en la cabecera variable de los mensajes CONNECT. Es un carácter de 8-bit sin signo que representa el nivel de revisión del protocolo, en este caso será 3 (0x03). Flags de conexión: Este campo representa en un byte los flags de conexión del mensaje CONNECT. El significado de cada bit de este campo puede verse en el Cuadro 5.4. • Clean Session: Si no está activado (con valor 0), el servidor deberá almacenar las suscripciones del cliente después de que este se desconecte. Válido para Q O S 1 y 2. Si está activado (con valor 1), el servidor descarta cualquier información acerca del cliente cuando este se desconecta.

5.3. ETAPA 3: LIBRERÍA MQTT

81

• Will Flag: Este bit indica si se va a utilizar o no, la funcionalidad last will and testament de MQTT. Si está activado, los bits Will QoS y Will Retain también deberán estarlo, y los campos Will Topic y Will Message del payload deberán estar presentes. • Will QoS: En caso de estar activado el bit Will Flag, indica el nivel garantía para el futuro Will Message. Se codifica conforme al Cuadro 5.3. • Will Retain: Si el Will Flag está activado, indica si el Will Message debe permanecer o no, en el servidor, una vez desconectado el cliente. • Usuario y contraseña: Indican si el cliente va a usar esta característica del protocolo. En caso de estar activados, deberán incluirse los campos correspondientes en el payload del mensaje. No es posible que esté activado el bit de la contraseña, si no lo está el de usuario. «Tiempo de vida» o Keep Alive: Debe estar presente en la cabecera variable del mensaje CONNECT. Mide el máximo intervalo de tiempo (en segundos), entre los mensajes recibidos por el cliente. Se usa para que el servidor detecte si la conexión de red ha caido, sin tener que esperar el largo timeout que tiene TCP/IP. El cliente tiene la responsabilidad de enviar un mensaje cada periodo de «tiempo de vida». En ausencia de mensajes en este periodo, el cliente envía un PINGERQ, que será contestado por un PINGRESP desde el servidor. Si el cliente no recibe un PINGRESP antes de que acabe el «tiempo de vida», este cerrará la conexión TCP. Este campo es un valor de 16-bit y debe ir codificado en orden big-endian. Código de retorno para el CONNECT: Este campo debe estar presente en la cabecera variable del mensaje CONNACK. Utiliza un byte y puede contener 5 tipos de código de retorno (véase Cuadro 5.5). Topic Name: Debe estar presente en la cabecera variable de los mensajes PUBLISH. El Topic Name representa la clave que identifica el canal de información al que debe ser enviada la información publicada. Es una cadena codificada en UTF-8 y como máximo puede tener una longitud de 32.767 caracteres. bit

7 User Name Flag

6 Password Flag

5 Will Retain

4 3 Will QoS

2 Will Flag

1 Clean Session

0 Reserved

Cuadro 5.4: Flags de conexión del mensaje CONNECT. Fuente: [Loc10]. La última parte de los mensajes MQTT es el payload, que solo está presente en los mensajes: CONNECT, SUBSCRIBE, SUBACK y PUBLISH. En los mensajes de establecimiento de conexión, el payload contendrá una o varias cadenas de caracteres codificadas en UTF-8.

82

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO Numeración 0 1 2 3 4 5 6-255

Hex 0x00 0x01 0x02 0x03 0x04 0x05

Significado Conexión aceptada Conexión rechazada: versión de protocolo no aceptada Conexión rechazada: identificador rechazado Conexión rechazada: servidor no disponible Conexión rechazada: usuario o contraseña incorrectos Conexión rechazada: no autorizado Reservado para uso futuro

Cuadro 5.5: Códigos de retorno al mensaje CONNECT y su significado. Fuente: [Loc10]. Estas especificarán: un único identificador de cliente, el Will Topic y el Will Message y el usuario y la contraseña, en caso de estar activados sus respectivos flags de la cabecera variable. El payload de los mensajes SUBSCRIBE contendrá una lista de Topic Names a los que el cliente se quiere suscribir, y la Q O S que requiere para ellos. Todo codificado en UTF-8. El payload del mensaje SUBACK estará formado por una lista de Q O Ss garantizadas a los Topic Names indicados en la correspondiente suscripción. Por último, el payload del mensaje PUBLISH contendrá los datos de aplicación que deben ser publicados. Una vez estudiadas las distintas partes que puede contener un mensaje MQTT, es importante destacar dos aspectos más, que influyen en la sintaxis de un mensaje: Identificadores de mensaje: Los mensajes PUBLISH, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE Y UNSUBACK, necesitan un identificador de mensaje, para poder realizar la asociación con sus correspondientes acuses de recibo. Este campo está representado por un entero sin signo de 16-bit, codificado en orden big-endian. MQTT y UTF-8: UTF-8

es una forma eficiente de codificación de caracteres y cadenas Unicode, que optimiza la codificación de caracteres ASCII como apoyo a las codificaciones basadas en texto. En MQTT, todas las cadenas de caracteres van precedidas de dos bytes que indican su longitud. Es decir, antes de introducir en el mensaje una cadena determinada, se introduce su longitud (véase Cuadro 5.6). De esta forma, la longitud de una cadena no será su número de caracteres, sino el número de bytes que ocupa la cadena codificada (número de caracteres + 2). bit byte 1 byte 2 bytes 3...

7 6 5 4 3 2 1 0 Longitud de Cadena MSB Longitud de Cadena LSB Caracteres codificados

Cuadro 5.6: Codificación de una cadena de caracteres en MQTT. Fuente: [Loc10].

5.3. ETAPA 3: LIBRERÍA MQTT

83

Flujo de datos En MQTT la distribución de los mensajes está relacionada con la Q O S usada. Como se mencionó en la Sección 3.3.2, existen tres niveles de Q O S, cada una de las cuales lleva asociado un determinado flujo de mensajes. A continuación se describen en detalle cada uno de estos niveles: QoS 0, At most once delivery: La garantía de los mensajes distribuidos se deja al servicio best effort de la red TCP/IP subyacente. No se espera respuesta ni están definidas políticas para el reenvío. Cuando se publica información utilizando Q O S nivel 0, no se tiene certeza de que esta haya llegado al servidor. Cuando el servidor la reciba, la distribuirá a los suscriptores. QoS 1, At least once delivery: En este nivel si se tienen garantías de los mensajes distribuidos. Cuando se publica información, el emisor queda a la espera del correspondiente acuse de recibo, que deberá contener un identificador de mensaje idéntico al del mensaje que contenía la publicación. Si este identificador fuese erróneo, o el acuse de recibo no se recibiese después del «tiempo de vida» establecido, el emisor de la publicación deberá reenviar el mensaje con el flag DUP activado. Los mensajes SUBSCRIBE y UNSUBSCRIBE siempre utilizan Q O S nivel 1. Cuando el servidor reciba un PUBLISH con este nivel de Q O S, deberá: (i) almacenar el mensaje, (ii) distribuir el mensaje a los suscriptores, (iii) borrar el mensaje y (iv) enviar un acuse de recibo (mensaje PUBACK en este caso) al emisor de la publicación. Si el servidor recibe publicaciones con el flag DUP activo, deberá redistribuir esta información y enviar otro acuse de recibo. QoS 2, Exactly once delivery: Este nivel añade una garantía más al nivel 1, asegurándose de que los suscriptores no reciban mensajes duplicados. Este es el nivel más alto de garantías que puede proporcionar MQTT y está pensado para usarlo cuando el suscriptor no deba recibir publicaciones duplicadas bajo ningún concepto. Dependiendo de cuando de distribuya la información a los suscriptores, un receptor de un mensaje PUBLISH con Q O S 2 puede actuar de dos formas: 1. Almacenando el mensaje y enviando un mensaje PUBREC, que contendrá el identificador de mensaje del PUBLISH recibido. Cuando el emisor reciba este mensaje, deberá enviar un PUBREL, con el mismo identificador. Entonces, el servidor distribuirá la publicación hacía los suscriptores, borrará el mensaje y enviará un PUBCOMP, con el mismo identificador usado en todo el proceso. 2. Almacenando el identificador de mensaje y publicando la información a los suscriptores. Después enviará un PUBREC que contendrá el identificador almacenado. Cuando lo reciba el emisor, enviará un PUBREL, con el mismo identificador,

84

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

Figura 5.7: Flujo de datos para una publicación con Q O S nivel 2. Fuente: elaboración propia. y cuando el servidor lo reciba, borrará el identificador de mensaje almacenado previamente y enviará un PUBCOMP en última instancia. Si se detecta un fallo en el proceso, el flujo de datos se reanuda a partir del último acuse de recibo que haya llegado correcto. Tanto si es del mensaje PUBLISH, como del PUBREC. En cualquiera de los casos, el flujo de datos es conforme aparece en la Figura 5.7 Por otra parte, en MQTT el orden en que se envían/reciben los mensajes puede verse afectado por ciertos factores, como el número de flujos de publicaciones que permita un cliente a la vez, o si el cliente es multihilo o no. Para que una implementación proporcione garantías de cara a la conservación del orden de los mensajes, esta debe asegurarse de que cada flujo de distribución de mensajes, sea completado en el mismo orden en que comenzó. Por ejemplo, en una serie de flujos de Q O S 2, los mensajes PUBREL deben ser enviados en el mismo orden en que se enviaron los PUBLISH originales (véase Figura 5.8). El número de mensajes «en el aire» permitidos, también afecta al tipo de garantías que pueden ser proporcionadas: Si se permite un solo mensaje «en el aire», cada flujo de distribución se completa antes de que empiece el siguiente. Si se permite más de un mensaje «en el aire», el orden de los mensajes solo puede ser

5.3. ETAPA 3: LIBRERÍA MQTT

85

Figura 5.8: Ejemplo de flujo de datos ordenado. Fuente: elaboración propia. garantizado por el nivel de Q O S utilizado.

5.3.2

Creación del archivo de cabecera

Cada uno de los mensajes del protocolo está formado por una serie de campos de bits, que dependiendo del tipo de mensaje y de las necesidades del usuario/cliente, tomarán diferentes valores. Hacer que las distintas partes de un mensaje tengan un valor u otro, es más sencillo si estos se encuentran identificados. Surge de esta forma, la necesidad de disponer de un lugar donde se almacenen estos identificadores, junto con su valor asociado. Ese lugar es el archivo de cabecera, en este caso mqtt.h. En esta fase se trata de realizar una primera versión de este archivo, que posteriormente será modificado ya que también debe contener los prototipos de las funciones que vaya a ser necesario implementar y cualquier otro aspecto común a todas las partes del protocolo. Las inclusiones del resto de archivos de cabecera que se necesiten durante el proceso de implementación de los mensajes, también debe de ir en este archivo. Los aspectos vistos hasta ahora y que pueden ser codificados en mqtt.h son: Códigos de los mensajes. Flags de la cabecera fija. Flags de conexión.

86

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO Códigos de retorno a un mensaje de petición de conexión. Nombre y versión del protocolo.

Por ejemplo, los códigos vistos en el Cuadro 5.2 deben ser codificados en hexadecimal y desplazados 4 bits hacía la izquierda, ya que el código de mensaje representa los 4 primeros bits del primer byte de la cabecera fija, p.e. el código número 1, en hexadecimal es 0x01, y desplazado 4 bits a la izquierda es 0x10. Si todos estos elementos se codifican correctamente y se les asigna un identificador, la tarea de formar los mensajes será estrictamente eso, dar forma a los mensajes utilizando los diferentes campos de bits previamente codificados e identificados. Además, las distintas funciones que contendrá la implementación final, poseerán un código más legible. El código de la primera versión de mqtt.h puede verse en el Listado 5.4. 1 2

#ifndef MQTT_H #define MQTT_H /∗ protocol version ∗/ #define M Q T T _ P R O T O C O L _ V E R S I O N

(0 x03 )

/∗ messages types ∗/ #define MQT T_TYPE _CONNE CT #define MQT T_TYPE _CONNA CK #define MQT T_TYPE _PUBLI SH #define MQTT_TYPE_PUBACK #define MQTT_TYPE_PUBREC #define MQTT_TYPE_PUBREL #define MQT T_TYPE _PUBCO MP #define M Q TT _ T YP E _ SU B S CR I B E #define MQTT_TYPE_SUBACK #define M Q T T _ T Y P E _ U N S U B S C R I B E #define M QTT _T YP E_ UN SU BA CK #define MQT T_TYPE _PINGR EQ #define M QTT _T YP E_ PI NG RE SP #define M Q T T _ T Y P E _ D I S C O N N E C T

(0 x10 ) (0 x20 ) (0 x30 ) (0 x40 ) (0 x50 ) (0 x60 ) (0 x70 ) (0 x80 ) (0 x90 ) (0 xA0 ) (0 xB0 ) (0 xC0 ) (0 xD0 ) (0 xE0 )

30

/∗ connect flags ∗/ #define M Q T T _ C O N N E C T _ C L E A N _ S E S S I O N #define MQT T_CONN ECT_WI LL #define M Q T T _ C O N N E C T _ W I L L _ Q o S 1 #define M Q T T _ C O N N E C T _ W I L L _ Q o S 2 #define M Q T T _ C O N N E C T _ W I L L _ R E T A I N #define M Q T T _ C O N N E C T _ P A S S W O R D #define M Q T T _ C O N N E C T _ U S E R N A M E

(0 x02 ) (0 x04 ) (0 x08 ) (0 x10 ) (0 x20 ) (0 x40 ) (0 x80 )

32

/∗ fixed−header flags ∗/

4 5

7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

23 24 25 26 27 28 29

5.3. ETAPA 3: LIBRERÍA MQTT 33 34 35 36 37 38

40 41 42 43 44 45 46

#define #define #define #define #define #define

MQTT_NO_FLAGS MQTT_FLAG_DUP MQTT_FLAG_QoS0 MQTT_FLAG_QoS1 MQTT_FLAG_QoS2 MQTT_FLAG_RETAIN

/∗ connect message constants ∗/ #define MQTT_CONNECT_M #define MQTT_CONNECT_Q #define MQTT_CONNECT_I #define MQTT_CONNECT_s #define MQTT_CONNECT_d #define MQTT_CONNECT_p

56

/∗ connack return codes ∗/ enum c o nn a c k_ r e tu r n _c o d e { C O NN E C TI O N _A C C EP T E D = UN PR OT OC OL _V ER SI ON = I D EN T I FI E R _R E J EC T E D = SE RV ER _U NA VA IL AB LE = BAD_USER_OR_PASS = NOT_AUTHORIZED = };

58

#endif

48 49 50 51 52 53 54 55

87 (0 x00 ) (0 x08 ) (0 x00 ) (0 x02 ) (0 x04 ) (0 x01 )

’M ’ ’Q ’ ’I ’ ’s ’ ’d ’ ’p ’

(0 x00 ) , (0 x01 ) , (0 x02 ) , (0 x03 ) , (0 x04 ) , (0 x05 )

Listado 5.4: Archivo de cabecera tras codificar el formato de lo mensajes de MQTT. La mayor parte de estos datos, son usados para codificar las cabeceras de los mensajes, sobre todo la fija. Otros simplemente conviene identificarlos para dotar al código de más legibilidad, como los retornos de la petición de conexión.

5.3.3

Implementación del protocolo

A partir del estudio de la parte 2 de la especificación de MQTT y utilizando el archivo de cabecera mqtt.h, a lo largo de esta fase se irán implementando todos los mensajes del protocolo (véase Cuadro 5.7), dotando poco a poco al código de todas las características de MQTT. Para lograr este cometido será necesario la creación de varios archivos nuevos, y la modificación de mqtt.h, para ir haciéndolo más completo. Cuando terminen los esfuerzos de implementación, se dispondrá de una librería que dará soporte completo a MQTT, para que posteriormente sea usada en la pasarela como parte del proceso de traducción entre MQTTSN y MQTT. El código de la toda librería tiene la siguiente estructura: Archivo mqtt.h, que contiene toda la estructura del protocolo. Aquí están declaradas

88

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO todas las variables, constantes, estructuras y prototipos de funciones necesarias. También todos los archivos de cabecera necesarios. Archivo mqtt.c, en el que se hará uso de todas las declaraciones del archivo mqtt.h para implementar las distintas funcionalidades del protocolo. Archivo mqtt-test.c, que contendrá los tests que se hayan ido creando durante la implementación del protocolo. Archivo Makefile, que se encarga de compilar los archivos anteriores y de generar el ejecutable para que puedan pasarse los test. Mnemónico CONNECT CONNACK PUBLISH PUBACK PUBREC PUBREL PUBCOMP SUBSCRIBE SUBACK UNSUBSCRIBE UNSUBACK PINGREQ PINGRESP DISCONNECT

Descripción El cliente realiza una petición de conexión al servidor Acuse de recibo de la petición de conexión Publicación de un mensaje Acuse de recibo de la publicación Indicador de publicación recibida Indicador de publicación realizada Indicador de publicación completada El cliente realiza una petición de suscripción Acuse de recibo para la peticón de suscripción El cliente realiza una petición de unsuscripción Acuse de recibo para la petición de unsuscripción Petición de PING Respuesta de PING El cliente indica que se desconecta

Cuadro 5.7: Descripción de los mensajes MQTT. Fuente: [Loc10]. Todo el código generado en esta etapa ha sido creado utilizando la metodología de desarrollo TDD. Para ello se han identificado varios escenarios de actuación del protocolo, cada uno de los cuales se implementa en una iteración, de forma que con cada escenario se prueba todo el código generado hasta el momento, asegurando que las nuevas funcionalidades no dañan las ya existentes. Los escenarios identificados son: Escenario CONNECT/DISCONNECT: en el que un cliente se conecta y desconecta de Mosquitto. Escenario SUBSCRIBE/UNSUBSCRIBE: en el que un cliente se suscribe a un topic, y después elimina esta suscripción. Escenario PUBLISH: en el que un cliente publica información a un topic, utilizando cada uno de los niveles de Q O S de MQTT. Escenario PING: en el que un cliente envía y recibe un ping, para probar las funciones de mantenimiento de la conexión.

5.3. ETAPA 3: LIBRERÍA MQTT

89

En general, el empleo práctico de TDD sigue los siguientes pasos [KBE06]: 1. Escoger la funcionalidad del sistema que se va a desarrollar. 2. Desarrollar un test que verifique la funcionalidad escogida. 3. Enlazar el código funcional al test para hacer que este compile. 4. Compilar y comprobar que al ejecutar el test falla. 5. Desarrollar el código funcional. 6. Compilar y ejecutar el test. 7. Refactorizar el código funcional. 8. Repetir los pasos 6 y 7 hasta que el código funcional se convierte en una implementación limpia. 9. Repetir los pasos 1-8 hasta que todas las funcionalidades sean implementadas. Estos pasos representan la secuencia detallada de como seguir el algoritmo de TDD, visto en la Sección 4.1.2. En este caso, las funcionalidades del sistema, son los distintos escenarios de actuación del protocolo y los test se desarrollan utilizando el framework CUnit. Con la consecución de las distintas iteraciones se consigue implementar todos los mensajes del protocolo, con una buena cobertura de pruebas. Esta implementación es un trabajo mecánico, una vez que se haya conseguido implementar el primer escenario, se dispondrá del código necesario para que el resto de implementaciones sean más ligeras, ya que se habrán creado diversas funciones comunes a todos los escenarios y se habrán solventado numerosos problemas que pueden surgir al formar los mensajes. Con el fin de mostrar este proceso de implementación, en este documento se detallarán los procedimientos realizados durante la primera iteración de la metodología, en la que se desarrolla el escenario CONNECT/DISCONNECT. Este escenario tiene especial importancia, ya que sin su implementación no pueden llevarse a cabo el resto de escenarios y al tener que formarse los primeros mensajes del protocolo, tiene que escribirse el código de funciones importantes que serán usadas durante el resto del proceso. Escenario CONNECT/DISCONNECT Siguiendo los pasos de TDD, para la implementación de este, y de todos los escenarios, se han realizado los siguientes procedimientos: 1. Escoger la funcionalidad del sistema que se va a desarrollar: La funcionalidad elegida es el escenario de actuación del protocolo en el que un cliente se conecta al broker Mosquitto y después se desconecta. Este escenario engloba

90

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO todos los tipos posibles de conexión: clean-session, unclean session y con usuario y contraseña. Antes de pasar al siguiente paso, es necesario un estudio de la parte 2 de la especificación de MQTT, para detectar que mensajes deben implementarse y sus principales requisitos. Esto dará como resultado que los test sean de mayor calidad, ya que tendrán una mayor adecuación a las necesidades de un futuro cliente MQTT. 2. Desarrollar un test que verifique la funcionalidad escogida: Todos los test que se realizan durante el proceso de implementación forman parte de una única suite, que consta de dos funciones: inicialización y destrucción. En la inicialización de la suite se crea todo lo necesario para que un cliente pueda conectarse al broker y proceder al intercambio de mensajes. En la destrucción de la suite se limpia lo creado anteriormente. Esta suite puede verse en el Listado 5.5. La mayor parte del código no tiene sentido porque aún no están creadas las estructuras, variables, funciones, etc. que lo harían compilar. Esto llegará en pasos posteriores.

1 2 3 4 5 6 7 8 9 10 11 12 13 14

16 17 18 19 20 21 22 23

/∗ SUITE ∗/ int init_suite (void) { /∗ initilization of conexion structure ∗ and TCP conexion with the broker ∗/ broker = ( broker_handle_t ∗) malloc (sizeof( broker_handle_t )); if( ( broker != NULL ) && ( mqtt_init ( broker , " localhost " , " 1883 " )) >= 0 ) { return 0; } else { return −1; } } int clean_suite (void) { /∗ close TCP socket and free variables ∗/ close ( broker −>sockfd ); free ( broker ); broker = NULL ; return 0; }

Listado 5.5: Suite para los test MQTT. Para llevar a cabo la funcionalidad elegida, es necesaria la implementación de los men-

5.3. ETAPA 3: LIBRERÍA MQTT

91

sajes: CONNECT, DISCONNECT y CONNACK. Con lo cual se han realizado test que envían y reciben estos mensajes, para cada tipo de conexión. En el Listado 5.6 pueden verse los distintos test para este escenario, los cuales han sido añadidos a la suite anterior, y esta suite al registro de test, para posteriormente ser ejecutados. Todo este código se omite en el listado ya que sigue las directrices que se detallan en el Anexo D. 1 2 3 4 5 6 7 8

10 11 12 13 14 15 16 17 18 19

21 22 23 24 25 26 27 28 29 30

/∗ Clean−session conexion Test ∗/ void tes tCONNE CT_cle an (void) { mq tt _s et _c li en t_ id ( broker , " mqtt_clean " ); CU_ASSERT_TRUE ( mq tt_se nd_con nect ( broker ) ); CU_ASSERT_TRUE ( mq tt_re cv_con nack ( broker ) ); CU_ASSERT_TRUE ( m q t t _ s e n d _ d i s c o n n e c t ( broker ) ); } /∗ Unclean−session conexion Test ∗/ void t e st C O NN E C T_ u n Cl e a n (void) { mqtt_init ( broker , " localhost " , " 1883 " ); mq tt _s et _c li en t_ id ( broker , " mqtt_unclean " ); broker −>clean_session = 0; CU_ASSERT_TRUE ( mq tt_se nd_con nect ( broker ) ); CU_ASSERT_TRUE ( mq tt_re cv_con nack ( broker ) ); CU_ASSERT_TRUE ( m q t t _ s e n d _ d i s c o n n e c t ( broker ) ); } /∗ Username and password conexion Test ∗/ void t e s t C O N N E C T _ u s e r p a s s (void) { mqtt_init ( broker , " localhost " , " 1883 " ); mq tt _s et _c li en t_ id ( broker , " mqtt_userpass " ); mqtt _set_ userpa ss ( broker , " botto " , " botto " ); CU_ASSERT_TRUE ( mq tt_se nd_con nect ( broker ) ); CU_ASSERT_TRUE ( mq tt_re cv_con nack ( broker ) ); CU_ASSERT_TRUE ( m q t t _ s e n d _ d i s c o n n e c t ( broker ) ); }

Listado 5.6: Test para el escenario CONNECT/DISCONNECT. Como puede observarse, para cada conexión MQTT será necesario inicializar un manejador de conexión, una conexión TCP con Mosquitto y después configurar el manejador según las opciones de conexión que se busquen. 3. Enlazar el código funcional al test, para hacer que este compile: Para que los test anteriores compilen es necesario el siguiente código funcional:

92

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO • Manejador de conexión con el broker Mosquitto. Este elemento es una estructura que contiene todas las variables necesarias para el establecimiento de una conexión MQTT, forma parte del archivo mqtt.h. Esta estructura debe inicializarse antes de enviar el primer mensaje CONNECT de cada cliente, todos los mensajes necesitarán obtener información de ella (véase Listado 5.7). 1 2 3 4 5 6 7 8 9 10 11 12

/∗ broker handler ∗/ typedef struct{ int sockfd ; char client_id [23]; char username [13]; char password [13]; uint8_t will_retain ; uint8_t will_qos ; uint8_t clean_session ; uint16_t keep_alive ; uint8_t debug_session ; } broker_handle_t ;

Listado 5.7: Manejador de conexión con el broker. • Funciones para modificar algunos de los campos del manejador de conexión. • Funciones de inicialización de las conexiones TCP y MQTT. • Funciones para enviar los mensajes CONNECT y DISCONNECT. • Función para recibir el mensaje CONNACK y comprobar el código de retorno. • Funciones para realizar el envío y recepción de datos por el socket TCP previamente creado. • Funciones para la comprobación del tipo de mensaje MQTT. Estas funciones deberán tener su prototipo en el archivo mqtt.h (véase Listado 5.8) y su implementación en mqtt.c (en un principio vacía). Todas reciben, al menos, el manejador de conexión como parámetro. 1 2 3

5 6

8 9 10 11 12

/∗ initialize the broker handler connection ∗/ int mqtt_init ( broker_handle_t ∗ broker , const char∗ host , const char∗ port ); /∗ initialize tcp connection ∗/ int mq tt _c re at e_ so ck et (const char∗ host , const char∗ port ); /∗ send−receive mqtt packets throught tcp socket ∗/ int mqtt_send_packet ( broker_handle_t ∗ broker , size_t send_buffer_size , uint8_t type_id ); int mqtt_recv_packet ( broker_handle_t ∗ broker , size_t recv_buffer_size , uint8_t type_id );

5.3. ETAPA 3: LIBRERÍA MQTT 14 15 16

18 19 20 21

23 24 25 26

93

/∗ check and get message by type ∗/ int mq tt _c he ck _m sg ty pe ( uint8_t type_id ); const char∗ mqtt_get_msgtype ( uint8_t type_id ); /∗ set client−id , user and password fields functions ∗/ void m qtt _s et _c li en t_ id ( broker_handle_t ∗ broker , const char ∗ id ); void mqt t_set_ userpa ss ( broker_handle_t ∗ broker , const char ∗ username , const char ∗ pass ); /∗ send−receive functions ∗/ int mqtt _send _conne ct ( broker_handle_t ∗ broker ); int mqtt _recv _conna ck ( broker_handle_t ∗ broker ); int m q t t _ s e n d _ d i s c o n n e c t ( broker_handle_t ∗ broker );

Listado 5.8: Prototipos de las funciones necesarias para el escenario CONNECT/DISCONNECT Por otra parte, en el archivo de test mqtt-test.c deberá incluirse el archivo de cabecera mqtt.h, para tener disponibles este código funcional creado. 4. Compilar y comprobar que al ejecutar el test falla: En este instante, una vez que se logre que el archivo de test compile con el código funcional, los test fallarán. Ya que no hay implementada ninguna funcionalidad de las funciones anteriores. 5. Desarrollar el código funcional: Con el fin de lograr que se pasen todos los test, en este paso se desarrolla el código de cada una de las funciones anteriores. • Creación de la conexión TCP (mqtt_create_socket): Esta función recibe como parámetros el host y el puerto donde reside el broker Mosquitto, y abre una conexión TCP con él. Devuelve el descriptor de socket que se haya asignado a la conexión TCP. El código de esta función se ha obtenido del Manual de Linux para Programadores, en concreto de la entrada getaddrinfo. • Inicialización de la conexión MQTT (mqtt_init): Esta función inicializa todos los campos del manejador de conexión con el broker o broker handler. Le llega por parámetro la dirección de memoria del manejador, el host y el puerto requeridos para la conexión TCP. Para obtener el descriptor del socket con Mosquitto, se utiliza la función anterior. El resto de variables se inicializan con valores por defecto, determinados por las buenas prácticas de MQTT, en su especificación. Los valores que no siempre es necesario usarlos, se

94

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO inicializan a cero, quedando en manos del cliente su modificación (véase Listado 5.9). 1 2 3 4 5 6 7 8 9

int mqtt_init ( broker_handle_t ∗ broker , const char ∗ host , const char ∗ port ) { mqtt_id ++; broker −>sockfd = mq tt_c re at e_ so ck et ( host , port ); broker −>will_retain = 0; broker −>will_qos = 0; broker −>clean_session = 1; broker −>keep_alive = 60; broker −>debug_session = 0;

14

memset ( broker −>username , 0 , sizeof( broker −>username )); memset ( broker −>password , 0 , sizeof( broker −>password )); memset ( broker −>client_id , 0 , sizeof( broker −>client_id )); sprintf ( broker −>client_id , " mqtt : %d " , mqtt_id );

16

return broker −>sockfd ;

11 12 13

17

}

Listado 5.9: Función de inicialización del manejador de conexión Puede observarse como, en primera instancia, se incrementa la variable mqtt_id y que posteriormente se usa para formar el identificador de cliente. Esta variable se ha añadido como global a todo el código y representa un identificador de cliente MQTT, para que cada cliente conectado disponga por defecto, de una identidad única de cara al broker. • Modificación de las variables del manejador: Estas funciones simplemente modifican los valores de las variables del manejador. Deberán ser ejecutadas después de crear la conexión TCP y antes de enviar el mensaje de petición de conexión MQTT. • Funciones de envío/recepción de datos por el socket TCP (mqtt_send_packet, mqtt_recv_packet): Estas funciones sirven para enviar/recibir datos por el socket que indique el manejador de conexión, de esta forma se desacopla el envío y la recepción de datos, de las funciones que implementan los mensajes MQTT. Una vez enviados/recibidos datos, se realizan comprobaciones (tanto en el socket, como en el tipo de mensaje MQTT), generándose un mensaje de alerta en caso de detectar error. Para realizar sus cálculos, estas funciones se ayudan de mqtt_check_msgtype() (comprueba si el código de mensaje que le llega por parámetro es igual al del mensaje que se está comprobando) y de mqtt_get_msgtype() (devuelve una cadena de caracteres que indica el nombre del mensaje correspondiente al código que

5.3. ETAPA 3: LIBRERÍA MQTT

95

le llega por parámetro). • Función para el envío del mensaje CONNECT (mqtt_send_connect): Esta función es una de las más importantes de todo el código de la librería. Tras el establecimiento de una conexión TCP con el broker, el cliente debe crear una sesión MQTT usando un mensaje de petición de conexión MQTT al broker. Si el mensaje está bien formado y los parámetros de conexión son válidos, el broker responderá a esta petición con un acuse de recibo (mensaje CONNACK en este caso), si no se indica error, la conexión quedará establecida. Para obtener toda la información necesaria sobre como debe formarse este mensaje, es necesario consultar la especificación de MQTT, parte 2. Aquí puede verse que el mensaje CONNECT está formado por tres partes (cabecera fija, cabecera variable y payload), la estructura de cada parte ya se mencionó en la Sección 5.3.1. Los flags de mensaje de la cabecera fija no se utilizan en este caso, la cabecera variable contiene: nombre del protocolo, versión del protocolo, flags de conexión y periodo de «tiempo de vida» o Keep Alive Timer. Un total de 12 bytes. El payload contiene obligatoriamente el identificador de cliente, y de forma opcional el resto de campos (Will Topic, Username, etc.), que estarán presentes o no, en función de los flags que se activen. • Función para la recepción del mensaje CONNACK (mqtt_recv_connack): Este mensaje lo envía el broker para indicar el estado en que se encuentra la petición de conexión del cliente (aceptada o rechazada). En caso de ser rechazada, se indica el problema mediante un código (véase Cuadro 5.5). Esta función (al igual que todas las funciones de recepción de mensajes MQTT) debe llamar en primera instancia a la función de recepción desde el socket TCP, que almacenará los datos recibidos en el array mqtt_recv_buffer y comprobará ciertos errores. Si el mensaje es correcto solo queda comprobar el código de retorno para ver si se ha establecido o no, y porque motivo. La primera versión del código de esta función puede verse en el Listado 5.10. 1 2 3 4 5 6 7 8 9 10 11

/∗ function to handler the connack message ∗/ int mqt t_recv _conna ck ( broker_handle_t ∗ broker ) { int ret ; /∗ receive from the socket ∗/ ret = mqtt_recv_packet ( broker , CONNACK , MQTT_ TYPE_ CONNAC K ); if( ret > 0) { /∗ if connection accepted ∗/ if( mqtt_recv_buffer [3] == C O N NE C T I ON _ A CC E P TE D ) { if( broker −>debug_session ) printf ( " Conexion accepted \ n " ); return SUCCESS ;

96

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO } /∗ if not , check the return code and display the error ∗/ else { switch( mqtt_recv_buffer [3]) { case UN PR OT OC OL _V ER SI ON : fprintf ( stderr , " Unnaceptable protocol version \ n " ); break; case I DE N T I FI E R _R E J EC T E D : fprintf ( stderr , " Identifier rejected \ n " ); break; case SE RV ER _U NA VA IL AB LE : fprintf ( stderr , " Server unavailable \ n " ); break; case BAD_USER_OR_PASS : fprintf ( stderr , " Bad user name or password \ n " ); break; case NOT_AUTHORIZED : fprintf ( stderr , " Not authorized \ n " ); break; } return −1; }

12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

} else return −1;

34 35 36

}

Listado 5.10: Implementación del mensaje CONNACK. Como puede observarse, para consultar el código de retorno, debe examinarse el contenido del cuarto byte del mensaje CONNACK que envía el broker. Esta información se obtiene de la parte 2 de la especificación de MQTT. • Función de envío del mensaje DISCONNECT (mqtt_send_disconnect): Esta función es sencilla de implementar, el mensaje DISCONNECT tan solo ocupa 2 bytes (la cabecera fija). El primer byte contiene el tipo de mensaje y los flags inactivos, el segundo byte es remaining length y contiene un cero, ya que el mensaje no tiene ningún campo más. Este mensaje no necesita acuse de recibo por parte del servidor. El código elaborado para esta función puede verse en el Listado 5.11. 1 2 3 4 5

7

/∗ function to send a disconnect message ∗/ int m q t t _ s e n d _ d i s c o n n e c t ( broker_handle_t ∗ broker ) { uint8_t packet [] = { MQTT_TYPE_DISCONNECT , (0 x00 )}; memset ( mqtt_send_buffer , 0 , M AX_PAC KET_LE NGTH ); memcpy ( mqtt_send_buffer , packet , sizeof( packet )); return mqtt_send_packet ( broker , sizeof( packet ) ,

5.3. ETAPA 3: LIBRERÍA MQTT

97 M Q T T _ T Y P E _ D I S C O N N E C T );

8 9

}

Listado 5.11: Implementación del mensaje DISCONNECT. Como puede observarse se utiliza el array mqtt_send_buffer, para almacenar los datos que forman el mensaje. Este buffer posteriormente es utilizado por la función mqtt_send_packet() para enviar el paquete MQTT por el socket. Tiene un tamaño máximo de 255 bytes. 6. Compilar y ejecutar el test: Cuando se tenga todo el código funcional implementado, deben ejecutarse los tests, para comprobar que, efectivamente, pasan. $ make test ./ exec / mqtt - test CUnit - A unit testing framework for C - Version 2.1 -2 http :// cunit . sourceforge . net / Suite : General Suite Test : connect & disconnect () _clean ... passed Test : connect & disconnect () _unclean ... passed Test : connect & disconnect () _userpass ... passed Run Summary :

Type suites tests asserts

Elapsed time =

Total 1 3 9

Ran Passed Failed Inactive 1 n/a 0 0 3 3 0 0 9 9 0 n/a

0.001 seconds

7. Refactorizar el código funcional: Una vez que se tiene el código funcional para un determinado escenario, en esta fase debe refactorizarse, es decir, revisarse en busca de mejoras. Como eliminar redundancias, dotarlo de mayor legibilidad, elegir buenos nombres para las variables, etc. 8. Repetir los pasos 6 y 7 hasta obtener una implementación limpia: Después de cada fase de refactorización, deben ejecutarse de nuevo las pruebas, para asegurarse de que los cambios no modifican el comportamiento del código. Cuando se disponga de una implementación limpia, habrá terminado esta fase y la primera iteración del proceso. La función que ha sufrido cambios más significativos es la encargada de enviar el mensaje CONNECT. Como ya se ha mencionado, es una de las funciones más importantes de la librería, y es fundamental que esté implementada de forma correcta. La última versión de su código, debidamente comentada para mayor claridad, puede verse en el Listado 5.12.

98

1

3 4 5 6 7 8 9 10 11 12 13 14

16 17

19 20 21 22

24 25 26 27

29 30 31 32 33 34 35 36 37 38 39 40 41

43 44 45 46

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

/∗ FUNCTION TO SEND CONNECT MESSAGE ∗/ int mqt t_send _conne ct ( broker_handle_t ∗ broker ) { /∗ VARIABLES ∗/ // lengths uint16_t clientidlen = strlen ( broker −>client_id ); uint16_t usernamelen = strlen ( broker −>username ); uint16_t passwordlen = strlen ( broker −>password ); uint16_t payloadlen = clientidlen +2; // others uint8_t flags = (0 x00 ) , offset = 0; uint8_t ∗ payload , var_header [12]; uint16_t packetlen ; // set clean−session flag if( broker −>clean_session ) flags |= M Q T T _ C O N N E C T _ C L E A N _ S E S S I O N ; /∗ GENERATE PAYLOAD AND UPDATE VARIABLE−HEADER FLAGS ∗/ // allocate memory and set to 0 payload = ( uint8_t ∗) malloc ( payloadlen ∗sizeof( uint8_t )); memset ( payload ,0 , payloadlen ); // set client id payload [ offset ++] = clientidlen >> 8; // string length MSB payload [ offset ++] = clientidlen & (0 xFF ); // string length LSB memcpy ( payload + offset , broker −>client_id , clientidlen ); // data // put username in payload if it ’s neccesary if( usernamelen ) { payloadlen += usernamelen +2; // update payload length offset += clientidlen ; // update offset inside payload flags |= M Q T T _ C O N N E C T _ U S E R N A M E ; // update flags // reallocate mem and add username to payload payload = ( uint8_t ∗) realloc ( payload , payloadlen ); memset ( payload + offset ,0 , payloadlen −offset ); payload [ offset ++] = usernamelen >> 8; payload [ offset ++] = usernamelen & (0 xFF ); memcpy ( payload + offset , broker −>username , usernamelen ); } // put password in payload if it ’s neccesary if( passwordlen ) { payloadlen += passwordlen +2; // update payload length

5.3. ETAPA 3: LIBRERÍA MQTT offset += usernamelen ; // update offset inside payload flags |= M Q T T _ C O N N E C T _ P A S S W O R D ; // update flags // reallocate mem and add password to payload payload = ( uint8_t ∗) realloc ( payload , payloadlen ); memset ( payload + offset ,0 , payloadlen −offset ); payload [ offset ++] = passwordlen >> 8; payload [ offset ++] = passwordlen & (0 xFF ); memcpy ( payload + offset , broker −>password , passwordlen );

47 48 49 50 51 52 53 54 55

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

75 76 77 78 79 80

82 83 84 85 86 87 88 89 90 91 92

99

} /∗ VARIABLE−HEADER ∗/ // protocol name var_header [0] = (0 x00 ); // string length MSB var_header [1] = (0 x06 ); // string length LSB var_header [2] = MQTT_CONNECT_M ; // data var_header [3] = MQTT_CONNECT_Q ; var_header [4] = MQTT_CONNECT_I ; var_header [5] = MQTT_CONNECT_s ; var_header [6] = MQTT_CONNECT_d ; var_header [7] = MQTT_CONNECT_p ; // protocol version var_header [8] = M Q T T _ P R O T O C O L _ V E R S I O N ; // flags var_header [9] = flags ; // keep−alive var_header [10] = broker −>keep_alive >> 8; var_header [11] = broker −>keep_alive & (0 xFF ); /∗ FIXED−HEADER ∗/ // now we know remaining length uint8_t fix_header [] = { MQT T_TYPE _CONNE CT | MQTT_NO_FLAGS , ( uint8_t )(sizeof( var_header )+ payloadlen ) }; /∗ PACKET ∗/ // set packet length packetlen = sizeof( fix_header )+sizeof( var_header )+ payloadlen ; // reset send buffer memset ( mqtt_send_buffer , 0 , M AX_PAC KET_L ENGTH ); // add fix−header , var−header and payload memcpy ( mqtt_send_buffer , fix_header , sizeof( fix_header )); memcpy ( mqtt_send_buffer +sizeof( fix_header ) , var_header , sizeof( var_header )); memcpy ( mqtt_send_buffer +sizeof( fix_header )+sizeof( var_header ) , payload , payloadlen );

100

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO // free memory free ( payload ); payload = NULL ;

94 95 96

// send packet and return return mqtt_send_packet ( broker , ( size_t ) packetlen , MQTT _TYPE _CONNE CT );

98 99 100 101

}

Listado 5.12: Implementación del mensaje CONNECT. El último paso de las directrices que marca TDD es el de repetir los pasos 1-8 hasta que todas las funcionalidades sean implementadas. En este caso, se deberá elegir un escenario distinto en cada iteración, y su implementación se irá realizando de igual manera a como se ha descrito en este escenario, pero con mucho menos esfuerzo, ya que tras esta primera iteración se han escrito partes de la librería que son usadas por todos los mensajes, y que como se ha podido comprobar, funcionan correctamente. Tras realizar todas las iteraciones, quedan implementados todos los mensajes de MQTT, con una alta cobertura de pruebas. Una vez finalizado la última iteración, la salida de test que se obtiene es la siguiente: $ make test ./ exec / mqtt - test CUnit - A unit testing framework for C - Version 2.1 -2 http :// cunit . sourceforge . net / Suite : General Suite Test : connect & disconnect () _clean ... passed Test : connect & disconnect () _unclean ... passed Test : connect & disconnect () _userpass ... passed Test : subscribe & unsubscribe () _topicQoS0 ... passed Test : subscribe & unsubscribe () _topicQoS1 ... passed Test : publish () _QoS0 ... passed Test : publish () _QoS1 ... passed Test : publish () _QoS2 ... passed Test : publish () _dup ... passed Test : publish () _retain ... passed Test : ping () ... passed Run Summary :

Type suites tests asserts

Elapsed time =

Total 1 11 52

Ran Passed Failed Inactive 1 n/a 0 0 11 11 0 0 52 52 0 n/a

0.002 seconds

Donde puede verse como se han pasado con éxito todos los test unitarios que se han ido creando en las distintas iteraciones. A partir de este momento, se obtiene uno de los primeros resultados de este proyecto, una librería para el protocolo MQTT.

5.4. ETAPA 4: PASARELA TRANSPARENTE

101

5.4 Etapa 4: Pasarela transparente Gracias a los resultados obtenidos en etapas anteriores, ya se dispone de un despliegue mínimo de la plataforma sensora y de una librería MQTT, destinada a ejecutarse en Meshlium como parte del proceso de traducción entre protocolos. El siguiente paso es preparar la pasarela para que sea capaz de actuar como pasarela transparente entre los clientes MQTT-SN y el broker MQTT (véase Figura 3.9). Debe elaborarse un programa que haga que la pasarela se mantenga a la espera tanto de paquetes MQTT-SN como MQTT, y cuando los reciba, realice la traducción que corresponda en cada caso y los envíe a uno de los extremos de la comunicación (cliente o broker). Este software es una pieza clave dentro de la infraestructura que se está desarrollando, ya que sin él no es posible que la información recopilada por los sensores llegue hasta Mosquitto, y por ende, a los suscriptores externos. Debe poseer las siguientes características: Capacidad para: 1. Recibir frames 802.15.4. 2. «Parsear» estos frames para obtener el paquete MQTT-SN que contienen, y el resto de información útil que envíen los sensores. Capacidad para que un cliente MQTT-SN pueda realizar las siguientes acciones: • Conectarse y desconectarse a un broker MQTT. • Publicar información a un topic determinado de un broker MQTT, utilizando cualquiera de las Q O S que ofrece tanto MQTT-SN como MQTT. • Realizar el procedimiento de registro de un Topic Name. • Mantener la conexión con el broker utilizando pings. Capacidad para que un broker pueda enviar mensajes a los clientes conectados. Capacidad para mantener varios de estos clientes conectados al mismo tiempo. Proporcionar seguridad a la información de cada cliente, para que esta no se mezcle con la del resto. Controlar casos especiales, como los reintentos de conexión. La pasarela transparente establece una conexión con Mosquitto por cada cliente MQTTSN conectado, con el fin de establecer un flujo de datos entre ambas partes. Para mantener este flujo, debe atender las peticiones que le lleguen desde estas conexiones, es decir, tiene que actuar como un servidor que es capaz de mantener un conjunto de descriptores de archivo (cada uno maneja una conexión) y ejecutar un conjunto de acciones según se activen unos u otros. Entre estos descriptores pueden diferenciarse dos tipos4 : el que se usa para manejar 4

En los sistemas Unix, los descriptores de archivo se pueden referir a archivos, directorios, dispositivos de bloques o dispositivos de caracteres (también llamados “archivos especiales”), sockets, FIFOs (también llamados “tuberías con nombre”) o tuberías sin nombre.

102

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

la interfaz 802.15.4 y los usados para manejar los distintos sockets abiertos (descriptores de socket) con Mosquitto. Si se activa el descriptor de 802.15.4: Significa que existen datos disponibles en él, procedentes de algún sensor. La pasarela deberá recibir estos datos y procesarlos. Tras este procesamiento se dispondrá de la dirección MAC origen de los datos (el sensor que ha emitido el mensaje) y del paquete MQTT-SN que ha sido enviado. Una vez hecho esto, la pasarela deberá actuar en consecuencia, dependiendo del tipo de mensaje recibido. Es decir, como servidor o como traductor, además de las acciones asociadas que conlleve cada tipo de mensaje. Por último, volverá a mantenerse a la espera de que se active algún descriptor. Si por el contrario, se activa un descriptor de socket: Significa que Mosquitto ha enviado un mensaje MQTT a la pasarela. Estos datos deben recibirse y procesarse. En este caso la pasarela siempre debe actuar como traductor. Es decir, detectar que tipo de mensaje MQTT se ha recibido, traducirlo y enviarlo al sensor correspondiente. Todo este proceso es complejo y requiere bastante esfuerzo de implementación. Por ello, en lo que resta de sección, primero se exponen los diferentes archivos que forman esta pasarela software, describiendo cada una de sus partes. Después se muestran distintos pseudocódigos del archivo principal, con el objetivo de esclarecer el funcionamiento del programa y se explica en detalle el funcionamiento de este código.

5.4.1

Estructura del código

El código de la pasarela tiene la siguiente estructura: Librería MQTT: • mqtt.h • mqtt.c Librería utils: • utils.h • utils.c Librería mqttsnServerForwarder: • mqttsnSF.cpp • mqttsnSF.h Archivo principal tGatewayServer.cpp

5.4. ETAPA 4: PASARELA TRANSPARENTE

103

La librería MQTT ya es una parte del software completamente operativa y funcional. Se ha desarrollado durante las etapas anteriores y proporciona a la pasarela toda la funcionalidad necesaria para que esta establezca sesiones MQTT con Mosquitto. La librería mqttsnServerForwarder realiza dos funciones. Por un lado maneja todo el proceso relativo a la traducción entre MQTT-SN y MQTT, y por otro, realiza funciones de servidor MQTT-SN cuando los clientes conectados lo requieren. Para realizar la traducción entre protocolos, se utiliza una librería reducida de MQTT-SN, contenida en el archivo mqttsnSF.h, este archivo de cabecera, al igual que mqtt.h, ofrece identificadores de los distintos valores que pueden tomar los campos de bits, que se utilizan para formar los mensajes MQTT-SN (códigos de los mensajes, flags, código de retorno, etc.), todo ello sacado de la librería de MQTT-SN que también se ha desarrollado en este proyecto y que será explicada en secciones posteriores. A partir de la aplicación de operaciones a nivel de bit, utilizando la información de la librería y los mensajes MQTT-SN entrantes, se obtiene la información necesaria para formar un mensaje MQTT, haciendo uso la librería MQTT desarrollada. La traducción propiamente dicha, se realiza en dos funciones de esta librería: Función mqttsn2mqtt(): Esta función se encarga de traducir un mensaje MQTT-SN a MQTT. Su estructura es sencilla, dispone de un switch que ejecuta un conjunto de sentencias u otro, en función del tipo de mensaje (CONNECT, PUBLISH, etc). En el Pseudocódigo 5.1 puede verse un esquema orientativo de esta función: Función mqtt2mqttsn(): Esta función realiza la traducción inversa a la función anterior, de MQTT a MQTT-SN. Su estructura es la misma, un switch que ejecutará unas sentencias u otras, en función del tipo de mensaje que se esté procesando. En este caso, los mensajes serán acuses de recibo que el broker envía a la pasarela, como respuesta a los mensajes previos. Con lo cual, deberán ser traducidos y enviados a los clientes MQTT-SN. Completando, de esta forma, el proceso de traducción para cada escenario del protocolo. En el Pseudocódigo 5.2 puede verse un esquema orientativo de esta función: El código de ambas funciones se completará durante la etapa de implementación del protocolo MQTT-SN, ya que durante esta etapa se adquieren unos conocimientos sólidos del protocolo y es el mejor momento para realizar la traducción. Por otra parte, hay ciertos mensajes MQTT-SN que no deben ser traducidos y enviados a Mosquitto, sino que requieren la ejecución de acciones concretas en la pasarela y que esta les envíe una respuesta. Es decir, necesitan que la pasarela actúe como servidor. En este caso, cuando se detecte uno de estos mensajes, deberá ejecutarse un manejador determinado, que

104

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

Pseudocódigo 5.1 Pseudocódigo de la función mqttsn2mqtt(). function MQTTSN 2 MQTT(mqtt-sn message) Switch Message type Case CONNECT –Code to translate message res ← MQTT _ SEND _ CONNECT(broker) EndCase Case DISCONNECT –Code to translate message res ← MQTT _ SEND _ DISCONNECT(broker) CLOSE (socket) EndCase Case PUBLISH –Code to translate message res ← MQTT _ SEND _ PUBLISH(broker, topicN ame, msg, qos, dup, retain) EndCase Case PUBREL –Code to translate message res ← MQTT _ SEND _ PUBREL(broker) EndCase Case PINGREQ –Code to translate message res ← MQTT _ SEND _ PING(broker) EndCase Default wrong message type EndSwitch return res end function

procese la petición y actúe según marque la especificación del protocolo. Puede verse un esquema de este tipo de escenario en el Pseudocódigo 5.3. El resto de funciones de esta librería, son utilidades concretas para alguno de los mensajes. De ser importantes, serán explicadas durante el proceso de implementación de MQTT-SN y posterior traducción. Por su parte, la librería utils contiene todo el código necesario para operar con el módulo XBee de la pasarela. Como se verá en la siguiente etapa, cuando un sensor quiere enviar un mensaje MQTT-SN, lo encapsula en un paquete 802.15.4 junto con su dirección MAC y después lo manda por la red. Cuando este paquete llega a la pasarela, se activa el correspondiente descriptor de archivo y el servidor que está en ejecución (la pasarela transparente) debe leer de este descriptor para obtener la información contenida en dicho paquete. Para realizar las funciones de inicialización del descriptor, lectura y «parseo» de la información recibida, y envío de datos desde la pasarela a los sensores, el programa principal utiliza las funcionalidades que ofrece esta librería. El código necesario para realizar estas

5.4. ETAPA 4: PASARELA TRANSPARENTE

105

Pseudocódigo 5.2 Pseudocódigo de la función mqtt2mqttsn(). function MQTT 2 MQTTSN(mqttM essage, originM ac) Switch Message type Case CONNACK –Code to translate message buf ← message buf Allocated ← true EndCase Case PUBACK –Code to translate message buf ← message buf Allocated ← true EndCase Case PUBREC –Code to translate message buf ← message buf Allocated ← true EndCase Case PUBCOMP –Code to translate message buf ← message buf Allocated ← true EndCase Case PINGRESP –Code to translate message buf ← message buf Allocated ← true EndCase Default wrong message type EndSwitch if buf Allocated == true then –Prepare buf to send by XBee module SEND _ BY M AC (originM ac, buf ) . Función para enviar datos a los sensores end if end function

106

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

Pseudocódigo 5.3 Pseudocódigo para un manejador de petición. function MESSAGE X_ HANDLER(message, originM ac) –Code to process the request linked to this message SEND _ MESSAGE X(param1, param2, ..., originM ac) end function function SEND _ MESSAGE X(param1, param2, ..., originM ac) –Code to generate the message to send using parameters received buf ← message SEND _ BY M AC (originM ac, buf ) end function tareas, es quizás el de más bajo nivel de esta etapa, con lo cual, en los siguientes apartados se explicará con detalle cada una de las funciones implementadas. Una vez se concluyan estos apartados, tan solo quedará explicar todo lo relacionado con el archivo principal de la pasarela (tGatewayServer.cpp). Dada su importancia, se le dedica la Sección 5.4.2. Inicialización y configuración del módulo XBee, función xbee_init() El puerto serie del modulo XBee se encuentra en el archivo /dev/ttyS0 de la pasarela. Esta función devuelve un entero que representa al descriptor de archivo de /dev/ttyS0, una vez abierto y configurado. Un descriptor de archivo, es una referencia a una de la entradas de la tabla de archivos abiertos que mantiene el sistema. En esta entrada se almacena el desplazamiento dentro del archivo y sus flags de estado. Para obtener este descriptor se utiliza la función open(), que dada una ruta de archivo, devuelve un entero no negativo que representa su descriptor. Como segundo parámetro de esta función, deben indicarse los flags de creación del archivo. Una vez obtenido correctamente el descriptor de archivo, se configuran diversos aspectos de la comunicación, como la velocidad de E/S, control de flujo, paridad, etc. para ello se utiliza una estructura del tipo termios y funciones asociadas a ella. En el Listado 5.13 puede verse el código de esta función, con aclaraciones paso a paso de todo lo que implica. 1

int xbee_init () {

3

struct termios options ;

5

/∗ opening port : ∗ O_RDWR − read and write access mode ∗ O_ASYNC − generate a signal when in input or output becomes possible on this file descriptor ∗ O_NOCTTY − for pathnames which refers to a terminal device ∗ O_NDELAY − open the file in nonblocking mode

6 7 8 9 10

5.4. ETAPA 4: PASARELA TRANSPARENTE ∗ serialPort = "/ dev / ttyS0 " ∗/ thefd = open ( serialPort , O_RDWR | O_NOCTTY | O_NDELAY | O_ASYNC ); if ( thefd == −1) { // could not open port fprintf ( stderr , " open_port : Unable to open %s \ n " , serialPort ); } else { fcntl ( thefd , F_SETFL , O_NDELAY ); tcgetattr ( thefd , & options ); // set BAUD RATE = B38400 cfsetispeed (& options , BAUD_RATE ); cfsetospeed (& options , BAUD_RATE ); // enable the receiver and set local mode ... options . c_cflag |= ( CLOCAL | CREAD ); // no parity (8 in 1) options . c_cflag &= ~ PARENB ; options . c_cflag &= ~ CSTOPB ; options . c_cflag &= ~ CSIZE ; options . c_cflag |= CS8 ; // set input mode ( non−canonical , no echo ,...) options . c_lflag = 0; // inter−character timer unused options . c_cc [ VTIME ] = 0; // blocking read until 1 char received options . c_cc [ VMIN ] = 1;

11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

38

tcflush ( thefd , TCIFLUSH );

40

// apply all changes immediately tcsetattr ( thefd , TCSANOW , & options );

41

}

42

return thefd ;

44 45

107

}

Listado 5.13: Código de la función xbee_init()

Lectura de un paquete, función xbee_getPacket() Una vez se obtenga el descriptor de archivo, se necesita disponer de un procedimiento para leer datos cuando estos estén disponibles en él. Esta función realiza esa tarea. Durante el desarrollo de este código, se han tenido grandes inconvenientes, derivados de un comportamiento inesperado del puerto serie que maneja al módulo XBee, ya que este proporcionaba una vez tras otra los datos que tenía disponibles, a pesar de que se leyesen,

108

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

haciendo imposible leer un mensaje completo utilizando el procedimiento habitual (cuando se activa el descriptor, leer todos los datos disponibles). Para solucionar este problema, se ha realizado una máquina de estados que reconoce una secuencia concreta de la información que debe recibirse, cuando la máquina de estados reconoce esta secuencia, deja que se lea el resto de información hasta fin de linea. Consiguiendo de esta forma, detectar un mensaje completo. Este procedimiento es clave en esta función y en el funcionamiento general de la pasarela transparente, ya que sin disponer de los mensajes MQTT-SN que envían los sensores, no es posible realizar ninguna acción más. Lo que resta de apartado, está dedicado a explicar con detalle el funcionamiento de la máquina de estados. En la Figura 5.9 puede verse la máquina de estados utilizada. Esta máquina se encuentra dentro de un bucle infinito, en estado IDLE, a la espera del comienzo de la secuencia de caracteres: 0x23 → 0x2d → 0x4d → 0x41. Cuando detecta el primer carácter, pasa a estado START1 y si va recibiendo la secuencia correcta avanza hasta el estado DATA, en el que permanece procesando caracteres hasta que detecta un 0x0a (carácter de nueva linea), y pasa a estado END. Cualquier carácter que rompa la secuencia durante los estados START1, START2 y START3, hace que la máquina vuelva a IDLE. Cuando se llega al estado END, significa que se ha recibido un fragmento del flujo total de caracteres, que representa un mensaje enviado por un sensor. Es el momento de almacenar la información leída en una estructura de la librería utils, para que este disponible al resto del programa. Una vez hecho esto, se activa un variable para salir del bucle en la siguiente iteración. Por su extensión no se incluye todo el código de esta función. En su lugar se exponen sus partes más importantes en el Listado 5.14, en el que puede verse como se implementa la máquina de estados y como está incluida dentro del bucle que itera leyendo caracteres. 1 2 3 4 5 6 7 8

/∗ In utils . h there are some define ’s ∗ and one struct that this function needs ∗/ #define IDLE 0 #define START1 1 #define START2 2 #define START3 3 #define DATA 4 #define END 5

13

typedef struct { char ∗ buf ; int size ; } packe t_rece ived_t ;

15

/∗ Some code of xbee_getpacket () function in utils . c ∗/

10 11 12

5.4. ETAPA 4: PASARELA TRANSPARENTE

109

Figura 5.9: Máquina de estados para detectar la secuencia de inicio de mensaje. Fuente: Elaboración propia.

17 18 19 20 21

void xbee_getPacket ( pa cket_r eceiv ed_t ∗ p802 ) { char inbuff [ MAX_FRAME ]; // Buffer to read incoming data into char ∗ offset ; int sizepacket = 0 , finish = 0; unsigned int state = IDLE ;

23

offset = & inbuff [0];

25

while (1) { // thefd is the file descriptor of / dev / ttyS0 sizepacket = read ( thefd , offset , 1); if ( sizepacket size = ( offset −&inbuff [0])+1; p802 −>buf = (char ∗) malloc ( p802 −>size ∗sizeof(char )); memcpy ( p802 −>buf , inbuff , p802 −>size );

5.4. ETAPA 4: PASARELA TRANSPARENTE

finish = 1; // set finish variable to 1 offset = & inbuff [0]; // reset offset

77 78

default: state = IDLE ; }

80 81 82

} if( finish ) break;

83 84

// exit of while if finish

}

85 86

111

}

Listado 5.14: Código principal de xbee_getPacket()

«Parseo» de un paquete para estructurar su información, función xbee_parsePacket() Después de ejecutar la función xbee_getPacket() se tendrá almacenado el paquete recibido en una estructura del tipo packet_received_t, junto con su tamaño. Como se verá en la etapa de implementación de MQTT-SN, cuando un sensor envía un mensaje, no solo envía el contenido del paquete MQTT-SN, sino que también añade su dirección MAC para que la pasarela pueda enviarle mensajes de respuesta. Para poder identificar la información se añaden etiquetas antes del comienzo de cada parte. Esta función se encarga de separar esta información y de almacenar en una estructura del tipo packet_splited_t la dirección MAC y el mensaje MQTT-SN, en variables distintas, para que el programa principal de la pasarela pueda usarlos de forma independiente. Para conseguir esto, hay que realizar un tratamiento del buffer de caracteres recibido anteriormente, en concreto se han utilizado las funciones strpbrk() y strchr() de la librería estándar de C, para localizar las etiquetas y posteriormente almacenar convenientemente la información que les sigue. La función strpbrk() recibe como parámetros dos punteros a cadenas de caracteres (s y p, respectivamente) y localiza en s, la ocurrencia de cualquiera de los caracteres de p. Devuelve un puntero al byte en s que coincide con uno de los caracteres de p, o el valor NULL si no encuentra coincidencias. La función strchr() recibe como parámetros un puntero a una cadena de caracteres (s) y un carácter (c), y localiza la primera ocurrencia de c en s. Devuelve un puntero al byte en s que coincida con c, o NULL si c no está contenido en s. Por ejemplo, la forma en que se ha obtenido la dirección MAC puede verse en el Listado 5.15. Del mismo modo, se ha obtenido el paquete MQTT-SN, y se ha almacenado en otro campo de la estructura del tipo packet_splited_t. 1 2

/∗ How to obtain mac value . ∗ −− p802 is a pa cket_r eceive d_t structure that contains

112 3 4

6 7 8 9

11 12 13

15 16 17 18 19 20 21 22 23 24 25

27 28 29 30 31 32 33 34 35

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

∗ the message received from the sensor ∗ −− pSplited is a empty packet_splited_t structure ∗/ char ∗ _macStart , ∗ aux ; char mac [22]; int index , error = 0; char pAux [ p802 −>size −1]; aux = strpbrk ( pAux , "−MAC " ); if( aux == NULL ) error = 1; // Get mac value memset ( mac , 0 , sizeof( mac )); if(! error ) { _macStart = strchr ( aux , ’: ’ ); if ( _macStart != NULL ) { index = _macStart−aux ; memcpy ( mac , aux + index +1 ,22); mac [22] = ’ \0 ’; }else error = 1; } if( error ) { fprintf ( stderr , " ERROR − Unable to parse received frame : %s \ n " , pAux ); exit (−1); } else { pSplited −>mac = (char ∗) malloc ((sizeof( mac ))∗ sizeof(char )); memset ( pSplited −>mac , 0 , sizeof( mac )); memcpy ( pSplited −>mac , mac , sizeof( mac )); }

Listado 5.15: Código ejemplo de xbee_parsePacket() Con esta función, se han terminado de desarrollar todas las utilidades necesarias para que la pasarela pueda recibir y procesar los mensajes provenientes de los sensores, aislando los distintos tipos de información disponibles en el mensaje (dirección MAC y paquete MQTTSN), pudiendo proceder así, a realizar sus funciones como servidor y traductor. Envio de datos al sensor, función send_byMac() Cuando el broker Mosquitto envíe mensajes hacia los clientes MQTT-SN, estos pasarán previamente por la pasarela, en concreto deberán pasar por la función mqtt2mqttsn() explicada anteriormente. Una vez que el mensaje haya sido traducido, la pasarela deberá enviarlo al

5.4. ETAPA 4: PASARELA TRANSPARENTE

113

sensor correspondiente, utilizando la dirección MAC del sensor, que la pasarela habrá almacenado previamente (generalmente durante la conexión del cliente MQTT-SN). La función send_byMac() se encarga de realizar este envío. Su código ha sido obtenido por completo del archivo ZigBeeSend.c contenido en la ruta /var/ManagerSystem/plugin/b_SensorData/b0_capturer/bin/ de la pasarela. Este archivo contiene funciones para enviar datos a los sensores que estén conectados en red con la pasarela Meshlium (véase Sección 5.1.2). Lo único que se ha hecho es adaptar la función que realiza el envío de mensajes utilizando la dirección MAC del sensor. En lugar de esperar el mensaje a enviar y la dirección MAC por linea de ordenes, le llegan como parámetros. También se ha eliminado una parte del código que ponía a la pasarela a la espera de recibir respuesta en un hilo de ejecución nuevo, esto no es necesario en este caso.

5.4.2

Archivo principal tGatewayServer.cpp (transparent Gateway Server)

Como se dijo al comienzo de esta sección, la pasarela transparente tiene que actuar como un programa servidor al que se le pueden conectar varios clientes, en este caso los clientes son las distintas conexiones que tiene que manejar, tanto con los sensores como con el broker MQTT. De forma que, el archivo tGatewayServer.cpp es un servidor. A la hora de escribir el código de este archivo se contemplaron dos opciones posibles: Crear un nuevo proceso o hilo por cada conexión que llegase desde los sensores, más el proceso o hilo principal, que se mantendría a la espera de aceptar nuevas conexiones. Manejar todas las conexiones en el mismo proceso, manteniendo el servidor «dormido», a la espera de que hubiese datos disponibles en alguna de las conexiones. Tras estudiar ambas posibilidades, se llegó a la conclusión de que la primera opción, sería adecuada cuando las peticiones de conexión por parte de los sensores fuesen muy numerosas, y el servidor emplease más tiempo en procesar una petición, que el periodo de tiempo que pasa entre peticiones de conexión. De forma que el servidor no fuese capaz de atender las conexiones de forma consecutiva, y tuviese que delegar este trabajo a nuevos procesos o hilos, y el dedicarse a crearlos y gestionarlos. Este caso no se adapta a estas características, ya que el tiempo en atender una petición es muy pequeño, en comparación con el tiempo en que se suceden. La segunda opción es la adecuada, ya que está pensada para cuando las peticiones de los clientes se pueden procesar rápidamente, de forma que es posible atender a una conexión antes de que se active otra. Si cada conexión que debe gestionar el servidor, es manejada por un descriptor de archivo, el código que se escriba para implementar el servidor tiene que ser capaz de gestionar un conjunto de estos descriptores (descriptor de socket, descriptor de dispositivo de terminal, etc.). Esta acción es posible llevarla a cabo con la función select() de la librería estándar de

114

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

C. La función select() permite que un programa monitorice múltiples descriptores de archivo, manteniéndose a la espera de que uno o varios de estos descriptores pasen a estado «preparado», para alguna operación de E/S. Un descriptor de archivo se considera «preparado» si es posible realizar una operación de E/S sin bloqueo. Los parámetros de esta función son los siguientes: int nfds: debe contener el valor del descriptor de archivo más alto, más uno. fd_set *readfds: puntero al conjunto de descriptores de los que interesa saber si hay algún data disponible para leer. También se avisará cuando haya un nuevo cliente o un cliente cierre la conexión. fd_set *writefds: puntero al conjunto de descriptores de los que interesa saber si se puede escribir en ellos. Para este caso en concreto no se usa. fd_set *exceptfds: puntero al conjunto de descriptores de los que interesa saber si ha ocurrido alguna excepción. En este caso tampoco interesa.ç struct timeval *timeout: especifica el intervalo de tiempo que select() va a estar esperando para que algún descriptor este «preparado». Una llamada a select() mantendrá el programa bloqueado hasta que un descriptor esté «preparado», se reciba una señal de interrupción o expire el timeout. Cuando la función retorna, cambia los contenidos de los conjuntos de descriptores, para indicar cuales de estos descriptores están «preparados», por este motivo es importante inicializar todos los conjuntos antes de volver a llamar a select(). Para operar con los conjuntos se dispone de una serie de macros: FD_ZERO(fd_set*): vacía el conjunto al que apunta el puntero. FD_SET(int, fd_set*): introduce el descriptor que se le pasa como parámetro uno, en el conjunto que se le pasa como parámetro dos. FD_ISSET(int, fd_set*): indica si el descriptor que se le pasa como parámetro uno, esta «preparado». Con esta macro se debe de ir preguntando a select() por cada uno de los descriptores que contiene. FD_CLEAR(int, fd_set*): elimina el descriptor que se le pasa como parámetro uno, del conjunto que se le pasa como parámetro dos. La función select() es fundamental en la realización del archivo tGatewayServer.cpp, ya que permite alternar entre el tratamiento de mensajes MQTT-SN y MQTT, mediante el uso de un conjunto de lectura de descriptores de archivo (readfds), donde, como ya se ha dicho, se introducen tanto los descriptores de socket, como el descriptor del módulo XBee.

5.4. ETAPA 4: PASARELA TRANSPARENTE

115

Lo que resta de apartado está dedicado a explicar en profundidad el código de la función principal o main, de este archivo. Para ello se han realizado una serie de pseudocódigos que esquematizan el código y permiten aclarar su propósito. Pseudocódigos En el Pseudocódigo 5.4, puede verse la estructura del código de esta función, la cual está formada por un bucle infinito, en cuyo interior se realiza una llamada a la función select(). Pseudocódigo 5.4 Esquema de todo el código de la función principal. function MAIN . p802: puntero a estructura packet_received_t maxf d ← −1 . pSplited: puntero a estructura packet_splited_t numCon ← 0 . rfds: conjunto de descriptores xbeef d ← XBEE _ INIT maxf d ← MAX(xbeef d, maxf d) while 1 do –Code to prepare select() function SELECT(maxf d + 1, rf ds, 0, 0, N U LL) . Llamada a select() if FD _ ISSET(xbeef d, rf ds) then . Si se activa XBee... XBEE _ GET PACKET(p802) XBEE _ PARSE PACKET(pSplited, p802) –Obtain message type from the packet if msgtype == connect then –Code for treat this situation else –Code for treat this situation end if –After that, we know if client requires a server or a translation if messagerequiresserver then –Code to serve the request else –Code to translate messages end if end if for i /∗ definitions & declarations ∗/ #define SUCCESS #define MAX _PACKE T_LENG TH

1 66

// message types #define M Q T T S N _ P R O T O C O L _ V E R S I O N #define M Q TT S N _T Y P E_ C O NN E C T #define M Q TT S N _T Y P E_ C O NN A C K #define M Q T T S N _ T Y P E _ R E G I S T E R #define M QTT SN _T YP E_ RE GA CK #define M Q TT S N _T Y P E_ P U BL I S H #define M QTT SN _T YP E_ PU BA CK #define M Q TT S N _T Y P E_ P U BC O M P #define M QTT SN _T YP E_ PU BR EC #define M QTT SN _T YP E_ PU BR EL #define M Q T T S N _ T Y P E _ S U B S C R I B E #define M QTT SN _T YP E_ SU BA CK #define M Q T T S N _ T Y P E _ U N S U B S C R I B E #define M Q T T S N _ T Y P E _ U N S U B A C K #define M Q TT S N _T Y P E_ P I NG R E Q #define M Q T T S N _ T Y P E _ P I N G R E S P #define M Q T T S N _ T Y P E _ D I S C O N N E C T

(0 x01 ) (0 x04 ) (0 x05 ) (0 x2E ) (0 x0B ) (0 x0C ) (0 x0D ) (0 x0E ) (0 x0F ) (0 x10 ) (0 x12 ) (0 x13 ) (0 x14 ) (0 x15 ) (0 x16 ) (0 x17 ) (0 x18 )

5.5. ETAPA 5: LIBRERÍA MQTT-SN Y EL SOFTWARE DE TRADUCCIÓN

30 31 32 33 34 35 36 37 38

40 41 42 43

45 46

48 49 50 51 52 53 54 55 56

58 59 60 61 62 63 64

66 67 68 69 70

72 73 74 75

// flags #define MQTTSN_FLAG_DUP #define MQTTSN_FLAG_QoS0 #define MQTTSN_FLAG_QoS1 #define MQTTSN_FLAG_QoS2 #define MQT TSN_FL AG_QoS m1 #define MQ TT SN _F LA G_ RE TA IN #define MQTTSN_FLAG_WILL #define M Q T T S N _ F L A G _ C L E A N _ S E S S I O N

127

(0 x80 ) (0 x00 ) (0 x20 ) (0 x40 ) (0 x60 ) (0 x10 ) (0 x08 ) (0 x04 )

// topics types #define M Q T T S N _ T O P I C _ T Y P E _ N O R M A L (0 x00 ) #define M Q T T S N _ T O P I C _ T Y P E _ P R E D E F I N E D (0 x01 ) #define M Q T T S N _ T O P I C _ T Y P E _ S H O R T (0 x02 ) // number of topics per client #define MAX_TOPICS

10

/∗ Recommended values for timers and counters . ∗ All timers are in seconds . ∗/ #define T_ADV 960 #define N_ADV 3 #define T_SEARCH_GW 5 #define T_GW_INFO 5 #define T_WAIT 360 #define T_RETRY 15 #define N_RETRY 5 /∗ Return codes ∗/ enum return_codes { ACCEPTED = (0 x00 ) , R E JE C T ED _ C ON G E ST I O N = (0 x01 ) , R E J E C T E D _ I N V A L I D _ T O P I C _ I D = (0 x02 ) , R E J E C T E D _ N O T _ S U P P O R T E D = (0 x03 ) }; /∗ struct to store the relationship beetwen topic name and topic id ∗/ struct topic { const char ∗ name ; uint16_t id ; }; /∗ class ∗/ class WaspMqttSN { /∗ All private variables here

128

∗ ( variables are private by default ) ∗/

76

78 79

81 82 83

private : /∗ Prototype of private functions here ∗/ public : WaspMqttSN (); ~ WaspMqttSN (){}; /∗ Prototipe of public functions here ∗/

85

87

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

};

90

/∗ Class object ∗/ extern WaspMqttSN mqttSN ;

92

#endif

89

Listado 5.16: Código de la primera versión del archivo WaspMqttSN.h

mqttsnSF.h Como se mencionó en la Sección 5.4.1, este archivo contiene una librería reducida de MQTT-SN, para que la pasarela pueda disponer de la información referente al formato de los mensajes de este protocolo, y utilizarla para realizar la conversión de MQTT-SN/MQTT y viceversa. La creación de este archivo se fundamenta en que no es posible incluir el archivo de cabecera WaspMqttSN.h, como parte del código de la pasarela transparente y utilizarlo para la traducción de protocolos, debido a que utiliza la API de Libelium para dispositivos Waspmote, que no está disponible para la pasarela Meshlium. Con lo cual, este archivo contendrá todas las declaraciones de constantes, variables y estructuras de WaspMqttSN.h, más los prototipos de las funciones necesarias para la implementación del software de la pasarela transparente, explicado en la Sección 5.4.1.

5.5.3

Implementación

En esta última fase de la etapa, se pretende desarrollar por completo la librería MQTT-SN, a partir de la implementación de todos los mensajes, características y procedimientos del protocolo. A su vez, también se trata de implementar las funciones de traducción del software de la pasarela transparente. Todo esto se consigue llevando a cabo la implementación de una serie de escenarios de actuación, pero esta vez no del protocolo MQTT-SN, sino de toda la infraestructura. De forma que en cada escenario: Se desarrolla código para una serie de mensajes MQTT-SN.

5.5. ETAPA 5: LIBRERÍA MQTT-SN Y EL SOFTWARE DE TRADUCCIÓN

129

Se escribe el código que necesita la pasarela para tratar estos mensajes. Cabe recordar que el código de la pasarela está prácticamente implementado, solo queda por codificar ciertos aspectos referentes al tratamiento de los mensajes MQTT-SN (una vez «parseado» el mensaje completo enviado por el sensor) y realizar las funciones de traducción. Se desarrolla código para traducir los mensajes que conlleva el escenario, a MQTT. Se desarrolla código para traducir las respuestas que proporciona Mosquitto y enviarlas a los sensores. Es decir, se implementa la traducción de MQTT a MQTT-SN. Para la implementación de cada mensaje MQTT-SN, se ha consultado la parte 2 de su especificación, en concreto los apartados que tratan cada mensaje de forma individual. Durante los esfuerzos de traducción, se han consultado las especificaciones de ambos protocolos (también la parte 2) y la librería MQTT previamente implementada (véase Sección 5.3.3). Los escenarios planteados son los siguientes: 1. CONNECT/DISCONNECT: Este escenario trata la situación en la que un cliente MQTT-SN se conecta a un broker MQTT, a través de una pasarela transparente. Los mensajes que intervienen en este caso son: CONNECT, DISCONNECT (envío) y CONNACK (recepción) (véase Figura 5.10). La implementación de este escenario es clave, ya que sin su implementación no es posible realizar el resto. MQTT-SN soporta otro tipo de conexión, llevada a cabo cuando un cliente quiere utilizar la característica last will and testament (véase Figura 5.11). Esta característica no la soporta la infraestructura que se desarrolla, y no será implementada. Sin embargo, es interesante para visualizar como aumenta considerablemente el número de mensajes si se utiliza esta característica. Si se han elegido estos protocolos para llevar a cabo la implementación de la infraestructura que se desarrolla en este TFG, es precisamente porque sobrecargan poco la red sobre la que actúan, luego esta característica no tiene sentido utilizarla. 2. REGISTER: Este escenario trata la situación en la que un cliente MQTT-SN se conecta a Mosquitto, registra un Topic Name en la pasarela y después se desconecta (véase Figura 5.12). Los mensajes que intervienen en este caso son: CONNECT, DISCONNECT (escenario 1), REGISTER (envío) y REGACK (recepción). Este es uno de los casos en que la pasarela no tiene que actuar como traductor, sino como servidor, activando la función manejador correspondiente (véase pseudocódigo 5.3). 3. PUBLISH:

130

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

Figura 5.10: Escenario de actuación del mensaje CONNECT. Fuente: elaboración propia.

Figura 5.11: Escenario de actuación del mensaje CONNECT con las características last will and testament. Fuente: elaboración propia.

5.5. ETAPA 5: LIBRERÍA MQTT-SN Y EL SOFTWARE DE TRADUCCIÓN

131

Figura 5.12: Escenario de actuación del mensaje REGISTER. Fuente: elaboración propia. Este escenario trata la situación en la que un cliente MQTT-SN se conecta a Mosquitto, publica información a un topic, y después se desconecta. Los mensajes que intervienen en este caso son: CONNECT, DISCONNECT (escenario 1), PUBLISH, PUBREL (envío), PUBREC y PUBCOMP (recepción). La publicación puede realizarse con cualquiera de los niveles de Q O S que soporta MQTT-SN (0, 1, 2 y -1). Dependiendo del nivel de Q O S, el flujo de mensajes que viajan a través de la infraestructura varía. La Figura 5.13 representa los distintos flujos de datos necesarios para las publicaciones nivel 0, 1. La Figura 5.14 representa el flujo de datos de una publicación de nivel 2, como puede verse conlleva un intercambio complejo, pero en este caso, al tratarse de la publicación de mensajes, se ha considerado conveniente implementarlo. La Figura 5.15 muestra el flujo de datos para una publicación de nivel -1. En la que el cliente se desentiendo por completo de la entrega de la publicación, quedando esta tarea para la pasarela. Para la ejecución de este escenario, es necesario que previamente se haya registrado el Topic Id en el que se publica (escenario 2). 4. PING: En este escenario se comprueba el funcionamiento del procedimiento de ping. Un

132

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

Figura 5.13: Escenario de actuación del mensaje PUBLISH con Q O S 0 y 1. Fuente: elaboración propia.

cliente se conecta a Mosquitto, envía un ping para mantener la conexión, recibe contestación y se desconecta. Los mensajes que intervienen son: CONNECT, DISCONNECT (escenario 1), PINGREQ (envío) y PINGRESP (recepción).

Estos escenarios se implementan utilizando la metodología de desarrollo TDD, cada iteración representa la implementación de un escenario, al que se le aplicará el algoritmo de TDD6 . Una vez se haya terminado este proceso, habrá concluido el desarrollo de la infraestructura de comunicación sobre la que trata este TFG, y se dispondrá, además, de una cobertura de pruebas completa para ella, que permitirá comprobar el correcto funcionamiento de cada una de sus partes. En los siguientes apartados se explican funciones que son comunes a todos los escenarios, y sin las cuales no es posible empezar a desarrollarlos. En los apartados sucesivos a estos, se explica el proceso de desarrollo seguido para cada uno de los escenarios descritos.

6

Para mayor simplicidad no se aplican todos los pasos de TDD como se explicó en el desarrollo de la librería MQTT (véase Sección 5.3.3), sino que se exponen los procedimientos realizados en cada una de las fases del algoritmo.

5.5. ETAPA 5: LIBRERÍA MQTT-SN Y EL SOFTWARE DE TRADUCCIÓN

133

Figura 5.14: Escenario de actuación del mensaje PUBLISH con Q O S 2. Fuente: elaboración propia. Funciones de envío/recepción de paquetes Como ya se ha mencionado, cada uno de los paquetes MQTT-SN que envía un dispositivo Waspmote, va encapsulado en un paquete 802.15.4, junto con la dirección MAC del dispositivo, para que la pasarela pueda identificarlo. Para realizar el envío/recepción de paquetes, en esta librería se han implementado dos funciones: send_packet() y recv_packet(). Su código es una adaptación de los ejemplos que proporciona la API de Libelium, y que se estudiaron en la Sección 5.1.2. Para que la máquina de estados de la función xbee_getPacket() (véase Sección 5.4.1) pueda reconocer la secuencia de inicio de mensaje, y también para distinguir ambas partes a la hora de realizar el «parseo» del mensaje (función xbee_parsePacket()), el mensaje que envía cada sensor contiene dos etiquetas antes del comienzo de cada parte (véase Cuadro 5.11). Etiqueta (#-MAC:)



Etiqueta (#-MQTT:)



Cuadro 5.11: Formato de los mensajes que envían los sensores de la infraestructura. Cada vez que un cliente MQTT-SN quiere enviar un mensaje, ejecutará su función de envío correspondiente (por ejemplo connect()), y esta, una vez genere el mensaje en cuestión, llamará a send_packet() para que le añada la dirección MAC (previamente obtenida por el

134

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

Figura 5.15: Escenario de actuación del mensaje PUBLISH con Q O S -1. Fuente: elaboración propia. dispositivo) y las etiquetas. Una vez formado el paquete completo, se introduce como payload del paquete 802.15.4 y se envía por la red. Para recibir un mensaje, el cliente llamará a recv_packet(), que se mantendrá a la espera de datos durante un tiempo determinado y cuando estos lleguen: Analizará las estructuras de la API en las que se ha guardado la información recibida (véase Sección 5.1.2). Procesará el mensaje en busca de errores (longitud errónea, que no se trate de un mensaje MQTT-SN, etc.). En ausencia de errores, pondrá el mensaje disponible a la función de la librería correspondiente. Obtención de la dirección MAC del dispositivo Para obtener la dirección MAC del dispositivo Waspmote, se ha añadido una función a la librería (obtain_sensorMac()), que se encarga de almacenar en dos arrays de carácteres, la parte alta de la dirección y la parte baja. Para realizar su código se ha adaptado el ejemplo wasp_pro_start_program_full_802_v1 de la API de Libelium. El código de está función puede verse en el Listado 5.17.

5.5. ETAPA 5: LIBRERÍA MQTT-SN Y EL SOFTWARE DE TRADUCCIÓN

1

3 4 5 6

/∗ macHigh and macLow are array variables in WaspMqttSN . h ∗/ void WaspMqttSN :: obtain_sensorMac () { xbee802 . ON (); delay (1000); xbee802 . flush (); // Get the XBee MAC address int counter = 0; while(( xbee802 . getOwnMac ()!=0) && ( counter >8; mq tt sn _s en d_ bu ff er [5] = ( keep_alive )&(0 xFF ); memcpy ( mq tts n_ se nd _b uf fe r +6 , client_id , clientidlen );

16 17 18 19 20 21 22 23 24

// send msg return WaspMqttSN :: send_packet ( packetlen , MQ T T SN _ T YP E _ CO N N E CT );

26 27 28

30 31 32 33 34

36 37

} /∗ FUNCTION TO SEND DISCCONECT MESSAGE ∗/ int WaspMqttSN :: disconnect () { // allocate packet memory mq tt sn _s en d_ bu ff er = ( uint8_t ∗) malloc (2∗ sizeof( uint8_t )); memset ( mqttsn_send_buffer , 0 , 2); // set header mq tt sn _s en d_ bu ff er [0] = (0 x02 );

138

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

38

mq tt sn _s en d_ bu ff er [1] = M Q T T S N _ T Y P E _ D I S C O N N E C T ;

40

// send message return WaspMqttSN :: send_packet (2 , M Q T T S N _ T Y P E _ D I S C O N N E C T );

41 42

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

} /∗ FUNCTION TO RECEIVE CONNACK MESSAGE ∗/ int WaspMqttSN :: recv_connack () { // receive message int ret = WaspMqttSN :: recv_packet ( CONNACK_SIZE , MQ T T SN _ T YP E _ CO N N AC K ); if( ret > 0) { // check return code if( mq tt sn _r ec v_ bu ff er [2] == ACCEPTED ) ret = 1; else ret = −1; } // free recv buffer free ( m qt ts n_ re cv _b uf fe r ); mq tt sn _r ec v_ bu ff er = NULL ; return ret ;

60 61

}

Listado 5.19: Código de las funciones del escenario CONNECT/DISCONNECT En el Listado 5.20 pueden verse las distintas partes de las funciones de traducción, tanto de mqttsn2mqtt() como de mqtt2mqttsn(). En cada caso de traducción se saca la información relevante del mensaje origen, para formar el mensaje destino, ya sea utilizando la librería MQTT implementada, o formando el mensaje in situ. 1 2 3 4 5 6 7 8 9 10 11 12

14 15

/∗ Code inside mqttsn2mqtt () function ∗ −− res variable is an integer ∗/ case M Q TT S N _T Y P E_ C O NN E C T : { uint16_t durationB1 = ( uint16_t ) mqttsn [4]; uint16_t durationB2 = ( uint16_t ) mqttsn [5]; broker −>clean_session = ( mqttsn [2] & M Q T T S N _ F L A G _ C L E A N _ S E S S I O N ) > >2; broker −>keep_alive = ( durationB1 < sockfd ); break;

16 17 18 19

}

21

/∗ Code inside mqtt2mqttsn () function ∗ −− buf is a character array ∗/ case MQT T_TYPE _CONNA CK : { buf = (char ∗) malloc ( CONNACK_SIZE ∗sizeof(char )); buf [0] = 0 x33 ; buf [1] = M Q TT S N _T Y P E_ C O NN A C K ; if( mqtt_recv_buffer [3] == 0 x00 ) buf [2] = ACCEPTED ; else buf [2] = R E JE C T ED _ C ON G E ST I O N ;

22 23 24 25 26 27 28 29 30 31

len = CONNACK_SIZE ; bufAllocated = 1; break;

33 34 35 36

139

}

Listado 5.20: Código de las funciones de conversión del escenario CONNECT/DISCONNECT

Escenario REGISTER Este escenario representa la segunda iteración del proceso de desarrollo, se le aplica el algoritmo de TDD: 1. Escribir la especificación del requisito (el test): El requisito que debe cumplirse en este escenario viene especificado por el test del Listado 5.21. 1 2 3

5 6 7 8 9 10 11 12

/∗ Test Register Scenary ∗/ void test_register () { int resCon , resCack , resReg , resRack ; // connect to mosquitto resCon = mqttSN . connect (); if ( resCon == 1) USB . println ( "−−−− connect send " ); // wait for ack resCack = mqttSN . recv_connack (); if ( resCack > 0) USB . println ( "−−−− connack received " );

140

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO // small delay delay (1000);

14 15

// register the topic name a / b resReg = mqttSN . re gis te r_ to pi cN am e ( " a / b " ); if( resReg == 1) USB . println ( "−−−− register send " ); // wait for ack resRack = mqttSN . recv_regack (); if( resRack > 0) USB . println ( "−−−− regack received " );

17 18 19 20 21 22 23 24

29

if( resCon && resCack && resReg && resRack ) USB . println ( " All Test Passed !! " ); else USB . println ( " Test Fail !! " );

31

delay (1000);

26 27 28

32

}

Listado 5.21: Test del escenario REGISTER 2. Implementar el código según dicho test: Para superar este test debe escribirse el siguiente código: • Función de la librería MQTT-SN para enviar el mensaje REGISTER a la pasarela. Y para recibir el REGACK. • Función que devuelva el Topic Id asignado a un Topic Name determinado. • Función manejador del mensaje REGISTER en la pasarela, que se ejecutará cuando el software de la pasarela detecte que el mensaje que ha llegado desde uno de los sensores, es un REGISTER. • Función para enviar el mensaje REGACK desde la pasarela al sensor correspondiente. Siguiendo la metodología, primero debe escribirse un código básico, que pase los test, apuntando las dudas que surjan y las posibles mejoras, para mejorar el código en la etapa de refactorización. 3. Refactorización: Tras las sucesivas etapas de refactorización (en las que se mejora una parte del código escrito y se ejecutan los test), se obtiene todo el código de este escenario. En el Listado 5.22 pueden verse tanto la función para enviar un mensaje de este tipo, como la encargada de recibir su acuse de recibo. La librería mantiene en todo momento un vector en el que almacena estructuras que guardan la relación Topic Id-Topic Name,

5.5. ETAPA 5: LIBRERÍA MQTT-SN Y EL SOFTWARE DE TRADUCCIÓN

141

el número máximo de topics almacenados también lo determina la librería. Antes de enviar un mensaje REGISTER, se comprueba que el número actual de topics almacenados, no sea superior al número máximo. De ser así, se crea la entrada en el vector de topics con el nuevo Topic Name, y se forma y envía el mensaje. Si el número de topics supera al máximo, se muestra error. Por otra parte, cuando se recibe un mensaje REGACK, se actúa igual que con todos los acuses de recibo, pero además si el código de retorno indica que se ha aceptado el registro, se actualiza la entrada correspondiente del vector de topics, añadiendo el Topic Id devuelto. 1 2 3 4 5 6 7 8

10 11 12 13 14

16 17 18

20 21 22 23 24 25 26 27 28

30 31 32 33 34 35 36

/∗ FUNCTION TO SEND REGISTER MESSAGE ∗/ int WaspMqttSN :: r eg ist er _t op ic Na me (const char ∗ topicName ) { int ret = 0; if( topic_count < ( MAX_TOPICS −1)) { // variables uint16_t topicnamelen = strlen ( topicName ); uint16_t packetlen = topicnamelen +6; // allocate packet memory and increase msg id count mq tt sn _s en d_ bu ff er = ( uint8_t ∗) malloc ( packetlen ∗sizeof( uint8_t )); memset ( mqttsn_send_buffer , 0 , packetlen ); msg_id ++; // store topic name topic_table [ topic_count ]. name = topicName ; topic_table [ topic_count ]. id = 0; // header mq tt sn _s en d_ bu ff er [0] = packetlen ; mq tt sn _s en d_ bu ff er [1] = M Q T T S N _ T Y P E _ R E G I S T E R ; // variable−part mq tt sn _s en d_ bu ff er [2] = 0 x00 ; mq tt sn _s en d_ bu ff er [3] = 0 x00 ; mq tt sn _s en d_ bu ff er [4] = ( msg_id ) > >8; mq tt sn _s en d_ bu ff er [5] = ( msg_id )&(0 xFF ); memcpy ( mq tts n_ se nd _b uf fe r +6 , topicName , topicnamelen ); // send message ret = WaspMqttSN :: send_packet ( packetlen , M Q T T S N _ T Y P E _ R E G I S T E R ); } else { fprintf ( stderr , " Error , no free space to store more topics .\ n " );

142

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO ret = −2;

37

} return ret ;

38 39 40

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67

} /∗ FUNCTION TO RECEIVE REGACK MESSAGE ∗/ int WaspMqttSN :: recv_regack () { // receive message int ret = WaspMqttSN :: recv_packet ( REGACK_SIZE , MQ TT SN _T YP E_ RE GA CK ); if( ret > 0) { // check msg_id if( ( msg_id > >8 != m qt ts n_r ec v_ bu ff er [4]) || (( msg_id &(0 xFF )) != mq tt sn_ re cv _b uf fe r [5]) ) { if( debug ) USB . println ( " recv_regack (): Wrong message id . " ); ret = −1; } // check return code else if( mq tt sn _r ec v_ bu ff er [6] == R E J E C T E D _ I N V A L I D _ T O P I C _ I D ) { USB . println ( " Error , rejected invalid topic id .\ n " ); ret = −2; } // update topic_table else if( mq tt sn _r ec v_ bu ff er [6] == ACCEPTED ) { uint16_t idMSB = ( uint16_t ) m qt ts n_ re cv _b uf fe r [2]; uint16_t idLSB = ( uint16_t ) m qt ts n_ re cv _b uf fe r [3]; topic_table [ topic_count ]. id = ( idMSB < >8; topic_id &(0 xFF ); msg_idMSB ; msg_idLSB ; return_code ;

// send regack using mac send_byMac ( mac , buf );

45 46 47

= = = = = = =

}

Listado 5.23: Código de las funciones de la pasarela del escenario REGISTER

Escenario PUBLISH Este escenario representa la tercera iteración del proceso de desarrollo, se le aplica el algoritmo de TDD: 1. Escribir la especificación del requisito (el test): El requisito que debe cumplirse en este escenario viene especificado por el test del Listado 5.24. En la descripción del escenario proporcionada en esta sección, se introdujo que se implementarían las publicaciones para cualquier nivel de Q O S, y así ha sido, pero por brevedad tan solo se van a exponer dos, para los niveles 1 y -1. Ya que se consideran los más representativos, el nivel 0 es igual que el 1, pero sin esperar acuse de recibo y el nivel 2 es igual que el 1, pero con un intercambio más de confirmaciones 1 2 3 4

6 7 8

/∗ Test Publish Scenary ∗/ uint8_t dup = 0; uint8_t retain = 0; int topicId = 1; // pre−defined topic id void test_publish () { int ret = −1, resCon , resCack , resPub , resPack ; uint8_t qos = 1;

17

// connect to mosquitto resCon = mqttSN . connect (); if ( resCon == 1) USB . println ( "−−−− connect send " ); // wait for ack resCack = mqttSN . recv_connack (); if ( resCack == 1) USB . println ( "−−−− connack received " );

19

// small delay

10 11 12 13 14 15 16

5.5. ETAPA 5: LIBRERÍA MQTT-SN Y EL SOFTWARE DE TRADUCCIÓN

145

20

delay (1000);

22

// publish to a pre−defined topic resPub = mqttSN . publish ( topicId , MQTTSN_TOPIC_TYPE_PREDEFINED , " Hello World from Waspmote " , qos , dup , retain ); if( resPub == 1) USB . println ( "−−−− publish send " ); // wait for ack if( qos == 1) { resPack = mqttSN . recv_puback (); if( resPack == 1) USB . println ( "−−−− puback received " ); }

23 24 25 26 27 28 29 30 31 32 33

// check results if ( resCon && resCack && resPub ) ret = 1;

35 36 37

42

if( ret == 1) USB . println ( " All Test Passed !! " ); else USB . println ( " Test Fail !! " );

44

delay (1000);

39 40 41

45

}

47

void test_publish_m1 () { int ret = −1, resPub ; uint8_t qos = −1;

48 49

51 52 53 54 55 56

58 59

61 62 63

65 66

// publish to a pre−defined topic resPub = mqttSN . publish ( topicId , MQTTSN_TOPIC_TYPE_PREDEFINED , " Hello World from Waspmote , QoS −1" , qos , dup , retain ); if( resPub == 1) USB . println ( "−−−− publish send " ); // small delay delay (1000); // check results if ( resPub ) ret = 1; if( ret == 1) USB . println ( " All Test Passed !! " );

146

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

68

else USB . println ( " Test Failed !! " );

70

delay (1000);

67

71

}

Listado 5.24: Test del escenario PUBLISH 2. Implementar el código según dicho test: Para superar este test debe escribirse el siguiente código: • Función de la librería MQTT-SN para enviar el mensaje PUBLISH y PUBREL. Y las funciones para recibir los mensajes PUBACK, PUBREC Y PUBCOMP. • Parte correspondiente a la traducción MQTT-SN → MQTT de la función mqttsn2mqtt() de la pasarela transparente. • Parte correspondiente a la traducción MQTT → MQTT-SN de la pasarela transparente (función mqtt2mqttsn()), para traducir los mensajes de respuesta que envíe Mosquitto. Siguiendo la metodología, primero debe escribirse un código básico, que pase los test, apuntando las dudas que surjan y las posibles mejoras, para mejorar el código en la etapa de refactorización. 3. Refactorización: Tras las sucesivas etapas de refactorización (en las que se mejora una parte del código escrito y se ejecutan los test), se obtiene todo el código de este escenario. En el Listado 5.25 pueden verse la función de envío del mensaje PUBLISH y de recepción del mensaje PUBACK. De nuevo se omiten los códigos de las funciones PUBREL, PUBREC y PUBCOMP, por ser muy similares a las expuestas en este listado. Como puede observarse, la función implementada sirve para enviar cualquier tipo de publicación que soporta el protocolo. 1 2 3 4 5 6 7

9 10 11 12 13

/∗ FUNCTION TO SEND PUBLISH MESSAGE ∗/ int WaspMqttSN :: publish ( uint16_t topicId , uint8_t topicType , const char ∗ msg , uint8_t qos , uint8_t dup , uint8_t retain ) { // variables uint16_t msglen = strlen ( msg ); uint16_t packetlen = 7+ msglen ; // allocate packet mem mq tt sn _s en d_ bu ff er = ( uint8_t ∗) malloc ( packetlen ∗sizeof( uint8_t )); memset ( mqttsn_send_buffer , 0 , packetlen ); msg_id ++;

5.5. ETAPA 5: LIBRERÍA MQTT-SN Y EL SOFTWARE DE TRADUCCIÓN

// set flags uint8_t flags = topicType ; if( dup ) flags |= MQTTSN_FLAG_DUP ; if( retain ) flags |= M QT TSN _F LA G_ RE TA IN ; if(! qos ) flags |= MQTTSN_FLAG_QoS0 ; else if( qos ==1) flags |= MQTTSN_FLAG_QoS1 ; else if( qos ==2) flags |= MQTTSN_FLAG_QoS2 ; else flags |= MQTTS N_FLA G_QoSm 1 ;

15 16 17 18 19 20 21 22 23 24 25 26 27 28

// set header mq tt sn _s en d_ bu ff er [0] = packetlen ; mq tt sn _s en d_ bu ff er [1] = M Q T TS N _ T YP E _ PU B L IS H ; // set variable−part mq tt sn _s en d_ bu ff er [2] = flags ; mq tt sn _s en d_ bu ff er [3] = ( topicId ) > >8; mq tt sn _s en d_ bu ff er [4] = ( topicId )&(0 xFF ); mq tt sn _s en d_ bu ff er [5] = ( msg_id ) > >8; mq tt sn _s en d_ bu ff er [6] = ( msg_id )&(0 xFF ); memcpy ( mq tts n_ se nd _b uf fe r +7 , msg , msglen );

30 31 32 33 34 35 36 37 38 39

// send message return WaspMqttSN :: send_packet ( packetlen , M QT T S N _T Y P E_ P U BL I S H );

41 42 43 44

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60

} /∗ FUNCTION TO RECEIVE PUBACK MESSAGE ∗/ int WaspMqttSN :: recv_puback () { // receive packet int ret = WaspMqttSN :: recv_packet ( PUBACK_SIZE , MQ TT SN _T YP E_ PU BA CK ); if( ret > 0) { // check msg id if( ( msg_id > >8 != m qt tsn _r ec v_ bu ff er [4]) || (( msg_id &(0 xFF )) != mq tt sn _r ecv _b uf fe r [5]) ) { if( debug ) USB . println ( " recv_puback (): Wrong message id " ); ret = −1; } else { // check return code

147

148

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO if( mq tt sn _r ec v_ bu ff er [6] == ACCEPTED ) if( debug ) USB . printf ( " Puback received " ); ret = 1;

61 62 63 64

}

65 66

}

68

70

// free allocated mem free ( m qt ts n_ re cv _b uf fe r ); mq tt sn _r ec v_ bu ff er = NULL ;

72

return ret ;

69

73

}

Listado 5.25: Código de las funciones del escenario PUBLISH En el Listado 5.26 pueden verse las dos partes en la que se realiza la traducción entre protocolos. En este código toma especial interés la implementación del nivel de Q O S -1, realizado en la función mqttsn2mqtt(). En este caso el cliente MQTT-SN se despreocupa por completo de la calidad de la publicación y la pasarela debe gestionar por completo la conexión con Mosquitto. La primera parte de la traducción se encarga de: (i) obtener el valor de los campos qos, dup y retain, (ii) de obtener el contenido del mensaje a publicar y (iii) obtener el topic name en el que se publicará. La segunda parte de la traducción consiste en evaluar la Q O S requerida y actuar consecuentemente. Otro de los procedimientos importantes de esta traducción, es la llamada a la función process_topicIDType(), que se encarga de devolver una cadena de caracteres que representa el topic name al que hay que enviar la publicación. El proceso interno de esta función se encarga de obtener el Topic Id contenido en el mensaje MQTT-SN, y tras analizarlo, consultar el mapa de topics del cliente, para así obtener el correspondiente Topic Name. Por su parte, las funciones de traducción MQTT → MQTT-SN, se encargan de formar los correspondientes acuses de recibo y enviarlos al cliente utilizando su MAC. 1 2 3 4 5 6 7 8 9

/∗ Code inside mqttsn2mqtt () function ∗ −− res variable is an integer ∗/ case M Q TT S N _T Y P E_ P U BL I S H : { // variables offset = mqttsn ; uint8_t qos = mqttsn [2]&(0 x60 ); uint8_t dup = ( mqttsn [2]&( MQTTSN_FLAG_DUP )) > >8; uint8_t retain = ( mqttsn [2]&( MQ TT SN _F LA G_ RE TA IN )) > >4;

5.5. ETAPA 5: LIBRERÍA MQTT-SN Y EL SOFTWARE DE TRADUCCIÓN char ∗ topicName ;

10

// obtain the msg data int msglen = mqttsn [0] − 7; char ∗ msg = (char ∗) malloc (( msglen +1)∗ sizeof(char )); memset ( msg , 0 , msglen ); memcpy ( msg , offset +7 , msglen ); msg [ msglen ] = ’ \0 ’;

12 13 14 15 16 17

// obtain topic name topicName = p r o ce s s _t o p ic I d Ty p e ( mqttsn , mac , msgtype );

19 20

if( qos == MQTTS N_FLAG _QoSm 1 ) { qos = 0; // init mqtt connection res = m qtt_s end_co nnect ( broker ); res = m qtt_r ecv_co nnack ( broker ); // send publish res = m qtt_s end_pu blish ( broker , topicName , msg , qos , dup , retain ); // disconnect and close res = m q t t _ s e n d _ d i s c o n n e c t ( broker ); close ( broker −>sockfd ); } else { if( qos == MQTTSN_FLAG_QoS0 ) qos = 0; else if( qos == MQTTSN_FLAG_QoS1 ) qos = 1; else if( qos == MQTTSN_FLAG_QoS2 ) qos = 2; // only send publish res = m qtt_s end_pu blish ( broker , topicName , msg , qos , dup , retain ); }

22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41

// free allocated mem free ( msg ); msg = NULL ; break;

43 44 45 46 47

}

49

54

case M QTT SN _T YP E_ PU BR EL : { // send pubrel res = mqtt_send_pubrel ( broker ); break; }

56

/∗ Code inside mqtt2mqttsn () function

50 51 52 53

149

150 57 58 59 60 61 62 63 64 65 66 67 68

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO ∗ −− buf is a character array ∗/ case MQTT_TYPE_PUBACK : { // set character buffer to make puback msg buf = (char ∗) malloc ( PUBACK_SIZE ∗sizeof(char )); buf [0] = 0 x37 ; buf [1] = MQ TT SN _T YP E_ PUB AC K ; buf [2] = 0 x1e ; buf [3] = 0 x1e ; buf [4] = mqtt_recv_buffer [2]; buf [5] = mqtt_recv_buffer [3]; buf [6] = ACCEPTED ; len = PUBACK_SIZE ; bufAllocated = 1; break;

70 71 72 73

}

75

case MQTT_TYPE_PUBREC : { // set character buffer to make pubrec msg buf = (char ∗) malloc ( PUBREC_SIZE ∗sizeof(char )); buf [0] = 0 x34 ; buf [1] = MQ TT SN _T YP E_ PUB RE C ; buf [2] = mqtt_recv_buffer [2]; buf [3] = mqtt_recv_buffer [3];

76 77 78 79 80 81 82

len = PUBREC_SIZE ; bufAllocated = 1; break;

84 85 86 87

}

89

case MQTT _TYPE _PUBCO MP : { // set character buffer to make pubcomp msg buf = (char ∗) malloc ( PUBCOMP_SIZE ∗sizeof(char )); buf [0] = 0 x34 ; buf [1] = M Q TT S N _T Y P E_ P U BC O M P ; buf [2] = mqtt_recv_buffer [2]; buf [3] = mqtt_recv_buffer [3];

90 91 92 93 94 95 96

len = PUBCOMP_SIZE ; bufAllocated = 1; break;

98 99 100 101

}

Listado 5.26: Código de las partes de traducción del escenario PUBLISH

5.5. ETAPA 5: LIBRERÍA MQTT-SN Y EL SOFTWARE DE TRADUCCIÓN

151

Escenario PING Este escenario representa la cuarta iteración del proceso de desarrollo, se le aplica el algoritmo de TDD: 1. Escribir la especificación del requisito (el test): El requisito que debe cumplirse en este escenario viene especificado por el test del Listado 5.27. 1 2

void test_ping () { int ret = −1, resCon , resCack , resPing , resPingAck ; // connect to mosquitto resCon = mqttSN . connect (); if ( resCon == 1) USB . println ( "−−−− connect send " ); // wait for ack resCack = mqttSN . recv_connack (); if ( resCack == 1) USB . println ( "−−−− connack received " ); // send ping resPing = mqttSN . pinreq (); if ( resPing == 1) USB . println ( "−−− ping send " ); // wait for pingresp resPingAck = mqttSN . recv_ping (); if ( resPingAck == 1) USB . println ( "−−− ping received " )

4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

// small delay delay (1000);

21 22

// check results if( resCon && resCack && resPing && resPingAck ) ret = 1;

24 25 26

31

if( ret == 1) USB . println ( " All Test Passed !! " ); else USB . println ( " Test Fail !! " );

33

delay (5000);

28 29 30

34

}

Listado 5.27: Test del escenario PING 2. Implementar el código según dicho test:

152

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO Para superar este test debe escribirse el siguiente código: • Función de la librería MQTT-SN para enviar el mensaje PINGREQ. Y la función para recibir el mensaje PINGRESP. • Parte correspondiente a la traducción MQTT-SN → MQTT de la función mqttsn2mqtt() de la pasarela transparente. • Parte correspondiente a la traducción MQTT → MQTT-SN de la pasarela transparente (función mqtt2mqttsn()), para traducir el ping de respuesta que envíe Mosquitto. Siguiendo la metodología, primero debe escribirse un código básico, que pase los test, apuntando las dudas que surjan y las posibles mejoras, para mejorar el código en la etapa de refactorización.

3. Refactorización: Tras las sucesivas etapas de refactorización (en las que se mejora una parte del código escrito y se ejecutan los test), se obtiene todo el código de este escenario. En el Listado 5.28 pueden verse las funciones de envío del mensaje PINGREQ y de recepción de PINGRESP. 1 2 3 4 5 6 7 8

/∗ FUNCTION TO SEND PING MESSAGE ∗/ int WaspMqttSN :: pingreq () { // variables uint8_t packetlen = 2; // allocate packet memory mq tt sn _s en d_ bu ff er = ( uint8_t ∗) malloc ( packetlen ∗sizeof( uint8_t )); memset ( mqttsn_send_buffer , 0 , packetlen ); // header mq tt sn _s en d_ bu ff er [0] = packetlen ; mq tt sn _s en d_ bu ff er [1] = MQ T T SN _ T YP E _ PI N G RE Q ;

10 11 12

// send packet return WaspMqttSN :: send_packet ( packetlen , M Q TT S N _T Y P E_ P I NG R E Q );

14 15 16 17

19 20 21 22 23 24 25

} /∗ FUNCTION TO RECEIVE PINGRESP MESSAGE ∗/ int WaspMqttSN :: recv_ping () { // receive packet int ret = WaspMqttSN :: recv_packet ( PING_SIZE , M Q T T S N _ T Y P E _ P I N G R E S P ); if( ret > 0) { ret = 1; }

5.6. ETAPA 6: SUSCRIPTORES EXTERNOS

29

// free allocated mem free ( m qt ts n_ re cv _b uf fe r ); mq tt sn _r ec v_ bu ff er = NULL ;

31

return ret ;

27 28

32

153

}

Listado 5.28: Código de las funciones del escenario PING

En el Listado 5.29 pueden verse las dos partes en las que se realiza la traducción entre protocolos. 1 2 3 4 5 6 7

9 10 11 12 13 14 15

/∗ Code inside mqttsn2mqtt () function ∗ −− res variable is an integer ∗/ case M Q TT S N _T Y P E_ P I NG R E Q : { res = mqtt_send_ping ( broker ); break; } /∗ Code inside mqtt2mqttsn () function ∗ −− buf is a character array ∗/ case M QTT _T YP E_ PI NG RE SP : { buf = (char ∗) malloc ( PING_SIZE ∗sizeof(char )); buf [0] = 0 x32 ; buf [1] = M Q T T S N _ T Y P E _ P I N G R E S P ; len = PING_SIZE ; bufAllocated = 1; break;

17 18 19 20

}

Listado 5.29: Código de las partes de traducción del escenario PING

Una vez concluidas todas las iteraciones, quedan implementadas y testeadas, todas las funcionalidades de la librería MQTT-SN y del software de traducción. Además, a pesar de que la librería MQTT se desarrolló por separado y ya estaba completamente testeada, los escenarios planteados para esta etapa del desarrollo del proyecto, han demostrado su completa adhesión a la infraestructura. Comprobando el correcto funcionamiento de la misma. Con esta etapa se concluye el desarrollo de la librería MQTT-SN y de la pasarela transparente.

154

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO

5.6 Etapa 6: Suscriptores externos Una vez finalizadas las etapas 1 a 5, se dispone de una infraestructura de comunicación que permite a los dispositivos de una red de sensores de la empresa Libelium, publicar información de su entorno a un broker MQTT, situado en una red externa (a la red de sensores). El objetivo de esta etapa, es desarrollar un mecanismo que muestre un procedimiento mediante el cual, cualquier dispositivo situado en una red externa a la infraestructura, pueda suscribirse a los canales de comunicación en los que publican los sensores, y recibir la información cuando el broker la distribuya. Con lo que se conseguirá comprobar el correcto funcionamiento de la infraestructura desarrollada, en un escenario real. El escenario que se plantea, es la visualización de la posición geográfica de sensores colocados cerca de la Escuela Superior de Informática de Ciudad Real. Estos publicaran sus coordenadas siguiendo el procedimiento de publicación de eventos MQTT-SN, los cuales llegarán hasta el broker Mosquitto, a través de la infraestructura, y este los distribuirá a los suscriptores. En este caso tan solo se tiene un suscriptor, situado en un navegador web, que actualiza un mapa cuando recibe una publicación. Para que la solución sea multiplataforma se han utilizado tecnologías web, en concreto JavaScript, NodeJS y HTML. Se pretende conseguir que cualquier dispositivo, tanto fijo como móvil, pueda acceder a la información que publican los sensores, a través de un navegador web. Para ello se ha creado: Un archivo HTML (Civitas.html). La función de este archivo es hacer que el navegador cliente que ha realizado la petición, se suscriba a determinados topics MQTT, en los que los sensores publicarán información. Esta información serán coordenadas, que representarán la posición actual del sensor en cuestión. Cuando el navegador reciba publicaciones con esta información, colocará una etiqueta en un mapa, indicando la localización del sensor. Un servidor NodeJS que realiza tres acciones: 1. Se mantiene a la espera de peticiones HTTP (en cualquier dirección de red, en el puerto 3000), sirviendo en cada caso el archivo que requiera la petición (por defecto el archivo Civitas.html) o mostrando error si el archivo no se encuentra en el servidor. 2. Crea un cliente MQTT que se conecta a Mosquitto. Su función es suscribirse al topic que le indique el suscriptor externo (desde el navegador web). 3. Abre un socket y se mantiene a la espera de conexiones por parte del navegador cliente (en cualquier dirección y en el puerto 5000). Cuando recibe una conexión, se mantiene a la espera de una suscripción por parte del cliente, que enviará después a Mosquitto.

5.6. ETAPA 6: SUSCRIPTORES EXTERNOS

155

Figura 5.16: Mecanismo creado para la realización de los suscriptores externos. De esta forma, es el propio servidor NodeJS el que está suscrito a determinados topics de Mosquitto, y es él, el que distribuye las publicaciones cuando Mosquitto se las envía (véase Figura 5.16). Con este mecanismo se consigue demostrar que la infraestructura que se ha desarrollado realiza sus funciones de forma correcta, en un escenario real. Ya que representa un uso completo de todas sus partes: MQTT-SN, MQTT, pasarela transparente y Mosquitto. En la Figura 5.17 puede verse el resultado final obtenido tras la ejecución, para ello han sido necesarias las siguientes acciones: Establecimiento de la red de sensores Waspmote-Meshlium. Conexión de Meshlium a la red TCP/IP en la que se encuentra el ordenador de Civitas con Mosquitto configurado y en ejecución. Puesta en marcha del servidor NodeJS. Realizar la petición del archivo Civitas.html desde un navegador en una red externa. Elaborar un código para los sensores, utilizando la librería MQTT-SN implementada, para que publiquen sus coordenadas a un topic o canal de eventos. Poner en ejecución este código, lo que genera un intercambio de mensajes entre sensorpasarela-Mosquitto que demuestra:

156

CAPÍTULO 5. ARQUITECTURA Y DESARROLLO • El correcto funcionamiento de la librería MQTT-SN implementada. • El correcto funcionamiento del código de la pasarela transparente, tanto su procedimiento de servidor (a la hora de registrar topics, aunque es opcional en este caso) como de traductor. • El correcto funcionamiento de la librería MQTT implementada. Distribución de publicaciones desde Mosquitto a los suscriptores. Visualización de los resultados en el mapa del navegador.

Figura 5.17: Visualización de las coordenadas publicadas por los sensores. Para realizar el código necesario para manejar el protocolo MQTT tanto en el archivo HTML como en el servidor NodeJS, se ha utilizado la librería MQTT.js7 . Para el uso de mapas se ha utilizado la API de JavaScript de Google Maps8 .

7 8

https://github.com/adamvr/MQTT.js https://developers.google.com/maps/documentation/javascript/?hl=es

Capítulo 6

Resultados

E

este capítulo se van a exponer los resultados obtenidos tras finalizar el proceso de desarrollo de este TFG. Primero se resume de forma breve la infraestructura de comunicación que se ha desarrollado, pues es el resultado principal. Después se exponen cada una de sus partes, ya que todas ellas pueden ser usadas de forma independiente, con otros fines. Acto seguido, se realiza una breve descripción del repositorio de software en el que se haya todo el código desarrollado y la documentación generada. Se sigue con una estimación de los costes del proyecto y por último, se introduce otro de los resultados del proyecto, la publicación de un artículo en el marco de las Smart Cities. N

6.1 Infraestructura de comunicación El proceso de desarrollo llevado a cabo, y expuesto a lo largo del Capítulo 5, ha dado como resultado el cumplimiento de todos los objetivos que inicialmente se establecieron para este proyecto. Tras la finalización de todas las implementaciones, se dispone de una infraestructura de comunicación basada en la publicación/suscripción de eventos, para el I OT. Que permite poner a disponibilidad de los distintos consumidores, la información que publican los dispositivos de una red de sensores (véase Figura 6.1). Además, como se ha podido comprobar en la Sección 5.6, la infraestructura ha sido testeada bajo un escenario real, obteniendo resultados satisfactorios. Este hecho, junto con la cobertura de pruebas que se obtiene como parte del proceso del desarrollo de TDD, hace que se haya generado una infraestructura completamente funcional. Por otro lado, algunas de las partes que componen esta infraestructura pueden ser usadas de forma independiente fuera de ella, pudiéndose considerar de esta forma, como resultados adicionales del proyecto. Estas partes son: Librería MQTT: Esta librería se considera como otro de los resultados del proyecto, ya que puede ser utilizada de forma independiente a la infraestructura. Con ella puede crearse cualquier tipo de cliente MQTT, exceptuando el uso de la característica last will and testament. 157

158

CAPÍTULO 6. RESULTADOS

Figura 6.1: Arquitectura y componentes de la infraestructura. Fuente: elaboración propia. Puede verse su manual de usuario en el Anexo A. Librería MQTT-SN: Esta librería también se considera como otro resultado del proyecto, ya que también puede utilizarse de forma independiente a la infraestructura, aunque en este caso con más limitaciones, ya que tan solo está preparada para ejecutarse sobre dispositivos Waspmote de la empresa Libelium. Puede verse su manual de usuario en el Anexo B. Pasarela transparente: El software que forma la pasarela transparente también puede considerarse como una entidad independiente. En este caso, encargada de traducir paquetes MQTT-SN en MQTT, y viceversa. Este software puede ser portado a cualquier sistema de este tipo, sin la necesidad de realizar grandes cambios en él, tan solo habría que modificar el uso de una u otra librería para el envío/recepción de paquetes, en función de la que elija usarse. Clientes MQTT: Como se explica en el Anexo A, una de las partes de la librería MQTT, son dos clientes: publicador y suscriptor. Los cuales pueden ser usados de forma completamente independiente a la infraestructura desarrollada, para cualquier finalidad que implique la publicación/suscripción de eventos MQTT.

6.2. REPOSITORIO

159

El código de la infraestructura completa, así como de todas sus partes, esta disponible en: https://rober [email protected]/rober botto/tfg.git Bajo la licencia de uso GNU GPL.

6.2 Repositorio Todo el código realizado durante el desarrollo del proyecto (infraestructura, librerías, test, clientes, etc.), junto con los archivos para generar toda la documentación asociada, están disponibles en un repositorio público de bitbucket.org1 . Para descargar el repositorio completo, puede ejecutarse el comando: $ git clone https :// r o b e r _ b o t t o @ b i t b u c k e t . org / rober_botto / tfg . git

La organización de este repositorio es la siguiente: anteproyecto: contiene los archivos para generar el documento que representa el Anteproyecto previamente aprobado al desarrollo de este TFG. proyecto: contiene los archivos para generar la memoria del proyecto. code: contiene todo el código fuente de la infraestructura desarrollada. Se organiza como sigue: • gateway: contiene el código fuente de la pasarela transparente (dentro de src/ ) y un archivo Makefile para compilarlo. • mqtt: contiene el código fuente de la librería MQTT, independiente de la pasarela transparente. En src/ se encuentra la librería y los test unitarios, y en client/ los clientes MQTT implementados. También dispone de archivo Makefile para compilar. • mqtt-sn: contiene el código fuente de la librería MQTT-SN y de los test creados para sus pruebas. • server: contiene el código fuente del servidor NodeJS utilizado para soportar suscriptores externos multiplataforma. En el Cuadro 6.1 puede verse una comparación de las lineas de código implementadas para construir la infraestructura, organizadas según la parte a la que pertenecen.

6.3 Coste del proyecto En esta sección se exponen los costes que lleva asociados este TFG, para ello se presentan agrupados según su procedencia, ya sea hardware, software o mano de obra. 1

https://bitbucket.org/

160

CAPÍTULO 6. RESULTADOS Componente Lenguaje Lineas Librería MQTT-SN C/C++ 874 Pararela transparente C/C++ 1188 Librería MQTT C/C++ 935 Suscriptores externos JavaScript/HTML 130 Cuadro 6.1: Lineas de código implementadas por componentes de la infraestructura.

6.3.1

Coste hardware

Como se especificó en la Sección 4.3.1, las herramientas hardware utilizadas para este proyecto han sido: un ordenador de sobremesa, un ordenador portátil, una placa sensora (contenida en el Kit de Evaluación de Libelium) y una pasarela, ambos de la empresa Libelium. En el Cuadro 6.2 puede verse el desglose de los gastos que ha supuesto la adquisición de estos elementos. Elemento HP Envy HP ProBook 4510s Kit de Evaluación de Libelium (University Lab Kit) Pasarela Meshlium Total

Coste 1400e 600e 2500e 895e 5395e

Cuadro 6.2: Costes Hardware.

6.3.2

Coste software

Como puede observarse en la Sección 4.3.2, todo el software que se ha utilizado para desarrollar este proyecto, es software libre. Con lo cual, supone un coste cero en cuanto a cuestiones de licencias o adquisición de software privativo específico.

6.3.3

Coste de la mano de obra

Para calcular el coste que ha supuesto la mano de obra, se han dividido los esfuerzos realizados en dos partes. Por un lado, los esfuerzos de implementación, y por otro, los de documentación. Como se indica en la Sección 4.2, la implementación del proyecto comienza la segunda semana de Enero de 2014, y se alarga hasta la última semana de Junio. Lo que arroja un total de 22 semanas aproximadamente, durante las cuales se dedicó una media de 4 horas al día, debido al solapamiento en el tiempo del desarrollo del proyecto con las últimas asignaturas de la carrera. La documentación del proyecto ha tenido lugar desde la última semana de Junio de 2014 (fecha de fin de implementación), hasta el día 26 de Agosto de 2014 (tercera semana del mes). Arrojando un total de 9 semanas aproximadamente, durante las cuales se ha dedicado una media de 8 horas al día.

6.4. PUBLICACIÓN

161

En el Cuadro 6.3 se muestran los costes asociados a la mano de obra necesaria para la realización del proyecto, teniendo en cuenta que cada hora de trabajo se cobrase a 50e. En el Cuadro 6.4 se muestran todos los costes del proyecto. Jornada Media Completa

Semanas 22 9

Horas/semana 20 40 Total

Coste 22.000 e 18.000 e 40.000e

Cuadro 6.3: Costes de la mano de obra. Procedencia Hardware Software Mano de obra Total

Coste 5395e 0e 40.000e 45.395e

Cuadro 6.4: Coste total del proyecto

6.4 Publicación Uno de los ámbitos de este proyecto son las Smart Cities, en concreto las etapas de recolección y transmisión de información. Como muestra de ello, uno de los resultados obtenidos es la publicación del artículo Implementing a Holistic Approach for the Smart City en The 2014 IEEE/WIC/ACM International Conference on Intelligent Agent Technology, celebrado en Varsovia del 11 al 14 de Agosto de 2014. Este artículo propone soluciones concretas para poder llevar a cabo una fácil implementación e integración de nuevos dispositivos y servicios en la Smart City, en concreto propone abordar esta tarea mediante la realización de abstracciones entre los distintos estándares y protocolos que forman parte de una Smart City, a través del empleo de un middleware, para hacer posible el uso de estos servicios de forma independiente a las tecnologías subyacentes. La realización de este proyecto ha servido como base a la redacción de la sección 3.2 del mencionado artículo, en la que se trata la integración de esta infraestructura como parte de la capa ICT Infraestructure de Civitas.

Capítulo 7

Conclusiones y propuestas

E

objetivo general del proyecto, implementar una infraestructura basada en la publicación/suscripción de eventos para el I OT, ha sido llevado a cabo a partir del desarrollo de los distintos objetivos específicos identificados en el Capítulo 2. Cada uno de ellos, ha supuesto avanzar en el proceso de desarrollo, aportando resultados e implementaciones que después se han utilizado conjuntamente para formar la infraestructura. L

Este capítulo se divide en tres partes, la primera de ellas muestra las conclusiones obtenidas tras los esfuerzos de implementación realizados durante el trascurso del proyecto, organizadas según las distintas partes que se han desarrollado para cumplir con los objetivos específicos. La segunda parte expone posibles propuestas que pueden llevarse a cabo para mejorar y ampliar la infraestructura, enfocadas en su mayoría a añadir nuevas características a la infraestructura para hacerla más completa. Y por último, la tercera, muestra las conclusiones personales del autor, obtenidas tras la realización de esta memoria.

7.1 Conclusiones Como primera tarea en el proceso de desarrollo de este TFG, se realizó un despliegue mínimo de la plataforma sensora sobre la que posteriormente se implementaría la mayor parte del software. En este ámbito, la documentación que Libelium tiene disponible para sus productos, fue clave. A partir de una lectura detallada de [Lib13a], [Lib13b], [Lib14a], [Lib13d] y de algunas secciones de [Lib14c] se obtuvieron los conocimientos necesarios para desplegar dicha plataforma (véase Sección 5.1). Esta etapa fue complicada, debido a que el comportamiento que requiere la infraestructura, difiere del comportamiento que Libelium plantea para las redes desplegadas con sus productos, con lo cual no todo estaba documentado y se tomaron ciertas decisiones cuyos resultados no estaban, a priori, garantizados. Por otra parte, Libelium no realiza una actualización inmediata de sus documentos cuando salen nuevas versiones del software de sus productos, como nuevas versiones del software de Meshlium, y en ocasiones fue necesario consultar y añadir hilos en su foro de ayuda, con el fin de obtener esta información, hecho que retrasó el tiempo de realización de esta etapa. El siguiente paso en el proceso de desarrollo, trató la implementación de la librería 163

164

CAPÍTULO 7. CONCLUSIONES Y PROPUESTAS

MQTT, que posteriormente sería usada como parte del proceso de traducción de protocolos, y que además como ya se ha mencionado, constituye una librería independiente que puede ser usada para crear clientes MQTT (véase Anexo A). Tras finalizar esta fase de implementación, puede concluirse que: Mosquitto es un broker MQTT muy eficiente, capaz de soportar un gran número de clientes conectados sin apenas consumir recursos de la máquina. Además, su configuración es sencilla, permitiendo en pocos pasos: dotar a MQTT de comunicación segura entre máquinas, establecer una red de brokers para mayor escalabilidad, control de acceso a topics por cliente, etc. MQTT, por sus características y principios de diseño, cumple con los requisitos que requiere una infraestructura para el I OT. Tras la implementación de esta librería, se dispuso a crear la estructura principal del software de la pasarela transparente, realizando toda la lógica de servidor y preparándola para interpretar mensajes MQTT-SN de los sensores. Esta fase tuvo una duración larga en comparación con el resto de implementaciones, debido a los problemas surgidos durante el proceso de lectura de un paquete 802.15.4 entrante, que se solucionaron con la máquina de estados vista en la Sección 5.4.1. De este proceso se obtienen las siguientes conclusiones: Por el tipo de acciones que tiene que realizar, la pasarela debe implementar un servidor monoproceso, manteniéndose a la espera de peticiones y procesándolas en un periodo de tiempo corto. Dentro de la infraestructura, el código de la pasarela es la pieza más importante, ya que actúa de puente entre los dos tipos de redes. Este código debe de estar ejecutándose durante periodos largos de tiempo y tiene que ser capaz de gestionar las conexiones de los clientes sin colapsarse. Esto significa: • Cuando un cliente se conecta, debe de crear e inicializar las estructuras de datos necesarias para almacenar su información, sin que entre en conflicto con la del resto de clientes. • Cuando un cliente se desconecta, debe de limpiar toda su información, para que la pasarela no almacene basura que con el tiempo colapsaría el sistema. Debido al desarrollo y la continua actividad en la que se haya inmerso el paradigma del I OT, las características requeridas para una infraestructura de este tipo pueden variar con relativa rapidez. De forma que, es importante que el código de la pasarela transparente este debidamente modularizado, permitiendo la incorporación de nuevas características de forma sencilla, sin que sea necesaria una gran reestructuración. Con el modelo de comunicación propuesto por esta infraestructura, no es necesario que la pasarela almacene la información que recopilan los sensores (en bases de datos,

7.1. CONCLUSIONES

165

o archivos), aunque puede hacerlo si así se requiere. Esto es debido a que el centro de operaciones se encuentra en un servidor externo, en Mosquitto. Con este esquema, la carga de trabajo de la pasarela se disminuye, al no tener que mantener ni gestionar, bases de datos o archivos. Si se desea que la información que publiquen los sensores se almacene de forma persistente, además de distribuirse a los suscriptores, estos deberán programarse para que utilicen convenientemente MQTT-SN, y le indiquen a Mosquitto que dichas publicaciones deben de tener persistencia. Este modelo, es distinto al que proporciona Libelium, basado en el protocolo ZigBee y en el almacenamiento de la información en bases de datos. La información se presenta a los consumidores en forma de eventos, y la tendrán disponible instantes después de que sea generada. La única tarea que deben de llevar a cabo los consumidores de información, es suscribirse a los canales de comunicación en los que los eventos publican, la infraestructura se encargará de hacer llegar estas publicaciones a Mosquitto, y este de distribuirlas a los suscriptores. Mosquitto puede residir en cualquier máquina que tenga conexión con la pasarela, ya sea a través de la interfaz Ethernet, Wi-Fi o 3G/GPRS. Proporcionando de esta forma, flexibilidad a la infraestructura. Una vez satisfechos los objetivos anteriores, solo quedaba implementar la librería MQTTSN y completar el software de traducción de la pasarela. Que permitirían disponer de la infraestructura completamente operativa. En esta etapa es en la que se programó el dispositivo Waspmote (véase Anexo C), para hacer que la librería pasase todos los test establecidos. En cuanto a la creación de la librería MQTT-SN y el software de traducción, se concluye: MQTT-SN es un protocolo adecuado para las redes de sensores, en relación al tamaño de los paquetes que envía por la red. Minimiza al máximo cada paquete, el mensaje mínimo es de 2 bytes de longitud. Y permite disponer de la mayor parte del paquete para la carga útil del mismo, acortando los Topic Names con el proceso de registro, mantiene identificadores de mensaje de tan solo 2 bytes, etc. Por regla general, realiza las mismas funciones que MQTT pero con mensajes menos pesados Sin embargo, en algunos escenarios de actuación del protocolo, el intercambio de mensajes requerido entre pasarela y sensor, es excesivo: • El proceso de conexión utilizando la característica last will and testament se ha dividido en un intercambio de 6 mensajes. • Para que la pasarela mantenga clientes en diferentes estados (dormido, despierto, activo, perdido, etc) se requiere un flujo de mensajes demasiado grande.

166

CAPÍTULO 7. CONCLUSIONES Y PROPUESTAS Estas dos situaciones, en una red con varios clientes conectados, pueden llevar a una sobrecarga excesiva y a un mal funcionamiento, ya que pueden generar efectos no deseados, como alta latencia. Además, este hecho se agrava debido a la naturaleza de las redes de sensores, que por lo general, son de bajo ancho de banda y alta latencia. La publicación con nivel de Q O S -1, es la más adecuada de cara a la eficiencia de la red, pero no proporciona ninguna garantía de entrega. La librería se ha implementado para actuar sobre dispositivos Waspmote de Libelium, y sitúa MQTT-SN sobre 802.15.4, pero se ha programado de forma que adaptarlo a una tecnología distinta solo dependa de dos funciones, las que envían y reciben datos a través de la red. Modificando estas funciones, se adaptará la librería a cualquier escenario de red.

Una vez desarrollada la infraestructura, el último de los objetivos consistía en implementar un mecanismo para soportar suscriptores externos y comprobar su funcionamiento. Tras su realización, se concluye: Se ha comprobado que la infraestructura proporciona la información que publiquen los sensores, en tiempo real. Puede afirmarse que la infraestructura actúa como un middleware básico, que abstrae al suscriptor externo o aplicación, de las tecnologías involucradas en el proceso de transmisión de la información desde los sensores de la red. Esta infraestructura puede ser utilizada como subsistema dentro de un sistema mayor, que utilice los eventos una vez llegan a Mosquitto, con alguna finalidad en concreto.

7.2 Propuestas El ámbito de este proyecto es amplio, el I OT es un paradigma emergente con multitud de lineas de evolución y un gran número de tecnologías involucradas en él. Las Smart Cities están teniendo gran acogida, tanto en España como en Europa, la Unión Europea y los distintos gobiernos de las ciudades, están destinando fondos a su desarrollo y en algunas lugares como Santander, Malaga o Barcelona ya se han obtenido buenos resultados. Y por su parte, MQTT y MQTT-SN son dos protocolos cuyo auge es latente, actualmente se está trabajando continuamente en nuevas versiones, tanto de brokers como de librerías y clientes, habiendo implementaciones disponibles para una gran variedad de lenguajes de programación (C, JavaScript, Java, C++, Go, etc.) y plataformas, como Android. De esta forma, a pesar de que se han cumplido con los objetivos establecidos inicialmente, surgen una serie de posibles mejoras susceptibles de ser aplicadas a la infraestructura implementada, para hacerla más completa o adaptarla a nuevos requisitos. A continuación se expone una lista con ellas:

7.2. PROPUESTAS

167

1. Hay algunas características de los protocolos que no eran necesarias para los requisitos con que se pretendía dotar a la infraestructura. Sin embargo, pueden resultar útiles en futuros usos, estas son: • Características last will and testament, tanto de MQTT como de MQTT-SN. • Gestión por parte de la pasarela de los diferentes estados del cliente MQTT-SN. 2. Debido a la inexistencia de actuadores en la plataforma sobre la que se ha desplegado la infraestructura, esta carece de la funcionalidad que haría posible que la pasarela pudiese enviar publicaciones a uno de los sensores, es decir, de tener el flujo inverso de información, que las publicaciones llegasen desde publicadores externos, hacia los dispositivos de la plataforma y que se provocasen acciones en los mismos. Una posible mejora sería dotar a la infraestructura de esta funcionalidad, realizando: • Las funciones de envío y recepción de los mensajes SUBSCRIBE y UNSUBSCRIBE del protocolo MQTT-SN. • La traducción de estos mensajes a MQTT y su envío utilizando la librería MQTT implementada. • La traducción de los mensajes PUBLISH que llegasen desde Mosquitto. • La recepción de mensajes PUBLISH en la librería MQTT-SN. 3. Integrar la infraestructura en Civitas, como uno de los mecanismos que tiene a su disposición el framework, para recopilar información que se produce en la ciudad. 4. Añadir seguridad al tráfico de la infraestructura. Para ello es posible: • Utilizar las funciones de seguridad del estándar 802.15.4, para que se cifrasen todos los paquetes enviados por la red de sensores. • Configurar Mosquitto para que la interacción con la pasarela, se realice utilizando criptografía de clave asimétrica. • Ambos procedimientos. 5. En caso de necesitar una solución muy escalable, pueden configurarse varios servidores Mosquitto en red, estableciendo una jerarquía entre ellos y consiguiendo que se repartan las suscripciones, disminuyendo así la carga de distribución de eventos que cada nodo Mosquitto de la red tendría que soportar. 6. Añadir opciones de persistencia a la pasarela. Con el funcionamiento actual, si los clientes lo desean, pueden almacenar sus publicaciones de forma permanente en el broker Mosquitto. Sin embargo, la pasarela no almacena información alguna. Esta mejora serviría para el caso concreto en que se requiriese que la pasarela almacenase la información que recopilan los sensores, para proporcionársela a otras aplicaciones. Para llevarla a cabo tan solo habría que añadir al código de la pasarela, las funciones necesarias para, tras recibir y procesar un mensaje, almacenar su información en un

archivo o base de datos. Este trabajo sería sencillo de realizar ya que Libelium proporciona el código hace estas tareas, y tan solo habría que adaptarlo.

7.3 Conclusiones personales En lo que a opinión personal del autor se refiere, la realización de este TFG ha servido para afianzar y ampliar los conocimientos adquiridos a lo largo de la carrera de Ingeniería Informática, en especial aquellos relacionados con la especificación cursada, Ingeniería de Computadores. Desde un primer momento el autor se decantó por la elección de dicha rama, debido en su mayor parte a los conocimientos asociados a ella y a los profesores encargados de difundirlos. La realización de este TFG, que está directamente relacionado con dicha rama, no ha hecho sino fortalecer la elección y el camino tomados. Por otra parte, el autor considera que este proyecto ha sido muy útil para ampliar los conocimientos de que disponía en áreas importantes de la informática, como son los sistemas empotrados, los sistemas de comunicaciones, la programación de estos sistemas, las redes de computadores, las comunicaciones inalámbricas, etc. En cuanto a aspectos que tienen relación directa con la temática de este TFG, el autor considera igualmente fructífero el descubrimiento de paradigmas y tecnologías de actualidad y en pleno auge, como son el Internet de las Cosas y las Ciudades Inteligentes. Durante la fase de documentación y posterior desarrollo, se han leído y estudiado numerosos documentos científicos, proyectos de investigación, trabajos innovadores, etc. que han reforzado en gran medida los conocimientos asimilados sobre estos temas, llegando al punto de comprender perfectamente sobre que cimientos están construidos y que puede aportar su uso a la sociedad. Por último, el autor considera que uno de los pilares fundamentales de esta ciencia, son los protocolos de comunicación. Con lo cual, el haber desarrollado un proyecto basado en el estudio, comprensión y posterior programación y aplicación de algunos de ellos, ha sido una tarea muy provechosa de cara a su formación como ingeniero informático. Como añadido, el lenguaje de programación C, ha sido el que más ha gustado al autor a lo largo de la carrera. Su aportación a la informática es innegable, estando los mejores sistemas construidos sobre él y siendo la base de la mayoría de los lenguajes de programación utilizados en la actualidad. El hecho de utilizarlo en este proyecto, ha permitido aumentar el conocimiento y el dominio sobre este lenguaje, y esto es algo que de alguna forma gratifica al autor.

168

ANEXOS

169

Anexo A

Manual de usuario de la librería MQTT v3.1.0

Este anexo presenta un manual de usuario en el que se describe como utilizar la librería MQTT que ha sido implementada durante el desarrollo del proyecto. Esta librería proporciona las funcionalidades necesarias para permitir que un usuario desarrolle un cliente MQTT. Se explicará como debe de proceder y se pondrán ejemplos prácticos que ilustren las distintas situaciones posibles.

A.1 Conexión TCP Antes de establecer una sesión MQTT, el cliente debe establecer una conexión TCP con un broker MQTT. Este procedimiento se realiza a través de la función mqtt_init(), la cual recibe tres parámetros: Estructura del tipo broker_handle_t: utilizada para manejar la conexión con el broker, siempre debe mantenerse una estructura de este tipo a lo largo de la ejecución del programa cliente, el programador deberá declararla, asignarle memoria y pasarla como parámetro a esta función. El manejador gestiona las siguientes opciones de conexión: • Descriptor del socket: utilizado para almacenar el descriptor de archivo correspondiente a la conexión TCP abierta con el broker MQTT. • Identificador del cliente MQTT. • Nombre de usuario. • Contraseña. • Característica Will1 . • Sesión limpia. • Tiempo de espera. • Indicativo de sesión de depuración. La función mqtt_init() inicializa todas estas opciones con sus valores por defecto, pudiendo modificarse cualquiera de ellas antes de realizar la conexión MQTT. Bien uti1

Aunque esta característica no ha sido implementada, se mantiene esta opción para futuras mejoras de la librería.

171

lizando las funciones mqtt_set_client_id() y mqtt_set_userpass(), o accediendo a cada uno de los campos de la estructura. Host: indica la dirección de red de la máquina en la que reside el broker MQTT, y con la que se quiere establecer la conexión TCP subyacente. Port: indica el puerto de la máquina destino en el que está escuchando el broker MQTT, a la espera de conexiones entrantes. La función mqtt_init() retorna el valor asignado al descriptor de socket, para que el cliente pueda realizar comprobación de errores si así lo desea. Cuando la sesión MQTT haya finalizado y no sea necesario utilizar de nuevo el manejador de conexión del cliente, deberá utilizarse la función mqtt_destroy() para liberar la memoria previamente asignada al manejador. La función mqtt_destroy() recibe como único parámetro el manejador de conexión.

A.2 Conexión MQTT Una vez establecida la conexión TCP con el broker, el cliente deberá utilizarla para establecer sobre ella una sesión MQTT. Para gestionar el establecimiento y la finalización de esta sesión, el usuario tiene disponibles las siguientes funciones: mqtt_send_connect(): esta función utilizará las opciones de conexión que se hayan definido en el manejador, para formar un mensaje CONNECT y enviarlo al broker. mqtt_recv_connack(): como respuesta a la petición de conexión, el broker enviará al cliente un mensaje CONNACK, en el que indicará si se ha establecido la sesión MQTT de forma correcta. Esta función sirve para mantenerse a la espera de este mensaje y procesarlo. mqtt_send_disconnect(): esta función envía un mensaje DISCONNECT al broker MQTT para que este finalice la sesión. Una vez enviado se supone concluida la sesión, ya que el broker no envía mensaje de respuesta. Deberá destruirse el manejador de conexión del cliente.

A.3 Publicación MQTT La librería soporta los distintos niveles de Q O S de MQTT, para cada tipo de publicación se dispone de una función que envía/recibe los distintos tipos de mensajes involucrados. La función más importante es mqtt_send_publish() que envía el mensaje PUBLISH. Recibe los siguiente parámetros: broker: manejador de conexión. topic_name: canal de eventos en el que se va a publicar. 172

msg: mensaje que se va a publicar. qos: nivel de Q O S que se va a utilizar. dup: indica si el mensaje es un duplicado de un mensaje anterior, deberá utilizarse cuando se reenvíen mensajes. retain: sirve para indicar al broker si debe tratar la publicación con esta característica de MQTT. En el listado A.1 puede verse un ejemplo sencillo de como publicar con lo distintos niveles de Q O S que soporta MQTT, a un broker situado en la dirección de red localhost y a la espera en el puerto 1883. 1

#include " mqtt . h "

4

const char ∗ host = " localhost " ; const char ∗ port = " 1883 " ;

6

int main (int argc , char∗ argv []){

3

28

// allocate memory to broker handler broker_handle_t ∗ broker = malloc (sizeof( broker_handle_t )); // init tcp connection with broker mqtt_init ( broker , host , port ); // connect to broker mqtt _send _conne ct ( broker ); mqtt _recv _conna ck ( broker ); // publish to a topic , with QoS 0 mqtt _send _publi sh ( broker , " a / b " , " Hello World ! " , 0 , 0 , 0); // publish to a topic , with QoS 1 mqtt _send _publi sh ( broker , " a / b " , " Hello World ! " , 1 , 0 , 0); mqtt_recv_puback ( broker ); // publish to a topic , with QoS 2 mqtt _send _publi sh ( broker , " a / b " , " Hello World ! " , 2 , 0 , 0); mqtt_recv_pubrec ( broker ); mqtt_send_pubrel ( broker ); mqtt _recv _pubco mp ( broker ); // disconnect m q t t _ s e n d _ d i s c o n n e c t ( broker ); // destroy broker handler mqtt_destroy ( broker );

30

return 0;

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

32

}

Listado A.1: Cliente MQTT que publica utilizando distintos niveles de Q O S

173

A.4 Suscripción MQTT Si el cliente quiere añadir o quitar suscripciones a determinados topics, deberá utilizar las funciones mqtt_send_subscribe() y mqtt_send_unsubscribe(). Tienen los siguientes parámetros: broker: manejador de conexión. topic_name: canal de eventos al que se quiere añadir/quitar la suscripción. La función mqtt_send_suscribe() tiene además, el parámetro qos para indicar el nivel mínimo de Q O S para ese canal de eventos. En el listado A.2 puede verse un ejemplo sencillo de como suscribirse y posteriormente quitar la suscripción a un topic. 1

#include " mqtt . h "

4

const char ∗ host = " localhost " ; const char ∗ port = " 1883 " ;

6

int main (int argc , char∗ argv []){

3

24

// allocate memory to broker handler broker_handle_t ∗ broker = malloc (sizeof( broker_handle_t )); // init tcp connection with broker mqtt_init ( broker , host , port ); // connect to broker mqt t_send _conne ct ( broker ); mqt t_recv _conna ck ( broker ); // subscribe to a topic m qt t _ s en d _ su b s cr i b e ( broker , " a / b " , 1); mqtt_recv_suback ( broker ); // unsubscribe to a topic m q t t _ s e n d _ u n s u b s c r i b e ( broker , " a / b " ); mq tt _r ec v_ un su ba ck ( broker ); // disconnect m q t t _ s e n d _ d i s c o n n e c t ( broker ); // destroy broker handler mqtt_destroy ( broker );

26

return 0;

8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

28

}

Listado A.2: Cliente MQTT que se suscribe a un topic y después cancela esta suscripción. Para hacer que un cliente suscriptor se mantenga a la espera de publicaciones, habrá que utilizar la función mqtt_loop(), que mantiene la conexión utilizando pings y cuando recibe 174

una publicación, aísla el mensaje recibido. El código de cliente deberá elegir que acción realizar con dicho mensaje.

A.5 Valores de retorno Todas las funciones de envío/recepción de mensajes de la librería, retornan el valor 1 si el mensaje se ha enviado/recibido sin que hayan ocurrido errores. Si por el contrario, ha ocurrido algún error, retornan el valor -1 y muestran por la salida estándar de error un mensaje indicando el tipo de error.

A.6 Clientes Esta librería también contiene dos clientes MQTT, exec/mqtt_sub y exec/mqtt_pub, que pueden ser ejecutados para probar la librería. El uso de ambos programas viene determinado por los comandos: $ mqtt_sub [ options ] -t < topic > $ mqtt_pub [ options ] -t < topic > -m < message >

Donde las opciones pueden ser: -c: desactiva la opción clean-session, que viene activada por defecto. -d: activa el modo de depuración. -h : host en el que reside el broker MQTT al que hay que conectarse. Por defecto localhost. -p : puerto de red del host anterior, en el que está escuchando el broker. Por defecto 1883. -i : identidad que se asignará al cliente. -k : periodo de tiempo de vida para el cliente, en segundos. Por defecto 180. -q : Q O S requerida para las publicaciones del topic al que se suscribe el cliente. -u : nombre de usuario del cliente, en caso de que el broker tenga configurado control de acceso para conectarse. -P : contraseña para el anterior nombre de usuario.

175

Anexo B

Manual de usuario de la librería MQTT-SN v1.2

Este anexo presenta un manual de usuario en el que se describe como utilizar la librería MQTT-SN que ha sido implementada durante el desarrollo del proyecto. Esta librería proporciona las funcionalidades necesarias para permitir que un usuario desarrolle un cliente MQTT-SN. Se explicará como debe de proceder y se pondrán ejemplos prácticos que ilustren las distintas situaciones posibles.

B.1 Instalación Para poder usar una librería de usuario en Waspmote, deben de introducirse sus archivos fuente en un directorio situado dentro del directorio libraries del IDE de Waspmote. Por ejemplo, si el IDE está situado en el home del usuario bajo el directorio waspmote, la ruta en la que habría que introducir los archivos de la librería MQTT-SN sería: /waspmote/libraries/MQTTSN. Una vez que se han situado los archivos fuente en su directorio correspondiente, si quieren usarse para programar el dispositivo, se deberá incluir el archivo de cabecera correspondiente en el código. Esta acción puede hacerse manualmente o a través de la interfaz de usuario, pestaña Sketch → Import libraries, y seleccionarla. Realizado esto, ya pueden usarse todas las funcionalidades que ofrezca la librería.

B.2 Configuración inicial Antes de comenzar con el proceso de conexión MQTT-SN, el cliente debe de configurar algunos aspectos de la futura conexión. Para ello tiene disponibles las siguientes funciones, que deberán ser usadas dentro de la función setup() del Sketch: set_debug_on(): sirve para activar el modo depuración, que imprimirá información de todo el proceso posterior, por el puerto serie. set_gw_mac(): recibe por parámetro una dirección MAC, que deberá ser la de la pasarela a la que se quieren enviar los mensajes. Siempre es necesario llamar a esta función al menos una vez durante la ejecución del código del cliente. set_client_id(): recibe por parámetro la identidad que se quiere asignar al cliente. En 177

caso de no utilizarse esta función, se inicializará automáticamente a un valor por defecto. set_keep_alive(): recibe como parámetro un entero de 16 bits, que indicará el periodo de tiempo de vida del cliente. obtain_sensorMac(): consulta la dirección MAC 802.15.4 del dispositivo, y la almacena en dos vectores de caracteres, por un lado la parte alta y por otro la parte baja. Esta función también es necesario utilizarla al menos una vez en cada ejecución. En el listado B.1 puede verse un ejemplo de configuración, en la que se establece la dirección MAC, se modifica el identificador de cliente y se deja el modo de depuración apagado (por defecto). 1 2

4 5 6 7

const char ∗ gw_mac = " 0013 A200xxxxxxxx " ; const char ∗ client_id = " mqttsn −0001" ; void setup () { mqttSN . set_gw_mac ( gw_mac ); mqttSn . set_client_id ( client_id ); mqttSN . obtain_sensorMac (); xbee802 . ON ();

9 10

}

Listado B.1: Ejemplo de configuración de cliente. Como puede observarse se utiliza el objeto mqttSN para acceder a las funcionalidades de la librería.

B.3 Registro de topics MQTT-SN Para publicar información a un topic determinado, antes es necesario registrarlo en la pasarela, y obtener su identificador de topic correspondiente. El primer paso es conectarse ya sea a un broker MQTT-SN, o MQTT a través de una pasarela. Cuando se reciba el acuse de recibo indicando que la conexión se ha realizado con éxito, el cliente deberá comenzar el proceso de registro, utilizando la función register_topicName() e indicando el topic name que quiere registrar. Después se mantendrá a la espera de recibir la confirmación de que todo ha ido bien, de no ser así, deberá intentar de nuevo registrar el topic name cuando pase un periodo de tiempo Twait (constante T_WAIT de la librería). En el listado B.21 puede verse un ejemplo en el que un cliente registra el topic name 1

El resto de listados del Anexo, corresponden a código que iría situado en el interior de la funcón loop() del Sketch.

178

«a/b». Tras recibir el REGACK, el topic id queda´ra almacenado en la tabla de topics del dispositivo. 1 2 3 4

6 7 8

10 11 12 13

15 16 17

// CONNECT int resCon = mqttSN . connect (); if ( resCon == 1) USB . println ( "−−−− connect send " ); int resCack = mqttSN . recv_connack (); if ( resCack > 0) USB . println ( "−−−− connack received " ); // REGISTER int resReg = mqttSN . re gi st er_ to pi cN am e ( " a / b " ); if( resReg == 1) USB . println ( "−−−− register send " ); int resRack = mqttSN . recv_regack (); if( resRack > 0) USB . println ( "−−−− regack received " );

Listado B.2: Ejemplo de registro de topic name de un cliente.

B.4 Publicación MQTT-SN En MQTT-SN hay varias formas de publicar, una es realizando el registro de un topic name como en la sección anterior, y después publicar utilizando el topic id recibido. Otra es utilizando bien un pre-defined topic id, o bien un short topic name. Los cuales no necesitan de registro previo, en el caso de pre-defined topic id porque la pasarela ya almacena una estructura de datos con varios topic id a los que publicar, en el caso de short topic name, porque son topic names de tan solo 2 bytes, y pueden enviarse en el mensaje PUBLISH. En este caso la pasarela almacena 3 pre-defined topic id por defecto, que son: 0→«a/b», 1→«a/c» y 2→«a/d». En cualquier caso, la función utiliza se denomina publish() y recibe los siguientes parámetros: topicId: identificador de topic al que publicar. topicType: tipo de topic. msg: mensaje para publicar. qos: nivel de Q O S de la publicación. dup: indica si el mensaje es un duplicado. retain: indica si el mensaje debe tener persistencia en el broker. 179

El cliente puede publicar con cualquiera de las Q O S de MQTT-SN, el flujo de mensajes es idéntico al de MQTT, en el listado A.1 puede verse un ejemplo de publicación con Q O S nivel 1. 1 2 3

5 6 7 8

10 11 12

14 15 16 17 18 19

21 22 23 24 25

int qos = 1; int dup = 0; int retain = 0; // CONNECT int resCon = mqttSN . connect (); if ( resCon == 1) USB . println ( "−−−− connect send " ); int resCack = mqttSN . recv_connack (); if ( resCack == 1) USB . println ( "−−−− connack received " ); // PUBLISH int resPub = mqttSN . publish (1 , MQTTSN_TOPIC_TYPE_PREDEFINED , " Hello World from Waspmote " , qos , dup , retain ); if( resPub == 1) USB . println ( "−−−− publish send " ); if( qos == 1) { resPack = mqttSN . recv_puback (); if( resPack == 1) USB . println ( "−−−− puback received " ); }

Listado B.3: Ejemplo de publish con Q O S 1.

B.4.1

Publicación con Q O S -1

Este tipo de publicación es la única forma de publicar en la que MQTT-SN difiere de MQTT, en este caso no es necesario conexión previa con el broker, es la pasarela la que maneja todo el proceso. Puede verse un ejemplo en el listado B.4. 1 2 3

5 6 7 8

int qos = −1; int dup = 0; int reatin = 0; // PUBLISH int resPub = mqttSN . publish (1 , MQTTSN_TOPIC_TYPE_PREDEFINED , " Hello World from Waspmote , QoS −1" , qos , dup , retain );

180

9 10

if( resPub == 1) USB . println ( "−−−− publish send " );

Listado B.4: Ejemplo de publish con Q O S -1.

B.5 Valores de retorno Todas las funciones de envío/recepción de esta librería, retornan en valor 1 si el paquete se ha enviado/recibido correctamente por la red, y el valor -1, si ha ocurrido algún error en el envío/recepción, o si no se han recibido los datos esperados.

B.6 Clientes Como parte del desarrollo y testeo de la librería, se han realizado varios clientes, cada uno para probar un escenario determinado. Pueden consultarse en el repositorio del proyecto: https://bitbucket.org/rober botto/tfg

181

Anexo C

Manual sobre cómo programar Waspmote

Este anexo pretende ser una guía sobre los pasos que hay que realizar para programar de forma correcta los dispositivos Waspmote de Libelium. Desde la instalación del IDE a cargar y ejecutar código en la placa.

C.1 IDE de Waspmote: Descarga e instalación El IDE de Waspmote está disponible para su descarga en la página web de Libelium, en concreto aquí: http://www.libelium.com/development/waspmote/sdk applications Desde donde se deberá descargar la versión correspondiente al sistema operativo del usuario, en este caso y siguiendo la linea de todo el documento, se opta por tratar la instalación del IDE para sistemas operativos GNU/Linux. Para este tipo de sistemas existen dos versiones distintas del software, la de 32 bits y la de 64 bits, ambas portables en el aspecto de que no necesitan instalación de paquetes para ejecutarse. Sin embargo, para poder compilar y ejecutar código sobre los dispositivos de forma correcta, es necesaria la instalación de algunos paquetes extra: 1. La versión necesaria del entorno Java. En concreto la versión 6 del JRE de Java. Para ello debe utilizarse cualquier gestor de paquetes e instalar sun-java6-jre. 2. La versión necesaria del compilador avr-gcc, para ser capaz de programar el microcontrolador ATMEGA 1281 de Waspmote. El paquete a instalar es gcc-avr. 3. La versión necesaria de la librería lib-avc. Contenida en el paquete avr-libc. Realizadas estas acciones ya se dispone del entorno adecuado para ejecutar el IDE y poder utilizar todas sus funcionalidades. Para ello, deberá ejecutarse el archivo ejecutable llamado waspmote, contenido dentro del directorio raíz del conjunto de archivos y directorios descargados. 183

C.2 Cargar un nuevo programa en Waspmote Para cargar y ejecutar código en el dispositivo, hay una serie de pasos, tanto para la propia placa como para el IDE, que hay que realizar siempre: 1. Encender Waspmote, en la Figura C.1 mover el botón hacia la izquierda.

Figura C.1: Como encender Waspmote. Fuente: [Lib13d]. 2. Conectar Waspmote al ordenador personal utilizando el cable USB. Abrir el IDE y seleccionar la placa y el puerto apropiados, en el menú Tools (véanse Figuras C.2 y C.3). 3. Preparar el código para subir a Waspmote, en este caso la plantilla hello_world. 4. Guardar el Sketch (con el botón correspondiente). Comprobar el estado que indica el IDE para ver si se ha guardado (véase Figura C.4). 5. Compilar el código (con el botón correspondiente) para ver si contiene errores o avisos. Si todo está correcto, el IDE mostrará el estado Done Compiling. 6. Cargar el código en el dispositivo, para ello utilizar el botón Upload y esperar unos segundos hasta que el proceso termine. Si se muestra el estado Done uploading significa que no han ocurrido errores en el proceso (véanse Figuras C.5 y C.6).

184

Figura C.2: Seleccionar placa adecuada. Fuente: [Lib13d].

Figura C.3: Seleccionar puerto adecuado. Fuente: [Lib13d].

185

Figura C.4: Guardar un Sketch. Fuente: [Lib13d].

Figura C.5: Cargar un Sketch 1. Fuente: [Lib13d].

186

Figura C.6: Cargar un Sketch 2. Fuente: [Lib13d].

187

Anexo D

Instalación y configuración de CUnit

En este anexo se tratan aspectos relativos al proceso de instalación y configuración del framework de testing CUnit, utilizado para realizar los distintos escenarios de test para el protocolo MQTT. CUnit es un framework para escribir, gestionar y ejecutar test unitarios en C. Está construido como una librería estática que se vincula al código del usuario mediante el uso de directivas del preprocesador. Además de proporcionar una plataforma para escribir test, también incorpora un conjunto de interfaces de usuario, las cuales facilitan la interacción con el framework y permiten visualizar los resultados de distintas formas. La estructura que sigue este framework puede verse en la Figura D.1. Los test unitarios son empaquetados en suites, y estas suites se registran en el registro de test activo. Las suites pueden tener funciones de inicialización y destrucción, que serán llamadas automáticamente antes y después de ejecutar los test que contengan. Solo puede haber un registro activo a la vez. Un esquema de uso de CUnit puede ser el siguiente: 1. Escribir funciones para testear y la inicialización/destrucción de las suites, si es necesario. 2. Inicializar el registro de test’s: CU_initialize_registry(). 3. Añadir las suites al registro: CU_add_suite(). 4. Añadir test’s a las suites: CU_add_test(). 5. Ejecutar los test’s usando la interfaz apropiada: p.e. CU_console_run_tests(). 6. Limpiar el registro de test: CU_cleanup_registry()

D.0.1

Instalación

CUnit no está disponible en los repositorios de ninguna distribución, para instalar este software es necesario compilarlo desde los fuentes. Esta tarea no tiene un procedimiento unificado para llevarse a cabo, y depende de la máquina en la que se quiera instalar. Sin embargo, si que hay un procedimiento habitual que, por regla general, suele funcionar sin problemas. Consta de los siguientes pasos: 189

Figura D.1: Estructura del framework CUnit. 1. Descargarse todos los archivos necesarios desde la página web del proyecto [KS]. 2. Extraer los archivos y situarse en el interior del directorio que los contiene. 3. Ejecutar: # ./ configure # make # make install

4. Opcionalmente se pueden borrar los archivos generados durante este proceso, ejecutando: # make clean

Entre los comandos make y make install, se puede ejecutar make check, para pasar una serie de test que vienen incorporados con el software. Para situaciones especiales en las que no logre instalarse CUnit con este procedimiento, será necesario consultar el archivo INSTALL que viene incluido en la descarga.

D.0.2

Ejemplo de uso

Una vez instalado el framework, para utilizarlo tan solo es necesario incluir en nuestro código los archivos de cabecera que se necesiten. CUnit dispone de varios de estos archivos, incluyendo cada uno, una parte del framework. De esta forma no es necesario incluir toda la funcionalidad de CUnit si no se necesita. 190

En el Listado D.1 puede verse un ejemplo de uso de CUnit, el escenario de test está formado por un test que comprueba la existencia del carácter H en un array de caracteres. En el código puede verse el proceso mediante el cual se declara la suite, se inicializa el registro, se añade la suite al registro y se añade el test a la suite. Una vez hecho esto, CUnit ya puede ejecutar el test, en este caso se ha usado la interfaz básica.

3

#include " CUnit / Basic . h " #include " CUnit / CUnit . h " #include < stdlib .h >

5

char ∗ array ;

1 2

7 8 9 10 11 12 13 14

16 17 18 19 20 21 22 23

25 26 27 28 29 30 31 32

34 35 36

38 39 40

/∗ Init function of the Suite ∗ − Get memory for array ∗ − Store " Hello " in array ∗/ int i n i t _ s u i t e _ c o n t a i n s H (void) { array = (char ∗) malloc (5∗ sizeof(char )); memcpy ( array , " Hello " , 5); return 0; } /∗ Clean function of the Suite ∗ − Free mem ∗ − Free pointer ∗/ int c l e a n _ s u i t e _ c o n t a i n s H (void) { free ( array ); array = NULL ; return 0; } /∗ Test that search into array the existence ∗ of the character ’H ’ ∗/ void t e s t _ A R R A Y _ c o n t a i n s _ H (void) { /∗ strchr function returns NULL if the character H is not ∗ found on ∗ array and return a pointer to the matched ∗ character if H is found ∗/ CU_ASSERT_TRUE ( strchr ( array , ’H ’) != NULL ); } /∗ main function ∗/ int main () { CU_pSuite pSuite_containsH = NULL ; /∗ initialize the CUnit test registry ∗/ if ( C U _ i n i t i a l i z e _ r e g i s t r y () != CUE_SUCCESS ) return CU_get_error ();

191

/∗ add the suites to the registry ∗/ pSuite_containsH = CU_add_suite ( " ContainsH_Suite " , init_suite_containsH , c l e a n _ s u i t e _ c o n t a i n s H );

42 43 44 45

if ( pSuite_containsH == NULL ) { C U _c l e an u p _r e g is t r y (); return CU_get_error (); }

47 48 49 50

/∗ add the tests to the suites ∗/ if(( CU_add_test ( pSuite_containsH , " contains H " , t e s t _ A R R A Y _ c o n t a i n s _ H ) == NULL )) { C U _c l e an u p _r e g is t r y (); return CU_get_error (); }

52 53 54 55 56 57

/∗ Run all tests using the CUnit Basic interface ∗/ CU_ basic_ set_mo de ( CU_BRM_VERBOSE ); CU _b as ic _r un _t es ts ();

59 60 61

C U_ c l e an u p _r e g is t r y (); return CU_get_error ();

63 64 65

}

Listado D.1: Código de ejemplo de uso de CUnit Para compilar este código debe usarse la librería lcunit, por ejemplo, si el archivo fuente tuviese el nombre test.c, valdría el comando: $ gcc - Wall test . c -o test - lcunit

La salida tras ejecutar el test sería la siguiente: $ ./ test CUnit - A unit testing framework for C - Version 2.1 -2 http :// cunit . sourceforge . net /

Suite : ContainsH_Suite Test : contains H ... passed Run Summary :

Type suites tests asserts

Elapsed time =

Total 1 1 1

Ran Passed Failed Inactive 1 n/a 0 0 1 1 0 0 1 1 0 n/a

0.000 seconds

Donde puede verse que el test contains H, de la suite ContainsH_Suite, ha sido pasado con éxito. 192

Referencias [AIM10a]

Luigi Atzori, Antonio Iera, y Giacomo Morabito. The internet of things: A survey. Computer networks, 54(15):2787–2805, 2010.

[AIM10b]

Luigi Atzori, Antonio Iera, y Giacomo Morabito. The Internet of Things: A Survey. Comput. Netw., 54(15):2787–2805, Octubre 2010. url: http://dx. doi.org/10.1016/j.comnet.2010.05.010.

[ASSC02]

Ian F Akyildiz, Weilian Su, Yogesh Sankarasubramaniam, y Erdal Cayirci. Wireless sensor networks: a survey. Computer networks, 38(4):393–422, 2002.

[Bec00]

Kent Beck. Extreme programming explained: embrace change. AddisonWesley Professional, 2000.

[Bec03]

Kent Beck. Test-driven development: by example. Addison-Wesley Professional, 2003.

[BGS+ 08]

Michael Buettner, Ben Greenstein, Alanson P Sample, Joshua R Smith, David Wetherall, et al. Revisiting Smart Dust with RFID Sensor Networks. En HotNets, páginas 37–42, 2008.

[Bie12]

Alberto Bielsa. Smart Water project in Valencia to monitor Water Cycle Management. http://www.libelium.com/ smart water cycle monitoring sensor network/, 2012.

[Bie13]

Alberto Bielsa. Smart Parking and environmental monitoring in one of the world’s largest WSN. http://www.libelium.com/ smart santander parking smart city/, 2013.

[BMA02]

Kent Beck, Jesús García Molina, y Luis Joyanes Aguilar. Una explicación de la programación extrema: aceptar el cambio. Addison Wesley, 2002.

[Bro01]

David L Brock. The electronic product code (epc). Auto-ID Center White Paper MIT-AUTOID-WH-002, 2001.

[CCB14]

Raphael Cohn, Richard Coppen, y Geoff Brown. OASIS Message Queuing Telemetry Transport (MQTT) TC. https://www.oasis-open.org/ committees/tc home.php?wg abbrev=mqtt, 2014. 193

[CLI13]

Oscar Cosido, Carlos Loucera, y Andres Iglesias. Automatic calculation of bicycle routes by combining meta-heuristics and GIS techniques within the framework of smart cities. En New Concepts in Smart Cities: Fostering Public and Private Alliances (SmartMILE), 2013 International Conference on, páginas 1–6. IEEE, 2013.

[CLP03]

José H Canós, Patricio Letelier, y Ma Carmen Penadés. Metodologías Ágiles en el desarrollo de Software. VIII Jornadas de Ingeniería de Software y Bases de Datos, JISBD, 2003.

[Coh]

Raphael Cohn. StormMQ: A Comparison of AMQP and MQTT. url: http:// stormmq.com.

[D+ 06]

Adam Dunkels et al. The contiki operating system. Web page. Visited Oct, 24, 2006.

[DV08]

Adam Dunkels y JP Vasseur. IP for smart objects. Ipso alliance white paper, 1, 2008.

[Fin10]

Klaus Finkenzeller. RFID Handbook, ed, 2010.

[FPPV12]

Maria Fazio, Maurizio Paone, Antonio Puliafito, y Massimo Villari. Heterogeneous sensors become homogeneous things in smart cities. En Innovative Mobile and Internet Services in Ubiquitous Computing (IMIS), 2012 Sixth International Conference on, páginas 775–780. IEEE, 2012.

[GDFSB09] Ning Gui, Vincenzo De Florio, Hong Sun, y Chris Blondia. ACCADA: A Framework for Continuous Context-Aware Deployment and Adaptation. En Rachid Guerraoui y Franck Petit, editors, Stabilization, Safety, and Security of Distributed Systems, volume 5873 of Lecture Notes in Computer Science, páginas 325–340. Springer Berlin Heidelberg, 2009. url: http://dx.doi.org/ 10.1007/978-3-642-05118-0 23. [GKC04]

Neil Gershenfelo, Raffi Krikorian, y Danny Cohen. The Internet of ThingsThe principles that run the Internet are now creating a new kind of network of everyday devices, anÏnternet-O.". Scientific American, 291(4):46–51, 2004.

[HCC09]

Jonathan Hui, David Culler, y Samita Chakrabarti. 6LoWPAN: Incorporating IEEE 802.15. 4 into the IP architecture. IPSO Alliance White Paper, 3, 2009.

[Ins10]

Berg Insight. Fleet Management and Wireless M2M, 2010.

[JHU+ 05]

Felice Armenio Johnson Johnson, Mark Harrison, Bernie Hogan GS US, Jin Mitsugi, Josef Preishuber, Oleg Ryaboy CVS, y KK Suen. The EPCglobal Architecture Framework. 2005. 194

[JPPM10]

Carlos Blé Jurado, Juan Gutierrez Plaza, Fran Reyes Perdomo, y Gregorio Mena. Diseño Ágil con TDD. Enero 2010.

[KBE06]

Michael J Karlesky, William I Bereza, y Carl B Erickson. Effective test driven development for embedded software. En Electro/information Technology, 2006 IEEE International Conference on, páginas 382–387. IEEE, 2006.

[KS]

Anil Kumar y Jerry St.Clair. CUnit Testing Framework. http://cunit. sourceforge.net/index.html.

[KS13]

Ganesh S Khekare y Apeksha V Sakhare. A smart city framework for intelligent traffic system using VANET. En Automation, Computing, Communication, Control and Compressed Sensing (iMac4s), 2013 International MultiConference on, páginas 302–305. IEEE, 2013.

[Lib13a]

Libelium Comunicaciones Distribuidas S.L. 2013.

[Lib13b]

Libelium Comunicaciones Distribuidas S.L. Meshlium Quickstart Guide, Noviembre 2013.

[Lib13c]

Libelium Comunicaciones Distribuidas S.L. Meshlium Technical Guide, Noviembre 2013.

[Lib13d]

Libelium Comunicaciones Distribuidas S.L. Agosto 2013.

[Lib14a]

Libelium Comunicaciones Distribuidas S.L. Waspmote 802.15.4 Networking Guide, Febrero 2014.

[Lib14b]

Libelium Comunicaciones Distribuidas S.L. Waspmote Datasheet, Febrero 2014.

[Lib14c]

Libelium Comunicaciones Distribuidas S.L. Waspmote Technical Guide, Febrero 2014.

[Loc10]

D Locke. MQ Telemetry Transport (MQTT) V3. 1 Protocol Specification. Technical report, 2010.

[LP+ 03]

Ying Liu, Beth Plale, et al. Survey of publish subscribe event systems. Computer Science Dept, Indian University, 16, 2003.

Meshlium Datasheet, Agosto

Waspmote Quickstart Guide,

[LTQS+ 12] Anh Le Tu’n, Hoan Nguyen Mau Quoc, Martin Serrano, Manfred Hauswirth, John Soldatos, Thanasis Papaioannou, y Karl Aberer. Global Sensor Modeling and Constrained Application Methods Enabling Cloud-Based Open Space 195

Smart Services. En Ubiquitous Intelligence & Computing and 9th International Conference on Autonomic & Trusted Computing (UIC/ATC), 2012 9th International Conference on, páginas 196–203. IEEE, 2012. [MOA10]

Gaetano Marrocco, Cecilia Occhiuzzi, y Francesco Amato. Sensor-oriented passive RFID. En The Internet of Things, páginas 273–282. Springer, 2010.

[mos14]

Mosquitto Eclipse Technology Project. http://projects.eclipse.org/ projects/technology.mosquitto, 2014.

[MQT]

MQTT.org. url: http://mqtt.org.

[NMF+ 02] James Newkirk, Robert C Martin, Martin Fowler, Francisco Javier Zapata Martínez, y Jesús García Molina. La programación extrema en la práctica. Addison Wesley, 2002. [PG09]

Mirko Presser y Alexander Gluhak. The Internet of Things: Connecting the Real World with the Digital World. 2, 2009. url: http://eurescom.eu/ message.

[Pul12]

Ana Trejo Pulido. Open Smart Cities III: Plataformas, servicios y aplicaciones de código abierto para las Smart Cities. http://goo.gl/TXJgzV, 2012.

[Pul13]

Ana Trejo Pulido. Open Smart Cities I: La Internet de las Cosas de Código Abierto. http://observatorio.cenatic. es/index.php?option=com content&view=article&id=803: open-smart-cities-i-la-internet-de-las-cosas-abierto&catid= 94:tecnologia&Itemid=137, 2013.

[RAB+ 14]

Roberto Requena, Antonio Agudo, Alba Baron, Maria Campos, Carlos Guijarro, Jose Puche, David Villa, Felix Villanueva, y Juan Carlos Lopez. Implementing a Holistic Approach for the Smart City. En Active Media Technology, páginas 537–548. Springer, 2014.

[Rad12]

Loki Radoslav. Wireless Identification and Sensing Platform. 2012.

[Rog02]

S PRESSMAN Roger. Ingeniería de software: un enfoque practico. McGraw Hill, 2002.

[Sak06]

Ken Sakamura. Challenges in the age of ubiquitous computing: a case study of T-Engine, an open development platform for embedded systems. En Proceedings of the 28th international conference on Software engineering, páginas 713–720. ACM, 2006. 196

[SCT13]

AS Stanford-Clark y Hong Linh Truong. MQTT for Sensor Networks (MQTTS) Protocol Specification. Technical report, IBM developerWorks Technical Library, available at http://mqtt.org/documentation, 2013.

[Sel14]

María Campos Selfa. Razonamiento espacio-temporal basado en sentido común para la Smart City. Master’s thesis, 2014.

[SKP+ 11]

Hans Schaffers, Nicos Komninos, Marc Pallot, Brigitte Trousse, Michael Nilsson, y Alvaro Oliveira. Smart Cities and the Future Internet: Towards Cooperation Frameworks for Open Innovation. En John Domingue, Alex Galis, y Gavras et al., editors, The Future Internet, volume 6656 of Lecture Notes in Computer Science, páginas 431–446. Springer Berlin Heidelberg, 2011. url: http://dx.doi.org/10.1007/978-3-642-20898-0 31.

[Sri06]

Lara Srivastava. Pervasive, ambient, ubiquitous: the magic of radio. En European Commission Conference “From RFID to the Internet of Things”, Bruxelles, Belgium, 2006.

[tel11]

Fundación telefónica. Smart Cities: un primer paso hacia la internet de las cosas. Gran Via, 28, Madrid, 2011.

[TSH09]

Ioan Toma, Elena Simperl, y Graham Hench. A joint roadmap for semantic technologies and the internet of things. En Proceedings of the Third STI Roadmapping Workshop, Crete, Greece, volume 1, 2009.

[VAG13]

Athena Vakali, Lefteris Angelis, y Maria Giatsoglou. Sensors talk and humans sense towards a reciprocal collective awareness smart city framework. En Communications Workshops (ICC), 2013 IEEE International Conference on, páginas 189–193. IEEE, 2013.

[VSV+ 13]

F.J. Villanueva, M.J. Santofimia, D. Villa, J. Barba, y J.C. Lopez. Innovative Mobile and Internet Services in Ubiquitous Computing (IMIS), 2013 Seventh International Conference on. páginas 445–450, July 2013.

[WLZZ12] Jiafu Wan, Di Li, Caifeng Zou, y Keliang Zhou. M2m communications for smart city: An event-based architecture. En Computer and Information Technology (CIT), 2012 IEEE 12th International Conference on, páginas 895–900. IEEE, 2012.

197

Este documento fue editado y tipografiado con LATEX empleando la clase esi-tfg que se puede encontrar en: https://bitbucket.org/arco group/esi-tfg [Respeta esta atribución al autor]

199