Quick viewing(Text Mode)

Especificación De Escenarios De Automatización En Espacios Inteligentes

Especificación De Escenarios De Automatización En Espacios Inteligentes

UNIVERSIDAD DE CASTILLA-LA MANCHA ESCUELA SUPERIOR DE INFORMÁTICA

GRADO EN INGENIERÍA EN INFORMÁTICA

Especificación de escenarios de automatización en espacios inteligentes

Jesús Fernández-Bermejo Ruiz

Julio, 2019

ESPECIFICACIÓN DE ESCENARIOS DE AUTOMATIZACIÓN EN ESPACIOS INTELIGENTES

UNIVERSIDAD DE CASTILLA-LA MANCHA ESCUELA SUPERIOR DE INFORMÁTICA

Tecnologías y Sistemas de Información

GRADO EN INGENIERÍA EN INFORMÁTICA

INGENIERÍA DE COMPUTADORES

Especificación de escenarios de automatización en espacios inteligentes

Autor: Jesús Fernández-Bermejo Ruiz Tutor académico: Dr. David Villa Alises Cotutor académico: Dr. Xavier del Toro García

Julio, 2019

Jesús Fernández-Bermejo Ruiz Ciudad Real – Spain E-mail: [email protected] Teléfono: 627 258 238 c 2019 Jesús Fernández-Bermejo Ruiz 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 VOCAL SECRETARIO

Fdo.: Fdo.: Fdo.:

iii

Resumen

En la actualidad, los entornos inteligentes están proliferando en nuestra vida cotidiana, to- do gracias al paradigma del Internet de las Cosas o Internet of Things (IOT), el cual permite la interconexión de una cantidad masiva de dispositivos de uso cotidiano. La aplicación del IOT está desembocando en la aparición y aplicación de los conceptos ciudad inteligente y entorno inteligente. Estos entornos inteligentes, permiten mejorar el confort y el bienestar a las personas que los habitan, facilitando sus tareas, por medio de una serie de servicios distribuidos. El mayor desafío que se plantea en estos entornos es el de coordinar todos los servicios disponibles, de modo que puedan cooperar para satisfacer las necesidades del usua- rio, superando la dificultad de la heterogeneidad de todos estos servicios y dispositivos. En este Trabajo Fin de Grado (TFG), se propone una solución para la composición de los servicios que componen un entorno inteligente, todo ello a partir de un sistema - minado Automaker, que proveerá al usuario de las herramientas necesarias para componer y automatizar el entorno con total flexibilidad según sus preferencias. Las herramientas que Automaker pone a disposición del usuario para lograr tal fin son, un lenguaje denominado scn (pronunciado como el inglés scene), con el que el usuario pueda definir una serie de automatizaciones a partir de dispositivos y servicios básicos presentes en el entorno y un compilador, que a partir de un archivo en el lenguaje scn, genera la lógica y despliegue ne- cesario para que la automatización planteada por el usuario sea llevada a la práctica. Como escenario de referencia que ayude a guiar el desarrollo, se partió de un escenario inteligente de confort térmico, en el que la temperatura del entorno se debía adaptar a las preferencias del usuario.

V

Abstract

Today, smart environments are proliferating in our daily lives, all thanks to the paradigm of the Internet of Things (IOT), which allows the interconnection of a massive amount of everyday devices. The application of IOT is leading to the emergence and application of the concepts of smart city and smart environment. These smart environments make it possible to improve the comfort and well-being of the people who inhabit them, facilitating their tasks, through a series of distributed services. The biggest challenge in these environments is to coordinate all available services, so that they can cooperate to meet the needs of the user, overcoming the difficulty of the heterogeneity of all these services and devices. In this TFG, we propose a solution for the composition of the services that compose a smart environment, based on a system called Automaker, which will provide the user with the necessary tools to compose and automate the environment with total flexibility according to their preferences. The tools that Automaker makes available to the user to achieve this end are a language called scn (pronounced like scene), with which the user can define a series of automations to provide intelligence to the environment, and a compiler, so that from a file in the language scn, the automation proposed by the user can be brought to reality. As a reference scenario to help guide development, the starting point was an intelligent scenario of thermal comfort, in which the temperature of the environment had to be adapted to the user’s preferences.

VII

Agradecimientos

Han sido 4 años de grado, en los que la graduación se antojaba lejana, a veces, no era consciente de lo cerca que estaba el momento en que se iniciaría mi carrera profesional y se acabaría mi etapa de estudiante. Con este trabajo, doy por finalizado el Grado en Ingeniería Informática, aún recuerdo como si fuese ayer el día en el que decidí que estudios de grado cursar, y sin lugar a dudas, puedo decir a día de hoy, que ha sido una de las elecciones más acertadas de mi vida. Hay una gran cantidad de gente que ha contribuido, tanto directa como indirectamente, en que yo pueda estar escribiendo este trabajo. En primer lugar, me gustaría agradecer a toda mi familia todo el apoyo recibido durante estos años. Gracias a mis padres, por haberme permitido cursar este grado, sin su ayuda y la educación que me han inculcado, seguramente no estaría escribiendo estas páginas. Gracias a mis amigos, Juanvi y Ángel, con los que he compartido tanto malas como bue- nas experiencias durante muchos años, y que en los peores momentos, me han ayudado a continuar esforzándome. Este TFG no habría sido posible sin la ayuda del grupo de investigación ARCO. Agradecer a mis compañeros del ITSI por toda la ayuda prestada, a Javi por haber sido mi guía en estos 6 meses en los que he trabajado en el grupo, a Bárbara por haber hecho del laboratorio un lugar agradable para trabajar, a Ana y Rubén por su ayuda en la búsqueda de información para este trabajo, así como por esas conversaciones de media mañana que ayudan a continuar con el trabajo y a Edu por su amabilidad y por esas situaciones con las que nos hemos echado unas risas. Gracias a Óscar por toda la ayuda en el apartado más técnico, por su tiempo prestado a pesar de toda la carga de trabajo que soporta. No quiero olvidarme de mis compañeros del laboratorio de la ESI, José Antonio, José Mota y Cristian, los cuales en nuestras breves conversaciones. me han ayudado a orientar este trabajo, en especial a Cristian, por su ayuda y trabajos previos que han sido de vital importancia para el desarrollo de mi TFG. A mis dos tutores, agradecer todo su esfuerzo por ayudarme. A David, por esas reunio- nes esporádicas por la mañana en las que siempre estaba dispuesto a responder cualquier pregunta, así como hacerme comprender que significa ser un buen ingeniero. A Xavi, por su comprensión y apoyo en todo momento, además de su interés e iniciativa para completar este trabajo. Gracias a Ma José, que a pesar de no ser una tutora oficial, ha actuado como tal, solucionando cualquier problema que le planteaba, y actuando en la sombra para que todo prosperase correctamente. Agradecer a Juan Carlos la oportunidad que me ha brindado de trabajar en el grupo ARCO y la confianza que ha puesto sobre mi. Para finalizar, me gustaría dar las gracias a Antonia, la que es seguramente la persona que

IX 0. Agradecimientos haya sufrido mas el desarrollo de este TFG. Perdona por esas semanas sin vernos y por según tu, mi “obsesión” con el trabajo, gracias por tu comprensión y apoyo la cual ha sido de vital importancia durante todos mis años de carrera. Jesús

x A toda mi familia, por haberme ayudado a llegar hasta aquí

xi

Índice general

Resumen V

Abstract VII

Agradecimientos IX

Índice general XIII

Índice de figuras XIX

Índice de listados XXI

Listado de acrónimos XXIII

1. Introducción1 1.1. Tecnologías de Simulación: Gemelos Digitales...... 2 1.2. Concepto de Hogar Digital...... 4 1.2.1. Clasificación de las Smart Homes...... 5 1.2.2. Beneficios de las Smart Homes...... 6 1.2.3. Implantación y barreras de las smart homes...... 6 1.3. Confort térmico...... 7 1.4. Composición automática de servicios...... 9 1.5. Lenguajes de especificación de escenarios...... 11 1.5.1. ¿Qué es un procesador de lenguaje?...... 11 1.5.2. Lenguajes y Sistemas existentes en especificación de automatizaciones 13 1.6. Sistemas Expertos...... 20 1.6.1. CLIPS...... 20 1.6.2. PyKnow...... 22 1.7. ZeroC Ice...... 22 1.7.1. Conceptos básicos de Ice...... 23 1.7.2. IceGrid...... 24

XIII 0. Índice general

1.7.3. IceC...... 24

2. Objetivos 27 2.1. Objetivo general...... 27 2.2. Objetivos específicos...... 27 2.2.1. Estudio de lenguajes y Sistemas existentes...... 27 2.2.2. Estudio de las necesidades de automatización...... 27 2.2.3. Diseño del lenguaje de especificación...... 28 2.2.4. Desarrollo del procesador de lenguaje...... 28 2.2.5. Diseño y desarrollo del sistema de despliegue...... 28 2.2.6. Elaboración de escenarios de ejemplo...... 28

3. Método 29 3.1. Metodología de Prototipado...... 29 3.1.1. Prototipos...... 29 3.1.2. Variantes de modelos de prototipado...... 30 3.2. Prototipado Evolutivo...... 31 3.3. Desarrollo Dirigido por Tests (TDD)...... 31 3.4. Justificación y Aplicación de la metodología...... 32 3.5. Herramientas...... 33 3.5.1. Herramientas Hardware...... 33 3.5.2. Herramientas Software...... 33

4. Desarrollo del Proyecto 35 4.1. Iteración 1: Desarrollo de la placa de control...... 35 4.2. Iteración 2: Estudio de sistemas de automatización...... 36 4.3. Iteración 3: Sintaxis del lenguaje scn...... 37 4.3.1. Modelado de condiciones...... 38 4.3.2. Modelado de acciones...... 38 4.3.3. Almacenamiento de las reglas...... 38 4.3.4. Representación de los elementos del mundo real...... 39 4.3.5. Retrospectiva...... 40 4.4. Iteración 4: Creación del Generador de Código...... 40 4.4.1. Retrospectiva...... 42 4.5. Iteración 5: Creación del Parser...... 42 4.5.1. Lectura de argumentos...... 43

xiv 4.5.2. Retrospectiva...... 44 4.6. Iteración 6: Implementación de un escenario con dos switches...... 44 4.6.1. Factory...... 45 4.6.2. Wirer...... 46 4.6.3. Retrospectiva...... 46 4.7. Iteración 7: Implementación del Provisioner...... 46 4.7.1. Refactorización del provisioner...... 47 4.7.2. Retrospectiva...... 48 4.8. Iteración 8: Implementación de nueva sintaxis...... 48 4.8.1. Refactorización de Template...... 50 4.8.2. Refactorización clase Statement...... 50 4.8.3. Refactorización Evento...... 51 4.8.4. Retrospectiva...... 52 4.9. Iteración 9: Añadir condiciones al lenguaje de provisionado...... 52 4.10. Iteración 10: Creación de escenario con condiciones...... 53 4.11. Iteración 11: Añadir soporte para condiciones con umbrales...... 55 4.11.1. Refactorización Jerarquía de clase Statement...... 56 4.11.2. Retrospectiva...... 56 4.12. Iteración 12: Definición de interfaz para la comunicación con los operadores 57 4.12.1. Refactorización jerarquía de operadores...... 58 4.12.2. Factoría de predicados...... 58 4.13. Iteración 13: Refactorización del lenguaje de provisión...... 59 4.13.1. Refactorizaciones de código en esta iteración...... 60 4.13.2. Modificación almacenamiento interno de condiciones...... 61 4.13.3. Retrospectiva...... 61 4.14. Iteración 14: Creación de escenarios HVAC...... 62 4.15. Iteración 15: Consulta del estado de los dispositivos en tiempo de ejecución 63 4.15.1. Inclusión del servidor de propiedades...... 64 4.15.2. Cambios en Condition, Event y Action...... 65 4.15.3. Nuevo nombre para el servidor de los Operadores...... 66 4.16. Iteración 16: Implementación del escenario real...... 67 4.17. Iteración 17: Adición de soporte para Delays...... 70

5. Conclusiones 71 5.1. Resultado del Proyecto...... 71 5.2. Objetivos Cumplidos...... 74

xv 0. Índice general

5.3. Trabajos Futuros...... 75 5.3.1. Provisionado de operadores en un escenario anteriormente provisio- nado...... 75 5.3.2. Incremento del análisis semántico...... 75 5.3.3. Temporalidad en el sistema...... 76 5.3.4. Mejora semántica de los mensajes...... 77 5.4. Justificación de Competencias: Ingeniería de Computadores...... 78

A. Desarrollo de la placa de control para el HVAC 83 A.1. Fabricación de la placa de control...... 83 A.1.1. Diseño de la placa con DesignsparkPCB...... 83 A.1.2. Fabricación de la placa...... 84 A.1.3. Soldado de componentes...... 94 A.1.4. Instalación del PCB...... 96

B. Esquemático de la placa 99

C. Diagrama de clases 101

D. Manual de usuario 103 D.1. Introducción...... 103 D.2. Creación e Instanciación de tipos de Dispositivos...... 103 D.3. Definición de una regla...... 104 D.4. Condiciones con umbrales...... 105 D.5. Utilización del estado de los dispositivos...... 106 D.6. Uso de Delays...... 107 D.7. Compilación de un archivo fuente...... 108

E. Listados de código 109

F. GNU Free Documentation License 113 F.0. PREAMBLE...... 113 F.1. APPLICABILITY AND DEFINITIONS...... 113 F.2. VERBATIM COPYING...... 114 F.3. COPYING IN QUANTITY...... 114 F.4. MODIFICATIONS...... 115 F.5. COLLECTIONS OF DOCUMENTS...... 116 F.6. AGGREGATION WITH INDEPENDENT WORKS...... 116

xvi F.7. TRANSLATION...... 116 F.8. TERMINATION...... 116 F.9. FUTURE REVISIONS OF THIS LICENSE...... 117 F.10. RELICENSING...... 117

Referencias 119

xvii

Índice de figuras

1.1. Esquema básico del sistema...... 2 1.2. Diferentes dimensiones en las tecnologías de simulación a través de todo el ciclo de vida de un sistema [SR16]...... 3 1.3. Vista de un Virtual Testbed [SR16]...... 4 1.4. Arquitectura propuesta [SVA+18]...... 10 1.5. Modelo semántico propuesto para la composición y reconfiguración de ser- vicios [SVA+18]...... 11

4.1. Representación de un operador...... 41

4.2. Construcción automática de los operadores a partir de un archivo scn .... 49 4.3. Solución fabrica para el control del HVAC...... 68 4.4. Gateway y sensor de temperatura de Xiaomi...... 68

5.1. Funcionamiento del sistema Automaker en el escenario del confort térmico 73

A.1. Centralita Mitsubishi...... 84 A.2. Correspondencia de cada archivo con su capa...... 85 A.3. Interfaz CircuitCam...... 86 A.4. Modificar parámetros del contorno...... 87 A.5. Máquina LPKF usada para la impresión de la placa...... 87 A.6. Mesa de trabajo de la máquina LPKF...... 88 A.7. Interfaz del software BoardMaster...... 90 A.8. Herramientas colocadas en la máquina LPKF...... 91 A.9. Área de trabajo seleccionada...... 92 A.10.Footprint de la placa tras importar el archivo...... 92 A.11.Ventana de modificación de las coordenadas del Home...... 93 A.12.Ejemplo de dos placas tras la impresión. En esta foto es observable las unio- nes de 1 mm que se indicaron a CircuitCam que no se debían cortar.... 94 A.13.Placa lista para ser soldada...... 95 A.14.Componentes SMD soldados en la placa...... 96

XIX 0. Índice de figuras

A.15.Placa extraída de la centralita...... 97

B.1. Esquemático de la placa de control...... 100

C.1. Diagrama de clases...... 101

xx Índice de listados

1.1. Ejemplo con Domoticz...... 14 1.2. Ejemplo con Home Assistant...... 15 1.3. Activar la luz del pasillo cuando la temperatura sea superior a 22oC con el lenguaje de Xiaomi...... 19 1.4. Ejemplo automatización de ESPHome...... 20 1.5. Ejemplo de regla con CLIPS...... 21 1.6. Regla con PyKnow...... 22 4.1. Sintaxis de una regla...... 37

4.2. Clase Engine ...... 39

4.3. Clase Template ...... 40 4.4. Escenario con la sintaxis actual del lenguaje...... 40 4.5. Línea de código para desplegar un operador...... 41 4.6. Generación de una línea de código a partir de una regla...... 42 4.7. Sintaxis de llamada al compilador...... 43 4.8. Procesado de argumentos...... 44 4.9. Interfaces de smart-transducer...... 45 4.10. Clase IceMixin...... 47

4.11. Clase Compiler y main del compilador...... 48 4.12. Regla con la nueva sintaxis...... 49 4.13. Metaclase Template...... 50 4.14. Clase Statement...... 51

4.15. Método para construir las condiciones del lenguaje prv ...... 52 4.16. Provisionado de un operador con condiciones...... 52 4.17. Ejemplo de especificación para el escenario...... 53

4.18. Comprobación de tipos permitiendo str ...... 55 4.19. Función Check...... 56 4.20. Automaker.ice...... 57 4.21. Factoría de Predicados...... 59 4.22. Ejemplo de lenguaje provisioner con condiciones...... 60

XXI 0. Índice de listados

4.23. Ejemplo con la nueva sintaxis...... 60 4.24. Cambios del método build_conditions...... 61 4.25. Uso de variable en una automatización...... 63 4.26. Slice de Automaker con la estructura Copy...... 64 4.27. Consulta de una variable en tiempo de ejecución por parte de un operador. 64 4.28. Clase Resolver...... 65 4.29. Métodos when y set para la generación de condiciones y acciones..... 66

4.30. Clase Event ...... 67 4.31. Ejemplo de regla con Delay ...... 70 5.1. Código fuente del escenario de ejemplo...... 72 5.2. Dos reglas inconsistentes...... 76 5.3. Interfaz haciendo uso de Protocol Buffers...... 78 5.4. Definición de Fact con Protocol Buffers...... 78

D.1. Automatización para los switches sw1 y sw2 ...... 105

D.2. Encender sw2 cuando cambie el estado de sw1 ...... 106

D.3. Automatización con sintaxis explícita en sw1 ...... 106 D.4. Automatización con variables...... 107 D.5. Automatización haciendo uso del estados de los dispositivos...... 107 D.6. Automatización con Delay...... 108 D.7. Archivo locator.config...... 108

D.8. Ejecución de un archivo denominado examples.scn ...... 108

E.1. Código fuente de la clase Rule ...... 109 E.2. Interfaz de la Factoría...... 109 E.3. Interfaz del Wirer...... 110 E.4. Ejecución del provisionamiento...... 110 E.5. Interfaz Ice del servidor de propiedades...... 111 E.6. Ultima versión de Automaker.ice...... 111

xxii Listado de acrónimos

CLIPS C Language Integrated Production System FPGA Field-Programmable Gate Array HVAC Heating, Ventilation and Air-Conditioning systems IA Inteligencia Artifical

ICEC ICE for C language IDM Inter-Domain Messaging Protocol IP Internet Protocol ITSI Insituto de Tecnologías y Sistemas de la Información

ICE Internet Communication Engine

IOT Internet of Things PCB Placas de Circuito Impreso PCS Personal Confort System PIO PlatformIO PMV Voto Medio Previsto SMD Surface Mounted Device

SLICE Specification Language for Ice TDD Test Driven Development TFG Trabajo Fin de Grado UCLM Universidad de Castilla-La Mancha

VSCODE Visual Studio Code

GCC GNU Compiler Collection

OPENHAB open Home Automation Bus

ST Smart Transducer

XXIII

Capítulo 1 Introducción

L concepto de Smart Home u Hogar Digital vuelve a resurgir como evolución del anti- E guo paradigma del hogar domótico pero, ¿qué es en realidad un Hogar Digital? ¿cómo afecta a nuestra vida cotidiana? o ¿cuál es su nivel de implantación? La característica princi- pal de una Hogar Digital es la automatización de los elementos que componen un hogar, que permita al entorno poseer la inteligencia necesaria para cubrir, en gran medidas y de forma automática, las necesidades del usuario.

El paradigma del hogar inteligente debe aún abordar una serie de retos hasta llegar a convertirse en una realidad. Entre estos está la capacidad para abordar necesidades no consi- deradas previamente y para las que no se puede disponer de un plan, precodificado, de cómo se deberá responder a la misma. La incertidumbre que caracteriza a estos entornos también es responsable de que no se pueda determinar, de antemano, la lista de servicios o disposi- tivos se necesitarán. Por lo tanto, uno de los principales retos que, a día de hoy, deben ser abordados es el de proporcionar al hogar inteligente la capacidad de, a partir de una nece- sidad detectada, combinar los servicios y dispositivos disponibles para satisfacer tanto las necesidades predeterminadas como las imprevistas.

En este proyecto (de forma similar a otros como veremos) hemos considerado que la forma más potente y flexible para proporcionar esta capacidad de composición es contar con un lenguaje que permita especificar cómo deben conectarse los distintos elementos disponibles en el entorno y cómo deben responder a situaciones concretas que el usuario (u otro agente) considere convenientes.

Estos servicios sobre los que se construye el concepto de hogar inteligente representan la versión digital de los diferentes objetos reales que existen en la misma. Se dice entonces que los servicios del entorno se representan mediante Digital Twins o Gemelos Digitales, encargados de controlar su contraparte física. Una de las grandes ventajas de usar Gemelos Digitales es la flexibilidad que estos aportan. Por ejemplo, un dispositivo físico es capaz de enviar un dato en un instante de tiempo concreto. En cambio, el uso de Gemelos Digitales nos permite hacer un pequeño preprocesamiento en su contraparte digital para hacer que el objeto envíe una media de los datos calculada en un periodo de tiempo, en lugar del valor único que proporciona el objeto físico.

1 1. Introducción

Sobre la base del paradigma de gemelos digitales y hogar inteligente, este trabajo es- tudiará el desarrollo de un lenguaje con su correspondiente compilador, que soportará la composición de servicios, como mecanismo habilitador para dar respuesta a las necesidades detectadas en estos entornos. Este lenguaje será puesto a prueba en un caso de uso donde se evaluará la composición de servicios en un entorno inteligente que pretende el confort térmico de las personas que lo habitan. Es importante señalar que se trata de un compilador muy especial, compuesto en realidad de dos componentes bien diferenciados: El primero es un compilador tradicional, que toma como fichero fuente la especifi- cación de una escena (lenguaje scn) y genera otro fichero escrito en un lenguaje de provisionado (prv) definido también en este proyecto. El segundo podríamos decir que es en realidad una especie de intérprete. Toma como entrada el fichero de provisión y con esta información interactúa con la infraestructura (una aplicación distribuida IceGrid) para instanciar y configurar todos los componentes y servicios necesarios para que el entorno sea capaz de llevar a cabo las automatiza- ciones correspondiente a la especificación original. En conjunto el lenguaje propuesto y el compilador no tienen como objeto generar un pro- grama ejecutable. Lo que hacen realmente es generar una aplicación distribuida que tomando elementos del entorno, los coordina para lograr la funcionalidad deseada. La figura 1.1 resu- me esta idea de forma muy simplificada.

Figura 1.1: Esquema básico del sistema

1.1 Tecnologías de Simulación: Gemelos Digitales El uso de la tecnología de simulación es una práctica muy usada en el campo de la ingenie- ría para el desarrollo de controladores en la prueba y verificación de diseño de componentes. En los procesos de la ingeniería, el uso de estos sistemas de simulaciones es muy común porque permite la reducción de costes y una optimización del tiempo de desarrollo. Además de este uso clásico de la simulación en ingeniería, una nueva tendencia es el uso de la tecnología de simulación dentro de un sistema real. Este fue el punto de partida para analizar sistemáticamente varios escenarios de uso para las tecnologías de simulación. La simulación se usa en diferentes etapas del ciclo de vida, por diferentes disciplinas de la

2 Tecnologías de Simulación: Gemelos Digitales

Figura 1.2: Diferentes dimensiones en las tecnologías de simulación a través de todo el ciclo de vida de un sistema [SR16] ingeniería, con diferentes dominios de simulación (ver Figura 1.2). Hoy en día la mayoría de aplicaciones de simulación resuelven exactamente una aplicación específica, formada por la combinación de un aspecto de cada una de las ocho dimensiones ilustradas anteriormente. La combinación de diferentes aspectos de la misma dimensión es prácticamente imposible.

Para superar la imposibilidad de combinar las distintas dimensiones, es necesario desa- rrollar nuevos conceptos que permitan el uso de las tecnologías de simulación. La respuesta para lograr superar estas limitaciones se puede organizar en dos partes, la primera apunta a los digitial twins o gemelos digitales, como representación virtual de un sujeto o un ob- jeto del mundo real. Un digital twin contiene un modelo de datos, su funcionalidad y una interfaz de comunicación. La segunda parte de la respuesta es afrontar los retos tecnológi- cos para poder desarrollar métodos de simulación que sean capaces de integrar las distintas dimensiones [SR16].

Un método muy útil para realizar la simulación de Gemelos Digitales es el uso de Virtual Testbeds o Banco de Pruebas Virtuales. Un Virtual Testbed es una aplicación de simulación que combina un DPS (Sistema de procesamiento de datos) con un entorno simulado (ver Figura 1.3). El entorno simulado comprende el sistema técnico simulado, representado por el vector del sistema interno, los sensores simulados, los actuadores simulados y un entorno simulado. El DPS comprende una entrada de sensores, una salida de actuadores y un entorno

3 1. Introducción percibido.

Figura 1.3: Vista de un Virtual Testbed [SR16]

Como se ha comentado anteriormente, los Virtual Testbeds son muy útiles para modelar y simular concurrentemente Gemelos Digitales, pero debido a que deben ser usados en dis- tintos escenarios de aplicación, es requerido un rendimiento considerable. Para superar las limitaciones inherentes al uso de las tecnologías de simulación y para crear Gemelos Digita- les cercanos a la realidad, se han desarrollado nuevas arquitecturas que permitan obtener el rendimiento necesario. Por lo tanto, el uso de los Gemelos Digitales permite, por un lado, procesos de desarrollo menos costosos, mejores diseños y sistemas más confiables. Esto permite llevar la simulación a sistemas reales, facilitando el desarrollo y la transferencia de algoritmos complejos a sis- temas reales y facilitando el desarrollo de sistemas inteligentes. Además, permite continuar con el desarrollo de diferentes aproximaciones en las tecnologías de la simulación.

1.2 Concepto de Hogar Digital El término smart va ganando en popularidad, aplicándose a distintas tecnologías, smart phone, smart tv, smart home... Los atributos clave de una tecnología smart son la capacidad de adquirir información del entorno que le rodea y reaccionar en consecuencia. La tendencia de transformar los productos y servicios en inteligentes ha puesto el foco en los distintos electrodomésticos de nuestro hogar, donde esta tecnología puede ser aplicada intensivamen- te. Debido al gran impacto, tanto económico como social de las tecnologías smart, se ha procedido a una revisión de la literatura sobre dicho concepto resultando en múltiples de- finiciones. Observando las definiciones anteriormente comentadas, D. Marikyan [MPA18] concluyó que hay un solapamiento entre todas ellas, compartiendo tres características en co-

4 Concepto de Hogar Digital mún: tecnología, servicios y la capacidad de satisfacer las necesidades de los usuarios. El núcleo de las smart home es la tecnología, que consiste en componentes hardware y soft- ware, incluidos sensores y electrodomésticos. Los sensores se integran dentro de algunos electrodomésticos a través de sistemas tanto inalámbricos como cableados, de modo que son capaces de detectar cambios en el comportamiento humano y otros estímulos del entorno, produciendo así una variedad de funciones y servicios que se ajustan a las necesidades del usuario. En resumen, una smart home representa dispositivos y sensores que están integrados en un sistema inteligente, ofreciendo gestión, monitorización, soporte y servicios eficientes, abarcando una serie de beneficios económicos, sociales, emocionales y también en cuanto a salud, sostenibilidad y seguridad.

1.2.1 Clasificación de las Smart Homes Profundizando en las características y significado de los hogares digitales se pueden ob- servar una serie de clasificaciones diferentes. [MPA18] En la primera de ellas las smart home pueden ser clasificadas en tres tipos según el servicio que ofrecen, la primera categoría provee asistencia a sus ocupantes según la identificación de sus acciones, la segunda consiste en detectar y recolectar información en formato multimedia y la tercera y última clasificación, consiste en la monitorización del hogar con el objetivo de procesar datos, para pronosticar y alertar a los residentes en caso de desastres naturales o intervenciones de seguridad. La segunda clasificación divide las smart homes en cuatro generaciones, según lo avanzada y sofisticada que sea la tecnología usada:

Primera generación: Representa tecnologías no embebidas con Inteligencia Artifical (IA), pero que eran activadas por el movimiento de los residentes.

Segunda generación: Empleo de formas elementales de dispositivos basados en IA, detectando cambios en el entorno a través de sensores, para monitorizar el estado de salud de los usuarios. Tercera generación: Uso de tecnologías interoperables y multifuncionales, gracias a la introducción del control de activado por voz y a la conectividad con otros dispositi- vos que hace posible capturar, procesar y transmitir datos en una red de dispositivos. Cuarta generación: Se empezará a poner práctica alrededor del 2020, y remplazará los sensores existentes por unos que estén embebidos bajo la piel. Estos sensores tienen un gran potencial para la monitorización y la gestión de la salud en remoto.

La tercera y última clasificación se basa en la observación del comportamiento de los servicios de una smart home, clasificando las mismas según la funcionalidad que proveen, dando lugar a 5 categorías distintas: Confort, Monitorización, Terapia de la salud, Soporte y Consultoría.

5 1. Introducción

1.2.2 Beneficios de las Smart Homes Como se puede observar, la literatura de Smart Home discute su potencial y percibe sus beneficios en términos de ventajas inmediatas que se le ofrecen a los usuarios junto a su impacto a largo plazo. Estos beneficios son descompuestos principalmente en cuatro grupos diferentes.

Para empezar, las smart home proporcionan beneficios relacionados con el ámbito de la salud. Estos beneficios se derivan de las tecnologías que llevan a cabo servicios de monitori- zación, gestión, confort y consultoría. Gracias a estos, se ofrece a los usuarios una atención médica de calidad, con una monitorización constante del estado de salud y la posibilidad de realizar consultas a distancias.

Las smart homes también son capaces de proveer beneficios medioambientales, gracias a la mejora de la eficiencia en el uso de energía en el entorno residencial. El interés de estos beneficios ha crecido exponencialmente en los últimos años, todo ello debido a amenazas como el cambio climático, el calentamiento global y la volatilidad del precio de la electri- cidad. Los beneficios de la eficiencia energética son posibles gracias a cuatro servicios, la monitorización de información en la consumición de energía, la gestión de los servicios con el objetivo de lograr una eficiencia energética y optimización, control de los patrones de consumo a través de dispositivos remotos y la consultoría.

El tercer beneficio que pueden aportar las smart homes es el beneficio en términos finan- cieros. Este beneficio está asociados de alguna forma con los dos anteriores, por ejemplo, el ahorro de energía en los dispositivos para lograr sostenibilidad medioambiental, también produce un menor consumo de energía, reduciendo así los gastos en electricidad.

Por último, las smart homes aportan beneficios sobre el bienestar psicológico e inclusión social. Gracias a las smart home, las personas pueden socializar de una forma más sencilla, a la vez que superan el sentimiento de aislamiento. Esto es posible gracias a la implemen- tación de servicios relacionados con el soporte y la asistencia. Algunos autores consideran este beneficio un arma de doble filo, ya que puede mejorar la autopercepción personal, pe- ro también puede afectar negativamente las vidas sociales de los usuarios reemplazando la comunicación física.

1.2.3 Implantación y barreras de las smart homes A pesar de los beneficios potenciales que poseen las smart homes, su adopción y difusión crecen lentamente. Por lo tanto es muy importante examinar la aceptación y adopción de los hogares digitales, además de la perspectiva de los usuarios respecto a las barreras que pueden suponer un obstáculo para su implementación. Estos obstáculos van desde las barre- ras tecnológicas, pasando por cuestiones económicas, éticas y legales hasta el desfase del conocimiento y la resistencia al cambio.

6 Confort térmico

Las barreras de la usabilidad, referida a la confiabilidad y facilidad de uso, han demostrado tener un rol crucial en la aceptación de la tecnología de las smart home, lo que conlleva que la complejidad de la tecnología derive en el rechazo a adoptarla. A pesar de esto, siguen exis- tiendo una gran cantidad de dispositivos complicados de usar, ya que la mayoría de proyectos sobre las smart homes solían ser puramente técnicos, sin tener en cuenta la perspectiva del usuario. El segundo grupo de barreras compromete asuntos legales, financieros y éticos. Los fac- tores financieros incluyen el precio de la tecnología, el coste de la instalación, reparación y mantenimiento, los cuales desalientan a los usuarios a adoptar esta tecnología. A algunas personas les es difícil comprender como las smart homes podrían ayudarles a ahorrar dinero, teniendo en cuenta que antes de obtener beneficios, hay que realizar un esfuerzo tanto eco- nómico como de aprendizaje. Todo esto genera una desconfianza por parte de los usuarios respecto a la tecnología. Debido a la capacidad que tienen las smart homes de almacenar y recolectar una gran cantidad de datos privados plantea algunos problemas éticos tales como la privacidad y la seguridad de los datos. Una solución a este problema es el desarrollo e implementación de protocolos sofisticados con el objetivo de eliminar el riesgo de intrusión a los datos que se manejan. Sumado a las dificultades anteriores, los problemas legales son un bloqueo para la acepta- ción, especialmente en relación a la industria médica y de asistencia social. Esto es debido a que estas tecnologías crean nuevos escenarios en los que existe un vacío legal que debe cu- brirse para lograr la aceptación de los usuarios, garantizando la protección y la seguridad de los datos de los usuarios y evitando incumplimientos de las leyes vigentes, ya sea accidental o intencionada. Una última barrera con la que se encuentran las smart home es la baja percepción de utili- dad por parte de los usuarios debido a la falta de conocimiento, confianza y experiencia para aceptar los beneficios de esta tecnología. Debido a que estas tecnologías están emergiendo recientemente, y a la falta de conocimiento por parte de los usuarios anteriormente mencio- nada, su aceptación es muy baja. A estas dificultades se le añade que con la implantación de esta tecnología cambia el comportamiento y estilo de vida de quien la utiliza, produciendo una barrera psicológica y una resistencia al cambio que conlleva una baja percepción de su utilidad. Una posible solución a esta barrera sería ajustar los productos de las smart home y hacerlos más flexibles y adaptables a los hábitos de los usuarios.

1.3 Confort térmico El confort térmico es una meta importante para las edificaciones, puesto que afectan la satisfacción del ocupante, la salud y la productividad. Algunos autores como M. Luo et al. [LWB+18] han desarrollado estudios sobre la expectación del confort térmico, compro-

7 1. Introducción bando que en efecto no todos los usuario poseen la misma noción del concepto confort y que además esta noción está basada en las experiencias previas. Para comprender qué es lo que se considera un ambiente térmicamente confortable, los investigadores se han centrado en desa- rrollar modelos empíricos que representen la percepción humana del confort térmico, dando lugar a dos principales modelos; Voto Medio Previsto (PMV) y modelos adaptativos.

El modelo PMV trata el confort térmico como un fenómeno psicosocial y expresa la sen- sación térmica como el resultado de la transferencia de calor entre un cuerpo humano y el entorno que le rodea. El modelo adaptativo, por el contrario, consideran la capacidad de las personas a adaptarse a condiciones ambientales variables, trazando una relación lineal entre la temperatura interior confortable y la temperatura exterior predominante.

Los modelos anteriormente presentados tienen problemas para predecir, con precisión, las características del confort térmico de un individuo en un entorno particular, dado que son modelos orientados a conjuntos. La investigación y la industria parece haber encontrado una solución a las limitaciones de estos modelos gracias a la aparición de la Internet of

Things (IOT) y su capacidad para generar una alta cantidad de datos.

Con la aparición de las tecnologías IOT, surgen los modelos personales de confort que predicen una respuesta individual al confort térmico, en lugar de la respuesta media para una gran población. Estos modelos personales de confort pueden ayudar a superar las dificulta- des de los antiguos modelos, entendiendo las necesidades y deseos de un ocupante concreto, y caracterizando una serie de condiciones que pueden satisfacer su confort térmico en un espacio dado. Para solventar las diferencias entre las preferencias térmicas de dos ocupantes del mismo entorno se han explorado dos aproximaciones, soluciones basadas en consenso y soluciones tecnológicas. Las soluciones basadas en consenso seleccionan un punto que minimiza el error entre las preferencias de todos los ocupantes y la temperatura actual del entorno. Las soluciones tecnológicas en cambio plantean que los usuarios ajusten el termos- tato en tiempo real, cada persona dispondrá de un voto cada diez minutos, al final del periodo de votos, se realizará la media de las temperaturas votadas cuyo resultado será la temperatura que marque el termostato. [KSB18]

Una solución tecnológica alternativa a la planteada puede ser el uso de Personal Confort System (PCS), para proveer temperaturas locales, sin afectar a otros individuos en el mismo espacio. Gracias a estos sistemas, se pueden crear zonas microclimáticas para un ocupante en particular, sin necesidad de afectar el resto de individuos en el mismo espacio. Algunas ejemplos de sistemas PCS pueden ser calentadores de pies y sillas con temperatura regulable. Estos dispositivos están pensados para modificar la temperatura de partes del cuerpo muy sensibles, para aumentar su influencia en el cuerpo y modificar la sensación de placer. A parte de modificar la temperatura corporal estos dispositivos también permiten la recolección de una gran cantidad de datos del usuario [KBR+18].

8 Composición automática de servicios

Aunque pueda parecer que los dispositivos PCS no sean de gran utilidad, su eficacia ha sido demostrada. Algunos resultados con sensores calibrados han demostrado que las tem- peraturas locales pueden variar hasta 2.9 oC en una misma hora a través de distintos espacios. Incluso en las mismas zonas térmicas, las temperaturas pueden variar mas de 0.4 oC. Estas diferencias de temperatura son muy difíciles de solventar con sistemas de ventilación y aire acondicionado convencionales. Gracias a los dispositivos PCS se puede conocer la tempe- ratura local exacta de un individuo, pudiendo actuar en consecuencia con las preferencias térmicas del usuario.

1.4 Composición automática de servicios

En la actualidad el mayor problema al que se enfrentan las tecnologías IOT es la hete- rogeneidad de las fuentes de datos con los que operan. Para abordar este problema se han planteado dos soluciones, el uso del cloud para permitir la interoperabilidad de las redes IOT, y el uso de gateways, el cual plantea un problema de sobrecarga de protocolos.

Una correcta actuación de los sistemas IOT no depende exclusivamente de una correcta interoperabilidad entre sus componentes, también depende de comprender el entorno y los objetos que lo componen. Con este objetivo es necesario desarrollar un modelo que capture la semántica del sistema y el comportamiento humano, además de la capacidad de componer y reconfigurar la funcionalidad de los servicios automáticamente.

La arquitectura propuesta por Santofimia et al. [SVV+16] está principalmente concebida para soportar la actuación y el comportamiento inteligente en IOT. Esta arquitectura se dota de los mecanismos necesarios para permitir la composición y reconfiguración de servicios, manteniendo a su vez una alta flexibilidad y una baja relación entre los procesos. Dado que el paradigma IOT es un paradigma orientado a eventos, la arquitectura propuesta está concebida para capturar eventos por medio de distintos sensores. Estos eventos pueden ser propagados virtualmente por todo el sistema, sin necesidad de propagar el estimulo causante del evento. De este modo, se crea una especie de pipeline de servicios que debe cumplir los siguientes requisitos:

1. Soporte para vinculación de servicios: El pipeline de servicios se apoya en el hecho de que cada servicio apunta al próximo elemento del pipeline por medio de una dirección que apunta al servicio. La elección de qué servicios y en qué orden serán enlazados es responsabilidad del planificador.

2. Compatibilidad en el nivel léxico: Los requisitos de un pipeline de servicios en tér- minos de corrección sintáctica, se refiere a los mensajes usados para el enlazado de elementos. Un mensaje es valido cuando los datos que contiene son del formato o tipo esperado.

3. Compatibilidad en el nivel semántico: La compatibilidad semántica de los servicios se

9 1. Introducción

determina considerando la compatibilidad de las interfaces de los servicios que están conectados, así como de las capacidades que un servicio necesita y el resto provee.

La arquitectura propuesta para las smart homes basadas en IOT posee dos funciones prin- cipales: 1) la capacidad para comprender situaciones actuales de forma automática y los medios disponibles para dar respuesta y, 2) la capacidad para integrar, componer y reconfi- gurar objetos IOT sin problema. Esta arquitectura esta compuesta por cuatro capas diferentes (ver Figura 1.4)[SVA+18].

Figura 1.4: Arquitectura propuesta [SVA+18]

Capa de servicios: Los servicios están localizados en la capa más baja de la arquitec- tura, y son tratados de forma simétrica independientemente de cómo o dónde han sido

desarrollados o implementados. Todo sistema IOT está formado por servicios a nivel de Edge-computing, Fog-computing y Cloud-computing. Estos servicios son homoge- neizados para ser tratados de igual manera, habilitando al planificador para componer y reconfigurar servicios. Para lograr esta homogeneización, se propone el uso del pro- tocolo Inter-Domain Messaging Protocol (IDM)[VA+17], protocolo que permite inter-

comunicar distintos objetos en una red IOT, logrando una comunicación simétrica sin necesidad de saber los detalles tecnológicos.

Capa de middleware: En esta capa se encuentra el middlware ZeroC Ice, un middlewa- re orientado a objetos de propósito general, con una serie de servicios que facilitan la propagación de eventos. Este middleware ha sido modificado, incorporando una serie de servicios que soportan el proceso de despliegue de servicios, así como las tareas involucradas en la composición de servicios. Estos servicios añadidos son servicios de propiedad, servicio de detección, servicio de contexto y servicio avanzado de eventos.

Capa semanticware: El término semanticware se refiere a que esta capa es la encar- gada de contener la información semántica del sistema. Esta capa asegura que todos los intercambios de información trabajan sobre la misma semántica, y como conse- cuencia, trabajan sobre la misma comprensión de la información o de la funcionalidad empleada. Esta capa está soportada por un modelo semántico (ver Figura 1.5).

10 Lenguajes de especificación de escenarios

Figura 1.5: Modelo semántico propuesto para la composición y reconfiguración de servi- cios [SVA+18]

Capa awareness: Esta capa, también denominada capa de concienciación con el en- torno, es le encargada de comprender que está sucediendo en el entorno, con el objetivo de actuar en consecuencia y tomar las decisiones oportunas. Gracias a esta concien- ciación del entorno, el sistema es capaz de saber qué situaciones se están dando a su alrededor, conocer qué metas del sistema no están satisfechas y generar un plan en con- secuencia. Para lograr una buena adaptación al entorno, la arquitectura cuenta con una serie de agentes software que supervisan los eventos para detectar metas insatisfechas.

1.5 Lenguajes de especificación de escenarios A lo largo de esta sección, se realizará una explicación sobre los conocimientos básicos de un procesador de lenguaje, así como el estudio de los sistemas existentes de automati- zación, junto a su lenguajes para terminar realizando una descripción de sus diferencias y limitaciones.

1.5.1 ¿Qué es un procesador de lenguaje? Un procesador de lenguaje o compilador es un programa que puede leer un programa en un lenguaje (denominado lenguaje fuente) y traducirlo en un programa equivalente en otro lenguaje distinto (lenguaje destino). Una función muy importante para un compilador es la de detectar y reportar cualquier error en el programa fuente, detectado durante el proceso de traducción [ALSU08].

Otro tipo común de procesador de lenguaje es un intérprete. Este procesador, en vez de traducir un programa de un lenguaje a otro completamente distinto, a partir del programa fuente y una serie de entradas, ejecuta el programa a medida que lo traduce y produce una

11 1. Introducción salida.

Un procesador de lenguaje puede ser descompuesto principalmente en dos procesos, aná- lisis y síntesis.

La parte de análisis divide el programa fuente en distintos componentes, a los cuales se les impone una estructura gramatical, a partir de esta estructura se crea una representación intermedia del programa fuente. Si la parte de análisis detecta que el programa fuente es- tá sintácticamente mal formado, o que posee una semántica inconsistente, debe informar al usuario por medio de diferentes mensajes para que el usuario pueda corregirlos. La parte de análisis recolecta información sobre el programa fuente y la almacena en una estructura de datos llamada tabla de símbolos. La parte de síntesis, haciendo uso de la representación in- termedia y de la tabla de símbolos obtenidas en el proceso de análisis, construye el programa destino.

Cada una de las dos partes que componen un procesador del lenguaje consta de una serie de fases que forman el proceso de compilación, cada una de estas fases transforma una representación del programa fuente en una nueva representación.

La parte de análisis posee las tres primeras fases del procesador de lenguaje:

Análisis léxico: El analizador léxico lee el conjunto de caracteres que componen el programa fuente y los agrupa en diferentes secuencias que tienen significado por si mismas, estas secuencias son conocidas como lexemas. Para cada lexema, el analiza- dor léxico produce una estructura de la forma (nombre-token, valor-atributo), donde nombre-token es un símbolo abstracto y valor-atributo es un apuntador a la tabla de símbolos. Esta estructura es entregada al análisis sintáctico.

Análisis sintáctico: El analizador sintáctico utiliza los componentes producidos por el analizador léxico para crear una representación intermedia en forma de árbol, que describa la estructura gramatical de flujo de tokens. Una representación común es el árbol sintáctico.

Análisis semántico: El analizador semántico utiliza el árbol sintáctico y la informa- ción de la tabla de símbolos con el fin de comprobar que el programa que está siendo traducido posee una semántica correcta según la definición del lenguaje. Una de las partes más importantes de esta fase es la comprobación de tipos, donde el analizador semántico comprueba la correcta correspondencia entre los operadores y sus operan- dos.

Las siguientes tres fases del compilador corresponden a la parte de síntesis:

Generación de código intermedio: Una vez finalizada la fase de análisis, muchos compiladores generan una representación intermedia de código que puede ser similar al código máquina. Esta representación intermedia debe ser fácil de producir y fácil de

12 Lenguajes de especificación de escenarios

traducir en la máquina destino. Optimización de código: En esta fase se intenta mejorar el código intermedio, con el fin de facilitar la generación de un mejor código destino. Por lo general, mejor significa más rápido, pero pueden lograrse otros objetivos, como un código que consuma menos memoria, o un código de destino que consuma menos potencia. Generación de código: El generador de código obtiene una representación intermedia de código, la cual es convertida al código destino. En el caso de que el lenguaje destino sea el código máquina, es necesario realizar una serie de asignaciones a registros y ubicaciones de memoria.

1.5.2 Lenguajes y Sistemas existentes en especificación de automatizacio- nes En el mundo de la domótica y los edificios inteligentes hay una gran variedad de sistemas, frameworks y lenguajes para la especificación de automatizaciones. A pesar de esta gran variedad, es un campo de estudio que no está bien asentado en la actualidad, por ejemplo, hoy en día pocos son los edificios o espacios automatizados. Se puede afirmar, por lo tanto, que la domótica está poco extendida en la vida de las personas. A lo largo de esta sección, se estudiarán y compararán distintos frameworks y sus lengua- jes para la especificación de automatizaciones en espacios inteligentes. Estos frameworks, en ocasiones también son denominados sistemas operativos domóticos. Como podrá observar el lector, ninguno de estos frameworks están fuertemente implantados, la mayoría son muy modernos, algunos aún incluso en vías de desarrollo.

Domoticz Domoticz1, tal y como está definido por sus desarrolladores «es un sistema de automatiza- ción del hogar que permite la configuración y monitorización de distintos dispositivos». Este sistema puede ser usado tanto en Windows, Linux, Mac OS X, Raspberry Pi y dispositivos embebidos. Domoticz esta escrito en C++ y sigue un modelo de código abierto. [Lin] Domticz funciona como un servidor centralizado, en el cual se registran una serie de dis- positivos que enviarán eventos el servidor, el servidor, como respuesta enviará eventos a otros dispositivos registrados, cambiando su estado. Todas las respuestas producidas por el siste- mas son debidas a la ocurrencia de un evento. Para realizar las distintas automatizaciones, este framework cuenta con la posibilidad de usar diferentes lenguajes como Lua, Python, , etc. Todos estos lenguajes permiten definir automatizaciones a partir de cambios en el estado de los dispositivos conectados. Blockly es una manera muy simple para comenzar a realizar automatizaciones y scripting en domoticz. La programación de Blockly se realiza mediante el arrastre y unión de distintos

1http://www.domoticz.com/

13 1. Introducción

bloques lógicos, resultando en una forma muy sencilla e intuitiva de programar, pero poco flexible y que no permite explotar todo el potencial de Domoticz.

Domoticz es capaz de operar también con el lenguaje LUA. En este lenguaje se dispone de varios diccionarios, cada uno de estos diccionarios se indexan con el identificador del dispositivo al cual queremos consultar o modificar sus datos. Los diccionarios principales de los que se dispone son otherDevices y commandArray. En el primero se almacena el estado de todos los dispositivos, en el segundo el estado que deben tener los dipositivos una vez se ejecute el script con las modificaciones pertinentes. Se devuelve el diccionario commandArray al final del script.

Por último Domoticz cuenta con el lenguaje DzVents. Este lenguaje es la última innova- ción de este framework, ha sido desarrollado por los creadores del propio sistema basándose en el lenguaje LUA, facilitando el desarrollo de los scripts sin perder flexibilidad. Estos scripts se dividen esencialmente en dos secciones, la sección on en la que aparecen los even- tos que disparan el script, y la sección execute en la que aparecen las acciones que deben ser tomadas una vez se dispare un evento. Para realizar acciones sobre los dispositivos, al igual que en LUA, se dispone de un diccionario indexado por el id de los dispositivos, al cual se puede acceder por medio de la variable domoticz.devices.

Para el desarrollo de scripts con los tres lenguajes anteriormente mencionados, el frontend del sistema Domoticz cuenta con una serie de asistentes que facilitan su creación.

Un ejemplo escrito en el lenguaje Dzvents para encender un switch cuando la temperatura de la habitación sea mayor a 18 grados y se active otro switch puede ser observado en el Listado 1.1.

1 return { 2 on = { 3 devices = { ’Room switch’} 4 }, 5 execute = function(domoticz, roomSwitch) 6 if (roomSwitch.active and domoticz.devices(’Living room’).temperature > 18) then 7 domoticz.devices(’Another switch’).switchOn() 8 domoticz.notify(’This rocks!’, 9 ’Turns out that it is getting warm here’, 10 domoticz.PRIORITY_LOW) 11 end 12 end 13 }

Listado 1.1: Ejemplo con Domoticz

14 Lenguajes de especificación de escenarios

Home Assistant Home Assistant2 es una herramienta de código abierto, que permite realizar automatiza- ciones para el control de los distintos dispositivos que se puedan encontrar en el entorno. Este sistema está desarrollado en Python y puede ejecutarse en microcontroladores de bajo coste como por ejemplo en la Raspberry Pi [Ass].

Home Assistant funciona como un servidor centralizado, y por medio de buses de eventos obtiene información acerca del estado de los dispositivos registrados y realiza modificaciones en los mismos.

Las automatizaciones son realizadas por medio de scripts, escrito según el formato YAML, y estructurados en reglas. Cada regla se divide en las siguientes tres secciones:

Trigger: Se declaran el evento que va a disparar la regla, un ejemplo de evento puede ser el cambio del estado en un dispositivo.

Condition: Se declaran una serie de condiciones que se deben cumplir para que, una vez disparado el evento que activa la regla, las acciones de dicha regla puedan ejecu- tarse. En el caso en el que se dispare el evento y las condiciones no se cumplan, las acciones no serán ejecutadas.

Action: En esta sección se incluyen todas las acciones que deben tomarse cuando una regla se dispara y se cumplen todas las condiciones.

Una de las mayores ventajas de este framework es la flexibilidad que incorpora, además de la flexibilidad para integrar componentes gracias a las Entities, una especie de plantillas para el registro de componentes de cierto tipo. Por ejemplo, existen Entities para sensores binarios, sensores de clima, switches etc.

Una automatización para apagar todas las luces del entorno cuando el usuario deje la casa puede ser observado en el Listado 1.2.

1 - alias: ’Away Mode’ 2 trigger: 3 platform: state 4 entity_id: group.all_devices 5 to: ’not_home’ 6 action: 7 service: light.turn_off 8 entity_id: group.all_lights

Listado 1.2: Ejemplo con Home Assistant

2https://www.home-assistant.io/

15 1. Introducción openHAB

3 open Home Automation Bus (OPENHAB) es una plataforma para la automatización del hogar de código abierto desarrollado en Java. Este framework permite integrar una gran cantidad de dispositivos, así como dotar al usuario con la capacidad para crear reglas de automatización.

+ Un sistema OPENHAB está compuesto principalmente por los siguientes elementos [ASOT 18].

Things: Son entidades software que representan los dispositivos añadidos al sistema, suelen tener una dirección IP. No tienen por qué ser dispositivos físicos, también pue- den representar cualquier fuente de información y funcionalidad.

Channels: Los canales o Channels son el medio por el cual las Things exponen sus funcionalidades.

Bindings: El propósito de los Bindings es el de crear una conexión entre un dispositivo físico y su Thing correspondiente del sistema. A efectos prácticos un Binding es la interfaz con la que un dispositivo se comunica con el sistema. Suelen ser add-ons que permiten enlazar Items a dispositivos físicos.

Items: Representan las funcionalidades de los dispositivos que pueden ser usadas por un sistema. Este concepto puede ser confundido con el de Thing, pero no son lo mis- mo. Por ejemplo, imaginemos que tenemos un actuador que controla el encendido y apagado de dos bombillas, el actuador sería la Thing y las bombillas los Items.

Links: Es el elemento que permite la unión entre las Things y los Items. El concepto de Link en el sistema se refiere más concretamente a la asociación que hay entre un Channel y un Item. Si un Channel está asociado a un Item, este está habilitado, lo que significa que las funcionalidades que representa el Item son accesibles por medio del Channel. El Channel asociado al Item será el que lo conecte con su Thing correspon- diente.

Las automatizaciones, son escritas en una variante del lenguaje Java denominada Xtend, y están basadas en un sistema de reglas. Cada regla se divide en dos secciones, la sección when y la sección then. En la sección when se añaden una serie de eventos que pueden disparar una regla. En la sección then se añaden las acciones que deben ser tomadas una vez que la regla se ha disparado. Las condiciones de disparo pueden ser, por ejemplo, el cambio del estado de un item, una condición temporal, el inicio del sistema, etc.

Los cambios en el estado de los dispositivos se realizan mediante el envío de comandos por medio de buses de eventos. A las automatizaciones de OPENHAB es posible añadirles funcionalidades propias del lenguaje Java, como pueden ser el uso de variables e incluso el uso de locks.

3https://www.openhab.org/

16 Lenguajes de especificación de escenarios

Calaos Calaos4 es una solución completa para la automatización del hogar escrito en C/C++. Fue desarrollado por una compañía francesa homónima, y desde 2013 este framework es de código abierto. Funciona como un servidor centralizado, y se distribuye como un sistema operativo completo basado en Linux con todos los elementos necesarios preconfigurados. Calaos puede ser instalado en una gran cantidad de dispositivos, como por ejemplo la Rasp- berry Pi. Al igual que otros frameworks similares, Calaos basa sus mecanismos de automatización en un sistema de reglas. Estas reglas pueden ser compuesta a través de una interfaz gráfica o por medio de scripts desarrollados con el lenguaje LUA. El lenguaje LUA usado por Calaos tiene incorporadas ciertas funciones desarrolladas por el propio framework para facilitar las automatizaciones, las funciones más importantes son las siguientes:

calaos:getInputValue(“id”, str): Permite recuperar el valor de la entrada correspon- diente al identificador y almacenarlo en la variable str.

calaos:getOutputValue(“id”, str): Permite recuperar el valor de la salida correspon- diente el identificador y almacenarlo en str.

calaos:setOutputValue(“id”, “value”): Permite asignar el valor “value” a la salida correspondiente el identificador.

En Calaos cuando se habla de entradas y salidas se refiere a dispositivos conectados al servidor, por ejemplo un sensor sería un dispositivo de entrada y un actuador un dispositivo de salida.

Pimatic Pimatic5 es un framework de automatización que provee una plataforma centralizada para la gestión y automatización de tareas en el hogar. Este framework está desarrollado para su integración con Raspberry Pi, y su versión comercial aún está en fase de pruebas. Pimatic provee una interfaz para una gran variedad de dispositivos, una interfaz web intui- tiva para controlar todo el sistema, un lenguaje basado en reglas con el que definir tareas de automatización y una cantidad de plugins para ampliar la funcionalidad del framework. Como se ha comentado anteriormente, Pimatic basa sus automatizaciones en un sistema de reglas, una regla es una cadena de texto del formato “if then”, siendo condition las condiciones para que se ejecuten la regla, y action las acciones que se tomarán una vez se active la regla. Las condiciones pueden estar formados por uno o más predicados, compuestos por operadores lógicos “and” y “or”. Algunos ejemplos de reglas desarrollados por Pimatic se pueden observar a continuación:

4https://www.calaos.fr/en/ 5https://pimatic.org/

17 1. Introducción

if temperature is less than 15 then turn the hvac on

if its 12pm then turn the tv off

if the door is open then turn the light on

Pimatic posee una serie de predicados y acciones incorporados en el framework para una gran variedad de dispositivos y entidades como por ejemplo switches, sensores de presencia, variables... Todos estos predicados y acciones pueden ser ampliados gracias a diferentes plugins.

Xiaomi Aqara La empresa china de tecnología Xiaomi ha lanzado recientemente una serie de dispositivos domóticos para el hogar denominados Xiaomi Aqara6. Estos dispositivos permiten al usuario, de una forma cómoda y sencilla, automatizar su vivienda. Esta línea de dispositivos posee una aplicación para móviles denominada Xiaomi Home, con la que el usuario es capaz de crear de forma gráfica y sencilla automatizaciones para los propios dispositivos fabricados por Xiaomi. Todos los dispositivos son coordinados por un dispositivo central denominado gateway.

Esta aplicación, posee un lenguaje propio con el que se trabaja por debajo para crear las automatizaciones que el usuario define en la interfaz gráfica. Este lenguaje permite definir tanto escenas (una secuencia de acciones) como las automatizaciones previamente comenta- das (secuencia de acciones condicionadas a la ocurrencia de una serie de eventos).

El listado 1.3 presenta una automatización del lenguaje de Xiaomi. Como se puede ob- servar, una automatización está formada por un nombre, un id (positionId), una serie de condiciones que activan la automatización (conditions) y una serie de acciones que se deben tomar cuando se active la automatización. Debido a que este lenguaje no está orientado para que sea usado directamente por los usuarios, su sintaxis es un poco más complicada y menos intuitiva que la de los frameworks anteriores.

El campo did representa una identificador único que posee cada dispositivo de Xiaomi, todas las acciones y triggers que posee un dipositivo pueden ser observadas en la página web de la documentación para desarrolladores de Xiaomi Aqara.

ESPHome ESPHome7 es un framework de automatización diseñado para la creación de firmware en los microprocesadores ESP8266/ESP32 desarrollado en C++. Con este framework se pueden cargar distintos archivos de configuración en nodos ESP del formato ., en los que se

6http://docs.opencloud.aqara.com/en/development/automation-api-demo/ 7https://esphome.io/

18 Lenguajes de especificación de escenarios

1 { 2 "name" : "test", 3 "positionId":"real1.xxxxxxxxx", 4 "conditionRelation": "0", 5 "conditions": [ 6 { 7 "trigger": "TD.lumi.weather.temp_more_than_instant", 8 "did": "lumi.xxxxxx", 9 "model":"lumi.weather.v1", 10 "params": [ 11 { 12 "paramId":"PD.temp", 13 "value":"22" 14 } 15 ] 16 } 17 ], 18 "actions": [ 19 { 20 "did": "lumi.xxxxx", 21 "action": "AD.lumi.gateway.open_corridor_light", 22 "model": "lumi.gateway.aq1", 23 "params": [] 24 } 25 ] 26 } Listado 1.3: Activar la luz del pasillo cuando la temperatura sea superior a 22oC con el lenguaje de Xiaomi

definirá la configuración de la plataforma junto con diversas automatizaciones. La primera carga debe ser por medio de una conexión USB, las siguientes se pueden hacer de forma remota gracias al sistema [ESP].

ESPHome ha sido diseñado en base a Home Assistant, incluso existe un addon para Home Assistant de este framework. Se pueden apreciar muchas similitudes entre estos dos sistemas, la más importante y más notable es el uso de archivos yaml para la creación de automatiza- ciones.

En un archivo de configuración de ESPHome se definen los dispositivos conectados al nodo, y las acciones que se deben tomar cuando en ese dispositivo ocurren ciertos eventos. Cada dispositivo posee un id y se debe indicar al pin del nodo ESP al que está conectado. A continuación se puede observar un ejemplo simple de automatización, en el que cuando se presiona un sensor binario un switch cambia su estado (ver Listado 1.4). Debido a que se van a usar componentes conectados a la propia placa ESP, en estas automatizaciones se hace uso de la plataforma gpio.

ESPHome además cuenta con lo denominado Templates o Lambda que permiten definir condiciones del tipo if (...) ... else ... . La documentación de la página web cuenta

19 1. Introducción

1 switch: 2 - platform: gpio 3 pin: GPIO3 4 name: "Living Room Dehumidifier" 5 id: dehumidifier1

7 binary_sensor: 8 - platform: gpio 9 pin: GPIO4 10 name: "Living Room Dehumidifier Toggle Button" 11 on_press: 12 then: 13 - switch.toggle: dehumidifier1

Listado 1.4: Ejemplo automatización de ESPHome

con una gran variedad de información sobre el uso de esta framework con diferentes dispo- sitivos y sobre las diferentes plataformas que incorpora.

Comparativa de lenguajes El cuadro 1.1 presenta una comparativa de cada uno de los sistemas expuestos anterior- mente, pudiendo observar las bondades y limitaciones de unos respecto a otros con un simple vistazo (Las siglas NS significa que se desconoce la información).

1.6 Sistemas Expertos Un sistema experto es un sistema computacional que permite simular la capacidad de un humano de tomar decisiones. Estos sistemas, están representados por una serie de reglas, y su objetivo es el de resolver problemas complejos por medio del razonamiento con la información que poseen. Los sistemas expertos son considerados la primera forma de inte- ligencia artificial satisfactoria, aunque algunos expertos no la consideran como tal, ya que estos sistemas no son capaces de aprender. Sus principales componentes son el cuerpo de conocimiento formado por un conjunto de reglas y de hechos y el motor de inferencia el cual aplica las reglas a los hechos del sistema con el fin de realizar deducciones [GR04].

En la actualidad, muchos son los sistemas expertos existentes, algunos ejemplos represen- tativos con CLIPS y PyKnow

1.6.1 CLIPS

C Language Integrated Production System (CLIPS) es un sistema experto que permite faci- litar el desarrollo de software para modelar el conocimiento y la experiencia de las personas escrito en C. El principal modo de representar conocimiento en CLIPS es por medio de un conjunto de Reglas, aunque también disponga de herramientas como la definición de funcio- nes y la programación orientada a objetos. CLIPS posee la capacidad para ser integrado con otros lenguajes procedurales, como lo pueden ser C++, Java, C, Objective-C, etc. [Gia07]

20 Sistemas Expertos

CLIPS esta compuesto principalmente por una lista de hechos, que contiene el «estado del mundo», una base de conocimiento con el conjunto de reglas definidas por el usuario y un motor de inferencia que controla la ejecución de las reglas en base a la lista de hechos. Para crear un modelo con CLIPS se dispone de la capacidad para definir hechos, plantillas, funciones y la capacidad de almacenar variables.

Como ya se ha comentado, los principales elementos de CLIPS son las reglas y los hechos por lo que a continuación se verá cómo utilizar ambos.

Un hecho se define por un conjunto de varios campos, por ejemplo (Juan mayor-que Luis) es un hecho formado por tres campos, a CLIPS no le importa la semántica que el usuario quiera darle a un hecho, simplemente reconocerá un hecho por los valores que este contiene. Para incluir un hecho en la lista de hechos del sistema se usa la palabra clave assert, de este modo, un hecho se puede incluir ejecutando (assert (Juan mayor-que Luis)). Los hechos anteriormente mencionados son hechos sin etiqueta, mediante el uso de lo que denomina CLIPS plantilla podríamos definir hechos con campos etiquetados, en los que podríamos de- finir incluso el tipo de dato(float, integer, string...) que debe tener cada campo. Las plantillas son definidas por medio de la instrucción deftemplate. A parte de poder incluir un hecho con assert, se pueden incluir varios hechos al mismos tiempo haciendo uso de la instrucción deffacts.

Una regla en CLIPS tiene el formato if-then, esto significa que una regla está formada por una serie de condiciones que se deben cumplir para que se ejecuten una serie de acciones. Las parte de las condiciones es denominada LHS y la parte de las acciones RHS. En la parte LHS se definen los hechos que deben esta incluidos en la lista de hechos para que al regla pueda ser ejecutada. En la parte RHS se definen las acciones que deben ser tomadas una vez se cumplan las condiciones de la regla, estas acciones pueden ir desde la ejecución de instrucciones, a la modificación, inclusión o eliminación de algunos hechos. En el Listado 1.5 se puede observar un ejemplo de una regla definida con CLIPS, en la que la luz de una habitación se enciende cuando se detecta movimiento.

1 (defrule light automation 2 (motion True) 3 (light off) 4 => 5 (light on)

Listado 1.5: Ejemplo de regla con CLIPS

21 1. Introducción

1.6.2 PyKnow PyKnow8 es una librería de python que permite la construcción de sistemas expertos inspi- rados en CLIPS. Sus fundamentos son prácticamente los anteriormente explicados con CLIPS, este módulo de python posee una lista de hechos, un motor de inferencia y una base de cono- cimiento. Las diferencia más relevante respecto a CLIPS es la sintaxis, además de un motor de inferencia mucho menos sofisticado. La principal ventaja que aporta PyKnow respecto a otros sistemas expertos es su capacidad para explotar las características de Python, a la vez que se comporta como un auténtico sistema experto, pudiendo sacar todo el potencial tanto de los sistemas expertos como de la orientación a objetos. Los hechos en PyKnow son definidos por medio de la clase Fact, la cual en esencia se comporta como un diccionario. Existe la posibilidad de que una clase definida por el usuario pueda utilizarse como un hecho gracias a la herencia de clases, cualquier subclase de Fact es un hecho. La definición de reglas en PyKnow puede parecer algo extraño. La definición de la parte LHS se realiza por medio del decorador @Rule, donde se incluirían los hechos que ejecutarían la regla. Por otro lado, la parte RHS se incluye en el método decorado. En el Listado 1.6 se puede observar una regla muy simple, la misma regla anteriormente definida con CLIPS.

1 @Rule( 2 AND( 3 AS.motion << Fact(name=’motion’, status=’True’), 4 AS.light << Fact(name=’light’, status=’off’) 5 ) 6 ) 7 def turn_on_when_presence(self, motion, light): 8 self.modify(light, status=True)

Listado 1.6: Regla con PyKnow

1.7 ZeroC Ice

Internet Communication Engine (ICE) es un middleware de comunicaciones, desarrollado por la compañía ZeroC. Este middleware posee una gran flexibilidad, ya que soporta un número variado tanto de lenguajes como de plataformas [VFA16]. A la hora de crear un objeto remoto para cualquier middleware, es necesario definir un contrato entre el cliente y el objeto remoto o servidor, en otras palabras, el protocolo usado por las dos partes para comunicarse. Los middlewares permiten el usuario definir una interfaz por medio de una lenguaje de programación de estilo declarativo, a partir de la cual, un com- pilador genera el código que contiene toda la lógica necesaria para serializar y deserializar 8https://pyknow.readthedocs.io/en/stable/

22 ZeroC Ice los mensajes. En Ice, este lenguaje de especificación se denomina Specification Language for

Ice (SLICE), y proporciona translators (compiladores de interfaces) para todos los lenguajes soportados.

1.7.1 Conceptos básicos de Ice

9 ICE contiene una serie de términos y conceptos propios que pueden resultar ajenos al lector. A continuación se dará una descripción breve de esta terminología para facilitar al lector la comprensión de este documento [Fer06].

Cliente: Entidad activa que solicita servicios a objetos remotos mediante la invocación de métodos.

Servidor: Entidades pasivas que inicializan y activan sus recursos para poner distintos objetos a disposición de sus clientes.

Objeto ICE: Entidad conceptual o abstracción, que se encuentra en un espacio de di- recciones local o remoto y que es capaz de responder a las peticiones de los clientes.

Las invocaciones que se pueden realizar a un objeto ICE son aquellas definidas en una

interfaz. Un objeto ICE puede implementar diferentes interfaces conocidas como face- tas, un cliente puede elegir que faceta utilizar para trabajar con el objeto remoto. Por

último, un objeto ICE tiene una identidad única, que lo distingue del resto de objetos.

Proxy: Componente que se encuentra en el espacio de direcciones local del cliente, y que representa un posible objeto remoto. Actúa como representante local de un objeto. El proxy almacena toda la información necesaria para direccionar el servidor correcto, identificar el objeto concreto en el servidor a partir de la identidad y la información sobre la faceta con la que se invoca el objeto. Se pueden distinguir los siguientes tipos de proxies:

• Proxies textuales: La información asociada el proxy es representada como una cadena. • Proxies directos: Proxy que encapsula la identidad de un objeto junto a la direc- ción del servidor en el que se encuentra. • Proxies indirectos: Estos proxies pueden proporcionar solo la identidad o espe- cificar la identidad junto con el identificador de un adaptador de objetos. Los objetos que son accesibles proporcionando únicamente su identidad son objetos bien conocidos. • Proxies fijos: Proxy asociado a una conexión en particular, estos proxies contie- nen un manejador de conexión.

9https://zeroc.com/products/ice

23 1. Introducción

1.7.2 IceGrid

Junto a todos los servicios que incluye ICE, uno de los más importantes es IceGrid. Ice- Grid contiene una gran cantidad de funcionalidades para el manejo y gestión de los objetos remotos.

IceGrid depende de una base de datos, denominada IceGrid Registry, que contiene la información de todos los objetos remotos que forman el sistema distribuido así como de los nodos del sistema. Un Registry es exclusivo en una aplicación distribuida, la existencia de más de uno conllevaría que existe más de una aplicación distribuida.

Cada nodo de computo que forme parte de la aplicación distribuida debe ejecutar una ser- vicio llamado Icegrid Node, de modo que IceGrid pueda conocer que nodos están disponibles para la ejecución de componentes de la aplicación.

IceGrid posee una serie de herramientas de administración que se pueden usar para con- trolar sus características. Estas herramientas son icegridadmin, una aplicación de línea de comandos, y icegridgui, una aplicación con interfaz gráfica.

Por útlimo, IceGrid maneja una serie de conceptos que es importante conocer:

Nodo: Se refiere a una instancia de IceGrid Node, y se corresponde con un nodo lógico. No es obligatorio que corresponda con un computador físico, ya que un computador puede poseer varios nodos, perteneciendo a la misma o a distintas aplicaciones.

Servidor: Programa que va a ser ejecutado en un nodo, identificado por un nombre único. Este programa incluye todos los atributos y propiedades necesarios para su con- figuración.

Adaptador de objetos: Contiene todos los datos específicos de un adaptador de obje-

tos utilizado en un servidor de ICE, como por ejemplo la información acerca de los endpoints, objetos bien conocidos, etc.

Aplicación: Conjunto de servicios y objetos que junto a sus configuraciones forman la aplicación distribuida. La descripción de una aplicación IceGrid puede ser almacenada en archivos XML o en la propia base de datos de IceGrid.

1.7.3 IceC

ICE for C language (ICEC) es un middleware de comunicaciones, escrito en C/C++, y dise- ñado para dispositivos pequeños que posean una serie de restricciones tanto de procesador, memoria, como de uso de ancho de banda.

Algunas de las características que posee ICEC son su portabilidad, ya que para usarlo única- mente es necesario un compilador de C. Es extensible con una gran variedad de plugins y per- mite el uso de endpoints para una gran variedad de protocolos. No requiere de una plataforma hardware compleja, IceC puede ser implementado para un dispositivo simple como un mi-

24 ZeroC Ice crocontrolador ESP8266, hasta dispositivos más complejos como una Field-Programmable Gate Array (FPGA), gracias a su buena gestión de los recursos de cómputo.

Una de las mayores ventajas de estos middlewares, es su compatibilidad con ICE, soporta todos sus servicios principales, así como la versión 1.0 del protocolo de cifrado. El lenguaje de definición de interfaces de ICEC es el mismo que el de ICE, con todas sus características básicas, propiciando una buena comunicación entre los programas escritos en ICE e ICEC.

25 1. Introducción

Cuadro 1.1: Tabla comparativa de los principales sistemas de automatización ESPHOME xxx x x x x x x x x x x Xiaomi Aqara x x x x x Pimatic x x x x x x x x x Home Assistant OpenHAB xx x xx x x x x x x x x xx x x x x x x x xx x x x x x Calaos 52.5 2 1 3 3 4 2 2 3.5 2 3 3 3 x x Domoticz C/C++dzvents C/C++ Java LUA Xtend Python YAML CoffeeScript NS NS NS C/C++ y Python YAML Iteradores sobre los dispositivos Acceso al dispositivo disparador por medioDefinición de de variables variables de usuario Tipado de los elementos Funciones propias del lenguaje Flexibilidad(1-5) Facilidad de uso(1-5) Registro (log) de eventos Uso de secuencias condicionales(and y or permitido) Comprobar y modificar el estado deEjecutar un una grupo acción de durante dispositivos un intervalo de tiempo Disparar eventos según un estado deDisparar seguridad eventos según el estado delUso sistema de múltiples disparadores para una automatización Modificar el estado de un dispositivo Disparar un evento cuando el estadoDisparar de una un acción dispositivo cuando cambie se ejecutenDiferenciar ciertos que eventos evento disparó una regla Disparar eventos en ciertos instantes de tiempo Framework Source code Lenguaje Acceder al estado de los dispositivos 26 Capítulo 2 Objetivos

N el presente capítulo, se procederá a la descripción de los diferentes objetivos que E se estudiaron realizar al inicio de este TFG. Estos objetivos estarán divididos en un objetivo general, que a continuación será desglosado en los diferentes objetivos específicos asociados al alcance del proyecto que se plantea.

2.1 Objetivo general El principal objetivo de este proyecto es el de la creación de un lenguaje de programación que permita la especificación de escenarios de automatización en el contexto de los entornos inteligentes. Este lenguaje permitirá la composición de los distintos servicios y dispositivos involucrados para cubrir las necesidades del usuario.

2.2 Objetivos específicos Para conseguir elaborar el lenguaje de especificación de escenarios de automatización en espacios inteligentes y así cumplir con el objetivo general, es necesario abordar los objetivos específicos que se detallan a continuación.

2.2.1 Estudio de lenguajes y Sistemas existentes El campo de la domótica y los espacios inteligentes es un campo en auge, cada día son más las tecnologías que surgen en torno a esta temática, y los lenguajes y sistemas de auto- matización no son una excepción. Como paso previo a afrontar la creación del lenguaje de especificación de escenarios, se procederá el estudio y comparación de los distintos sistemas de automatización que hay en el mercado, detectando sus diferencias y limitaciones, para comprender que requisitos son necesarios para un sistema de estas características y los retos que plantean.

2.2.2 Estudio de las necesidades de automatización Creación de distintos ejemplos de automatización concretos, para detectar las posibles carencias de los lenguajes existentes a la hora de crear automatizaciones. Este estudio será usado para definir que funcionalidades son interesantes y debe incorporar al lenguaje que vamos a diseñar.

27 2. Objetivos

2.2.3 Diseño del lenguaje de especificación Tomando como referencia los estudios de lenguajes anteriores, el siguiente objetivo es diseñar la sintaxis y semántica que tendrá nuestro lenguaje. Para hacer el lenguaje lo más intuitivo para el usuario, el diseño de la sintaxis será conducido con el desarrollo de ejemplos, cada ejemplo con distintas sintaxis, eligiendo aquellas sintaxis más simple, descriptiva e intuitiva.

2.2.4 Desarrollo del procesador de lenguaje A partir de la sintaxis definida para el lenguaje, hay que desarrollar un compilador o pro- cesador de lenguaje que sea capaz de leer el contenido de los escenarios de automatización descritos con nuestro lenguaje, analizar su contenido, y comprobar que tanto la sintaxis como la semántica es la correcta. Una vez verificado un programa escrito con el lenguaje, transfor- mará el código de entrada en un código escrito en el lenguaje destino del compilador, el cual permitirá llevar a la realidad el escenario definido.

2.2.5 Diseño y desarrollo del sistema de despliegue Una vez obtenido el código generado por el procesador del lenguaje, hace falta provisionar los componentes necesarios para llevar el escenario inicialmente definido a la realidad. Esta tarea consistirá en la instanciación automática de unos componentes intermedios, que pode- mos denominar operadores, que realizarán la composición y serán enlazados a los diferentes servicios para comunicarlos y hacer efectivo el escenario.

2.2.6 Elaboración de escenarios de ejemplo Una vez se tenga el sistema en un estado funcional, elegir casos de uso para ponerlo en práctica y demostrar que el funcionamiento es el deseado. El caso de uso elegido será el de control de la temperatura en edificios inteligentes y su provisionado automático. Para llevar a cabo este escenario, se integrarán un sensor de temperatura del fabricante Xiaomi y un dispositivo de control para un HVAC fabricado desde cero, con el objetivo de demostrar la posibilidad de integración de componentes de distintos fabricantes en el sistema desarrolla- do.

28 Capítulo 3 Método

Lo largo de las próximas páginas se realizará una explicación sobre la metodología de A desarrollo elegida, junto a la justificación de su elección. Una vez el lector comprenda la metodología se explicará cual será su funcionalidad en este proyecto y la forma en la que será aplicada.

3.1 Metodología de Prototipado Se denomina Metodología de Prototipado de Software a la actividad de crear versiones incompletas de software, denominados prototipos. Esta metodología fue primeramente desa- rrollada en diversos campos de la ingeniería, para más tarde ser aplicada en el software. Esta metodología aporta un conjunto importante de ventajas:

El desarrollador puede obtener información valiosa de los usuarios en un estado tem- prano del proyecto. Se puede comprobar, conforme se va desarrollando el producto, si este cumple con las especificaciones. Ayuda al desarrollador a hacer una estimación del tiempo buena y precisa, pudiendo calcular satisfactoriamente si los plazos e hitos se van a cumplir.

Dos aspectos muy importantes sobre los prototipos son, que no es necesario que ejerzan el mismo trabajo que la aplicación final y que no tienen porque implementar todas las funcio- nalidades que tendrá el sistema. Si un prototipo tuviese las mismas funcionalidades que la aplicación final, sería la aplicación final, en cambio su objetivo es el de darles a los usuarios un vistazo de como se verá el sistema una vez desarrollado.

3.1.1 Prototipos Cuando hablamos de Prototipos en ingeniería del software nos referimos a un modelo de parte o de toda la aplicación. Este prototipo permite darle a los usuarios una idea intuitiva de como se verá y como se comportará el software, de una forma mucho más clara que con el uso de casos de uso o historias de usuario[Ste15]. Un prototipo funcional se comportará como la aplicación final, a pesar de que realmente,

29 3. Método el prototipo tendrá componentes que simplemente simularán que funcionan, pero esto real- mente no será así. Es posible por ejemplo que el prototipo trabaje con ficheros de texto en lugar de una base de datos, o incluso que cierta funcionalidad sea la utilización de una serie de datos hard-coded. La construcción de un prototipo permite definir nuevos requisitos y redefinir aquellos ya existentes. Un prototipo puede ser mostrado a un usuario, permitiendo obtener una informa- ción muy valiosa sobre su opinión actual del producto, pudiendo concluir que es necesario mejorar. Existen principalmente dos tipos de prototipos:

Prototipo Horizontal: Muestra la mayoría de las funcionalidades de la aplicación final pero con una implementación muy ligera. Por ejemplo, un prototipo horizontal sería una interfaz de usuario que por debajo simula toda la funcionalidad. Prototipo Vertical: Prototipo de poca amplitud, que posee muy pocas funcionalidades pero que están muy bien refinadas.

3.1.2 Variantes de modelos de prototipado Los modelos de prototipado de software poseen una serie de variantes, basadas principal- mente en los modelos de prototipado desechable y evolutivo[Smi91].

Prototipado desechable: En esta variante los prototipos acabarán siendo desechados, en lugar de ser incorporado en el producto final. La única finalidad de estos prototipos es la de construir un modelo simple del sistema, que permita a los usuarios ver vi- sualmente como se verá el sistema cuando esté funcionando, pero estos prototipos no aportan ninguna funcionalidad. La principal razón para elegir esta variante de prototi- pado, es la capacidad de obtener prototipos de una forma rápida y poder obtener una retroalimentación lo más pronto posible. En una fase temprana del desarrollo, realizar cambios en el software no es muy costos, en este punto es donde reside el valor de los prototipos desechables. Prototipado evolutivo: El principal objetivo de este tipo de prototipado es construir prototipos robustos de una forma estructurada y constantemente refinada. En este enfo- que, el prototipo será el núcleo del sistema, sobre el que se irán añadiendo y refinando los requisitos. Estos prototipos son sistemas funcionales, a los que se les agregarán características hasta llegar al punto de obtener el sistema final. Prototipado incremental: El producto final es desarrollado como diferentes prototi- pos, que más tarde son combinado en el diseño final. Prototipado extremo: El prototipado extremo, cuando se habla de desarrollo, es usado principalmente para el diseño de páginas web. Esta clase de prototipado se divide en tres fases, la primera fase con un prototipo estático, en la segunda se añade una capa de

30 Prototipado Evolutivo

simulación de servicios para obtener una funcionalidad y en la última fase los servicios son implementados.

3.2 Prototipado Evolutivo El Modelo de Prototipado Evolutivo es un modelo en el que el sistema es desarrollado en incrementos, basándose en la retroalimentación que los usuarios ofrecen sobre el sistema. A partir de la información obtenida, los prototipos pueden ser modificados apropiadamente, en respuesta a la opinión de los usuarios[McC96]. El prototipado permite desarrollar partes seleccionadas del sistema, para después, a partir de estas partes, evolucionar hasta obtener el resto del sistema. Siguiendo esta metodología, los prototipos van evolucionando hasta que se obtiene el sistema completo. En este modelo de desarrollo, los riesgos más altos de la aplicación son tomados al prin- cipio del desarrollo, si estos riesgos pueden ser abordados, el prototipo puede evolucionar hacia el sistema final, si estos riesgos no pueden ser tomados, el proyecto puede ser cancela- do sin necesidad de haber invertido más dinero del necesario para descubrir que el proyecto no era abordable. El prototipado evolutivo es una actividad usada principalmente cuando no se sabe que se necesita desarrollar con exactitud. Para comenzar el desarrollo, el primer paso es definir que parte del sistema será usada como punto de partida, para a partir de ahí, agregar funcionali- dades hasta obtener el sistema final. Se podría considerar que existen dos clases de prototipado evolutivo, el que dirige sus esfuerzos al cliente y el que sus esfuerzos son orientados a la técnica.

Prototipado dirigido al cliente: El prototipo es desarrollado en base a la información que se recibe de los cliente, de este modo, al prototipo se la agregan funcionalidades hasta que todos los clientes consideren que el prototipo cumple con todos los requisitos del sistema final. Prototipado orientado técnicamente: En este modelo, se desarrolla un prototipo ini- cial con una funcionalidad básica que forme parte del sistema final al igual que en el resto de modelos, pero en este caso no se obtienen comentarios de ningún cliente sino que se les va agregando funcionalidades, a la vez que se comprueba su comportamien- to y rendimiento. Los cambios en el prototipo son basados en los resultados de estas comprobaciones.

3.3 Desarrollo Dirigido por Tests (TDD)

Test Driven Development (TDD) o Desarrollo Dirigido por Tests es una técnica de desa- rrollo e implementación para diseñar software incluida en la metodología XP [Jur10]. TDD permite el desarrollo de software que posee principalmente tres características:

31 3. Método

La implementación de las funciones es la mínima posible. No se codifican funcionali- dades que nunca será usadas.

El número de defectos del software en fase de producción de mínimo.

El resultado de aplicar TDD es un software modular, reutilizable y abierto a cambios.

Puede parecer que el objetivo es el de crear una gran batería de pruebas que cubra todo el código posible, pero esto en realidad de una consecuencia del uso de TDD. Su auténtica finalidad, es la de adecuar el desarrollo de software a los requisitos, obteniendo un software de alta calidad. TDD será la herramienta que guíe nuestra implementación, a partir de los ejemplos aportados por los tests, se descubrirá que implementación es la más apropiada para obtener la funcionalidad deseada.

La aplicación de TDD se divide principalmente en tres pasos, 1) Escribir los requisitos en forma de Test, 2) Implementar la funcionalidad que haga pasar la prueba, 3) Refactorizar para eliminar duplicidades, solucionar errores y añadir mejoras.

TDD es una técnica de desarrollo que encaja muy bien con la metodología de prototipa- do evolutivo, añadir funcionalidades a un prototipo se puede mapear a escribir los tests e implementar el código para hacer que estos pasen. Además gracias a los test producto de TDD, cuando se agregue una nueva funcionalidad, simplemente ejecutando los tests, se sa- brá si las funcionalidades del prototipo anteriormente implementadas siguen funcionando correctamente.

3.4 Justificación y Aplicación de la metodología Debido a la naturaleza del problema presentado, y dada la complejidad del desarrollo de software se ha decidido hacer uso del prototipado evolutivo.

Debido a la complejidad que se planteaba para este proyecto, era necesario tener un siste- ma funcional lo más pronto posible que fuese un referente para continuar el desarrollo. La metodología de prototipado, como se ha explicado anteriormente, permite obtener sistemas funcionales en cuanto se haya desarrollado el primer prototipo.

Además, como el proyecto tiene un alcance demasiado grande, usar prototipado evolu- tivo permite tener un pequeño sistema funcional desde el desarrollo del primer prototipo. Realizar un sistema más complejo se basará en aumentar la complejidad y agregar las carac- terísticas necesarias al sistema. Al tener este alcance tan grande, realizar el sistema con otra metodología resulta inviable, ya que conlleva asumir el riesgo de que, una vez terminado el sistema, se haya abordado un lenguaje tan complejo y que ofrece tantas posibilidades, que sea imposible poner el sistema en práctica.

Por último, usar otra metodología requiere de unos conocimientos que no se poseían sobre la planificación del proyecto, los problemas que pueden surgir y los riesgos que se deben

32 Herramientas asumir en el desarrollo. La aplicación del prototipado evolutivo será realizada por medio de iteraciones, en cada iteración se obtendrá un prototipo funcional con una serie de características nuevas, y con las modificaciones pertinentes que han propiciado estas nuevas características para que el prototipo funcione. En cada iteración, las funcionalidades serán implementadas por medio de la aplicación de TDD.

3.5 Herramientas En la siguiente sección se presentarán todas las herramientas que serán usadas, tanto hard- ware, como software que han tenido que ser usadas para el desarrollo completo del proyecto. Junto a este listado de las herramientas se incluirá una breve descripción de sus característi- cas y propósito en el proyecto.

3.5.1 Herramientas Hardware Las herramientas hardware usadas a lo largo del proyecto han sido las siguientes:

Ordenador de Sobremesa: Ordenador con un Procesador Intel Core i5-760, HDD de 500 GB y 8 GB de RAM. Ordenador portátil: Portátil ASUS, Procesador Intel Core i3-5005U, HDD de 500 GB y 4 GB de RAM. Máquina de impresión LPKF: Máquina de impresión de Placas de Circuito Impreso (PCB) de la empresa LPKF.

Centralita Mistubishi Electronics: Sistema HVAC para el control térmico del entorno. Estación de soldadura: Estación con las herramientas necesarias para soldar compo- nentes Surface Mounted Device (SMD) a un PCB. Xiaomi Aqara: Conjunto de dispositivos domóticos de Xiaomi, que permiten automa- tizar ciertas características del entorno con el uso de la aplicación Xiaomi Mi Home.

NodeMCU: Plataforma IOT de código abierto que posee un microprocesador ESP8266 con un módulo WiFi integrado.

3.5.2 Herramientas Software Sistema Operativo y Lenguajes de Programación Como sistema operativo se ha hecho uso de Debian 9.0 Stretch, un sistema operativo con núcleo Linux, formado principalmente por software libre y de Windows 10, sistema operativo de la familia Windows NT desarrollado por Microsoft, Como lenguaje de programación se han usado dos principalmente, Python un lenguaje interpretado y multiplataforma en su versión 3.5.3 como lenguaje principal y C/C++ para la programación de microcontroladores debido a su eficiencia.

33 3. Método

Aplicaciones Visual Studio Code1 Editor de código desarrollado por Microsoft, que cuenta con una gran cantidad de extensiones, con el fin de facilitar la programación al usuario en una gran cantidad de lenguajes.

LATEX: Sistema de composición de texto, que permite la creación de documentos cien- tíficos de forma sencilla y con una alta calidad tipográfica. TexMaker: Editor cuyo propósito es escribir documentos de texto haciendo uso del sistema LATEX. Integra muchas de las herramientas necesarias para el desarrollo de documentos escritos en LATEX. Inkscape: Editor de gráficos vectoriales, usado para crear y editar todo tipo de imáge- nes y gráficos en un formato vectorial y escalable. Es una herramienta multiplataforma, presente en Windows, Mac OS X y GNU/Linux. Bitbucket2 Sistema de control de versiones basado en web que permite planificar pro- yectos y colaborar en el desarrollo de código. Platform IO: Plataforma de código abierto que facilitar el desarrollo de código para

soluciones IOT. Disponible como extensión para Visual Studio Code (VSCODE). Xiaomi Mi Home: Aplicación que permite controlar los dispositivos domóticos de Xiaomi. DesignSparkPCB3 Software de diseño electrónico totalmente gratuito, que permite el

diseño de PCBS para su posterior impresión.

1https://code.visualstudio.com/ 2https://bitbucket.org 3https://www.rs-online.com/designspark/pcb-software

34 Capítulo 4 Desarrollo del Proyecto

N el próximo capítulo se hará un resumen sobre como ha sido orientado el trabajo, apli- E cando una metodología de prototipado evolutivo, hasta cubrir los objetivos planteados inicialmente para este proyecto. Principalmente, el proyecto surge de la necesidad de auto- matizar el control térmico de un entorno, donde la principal complejidad será dotar al entorno de inteligencia hasta obtener un escenario domótico totalmente automatizado. Este capítulo estará divido en diferentes iteraciones, representando las distintas funcionalidades que se han conseguido realizar en orden cronológico, dando resultado a distintos prototipos.

El proyecto, comprende desde la elección de un escenario donde automatizar el entorno para satisfacer el confort térmico del usuario, pasando por el desarrollo de un sistema para dotar al entorno de inteligencia, hasta tener implementado en el escenario un caso de uso totalmente funcional.

4.1 Iteración 1: Desarrollo de la placa de control El escenario elegido para implementar la solución de control térmico ha sido el laboratorio de investigación del grupo ARCO situado en el Insituto de Tecnologías y Sistemas de la Información (ITSI) de la Universidad de Castilla-La Mancha (UCLM). Para poder realizar un control térmico del laboratorio, el primer paso es poder cambiar la temperatura del entorno a voluntad, esto se realizará por medio de un nodo que controlará el Heating, Ventilation and Air-Conditioning systems (HVAC) del propio laboratorio. El nodo consistirá en una placa de control, controlada por un procesador ESP8266.

Por lo tanto, esta primera iteración consiste en el diseño y fabricación de una placa de con- trol, que integrada con un microprocesador ESP8266, pueda controlar un dispositivo HVAC, modificando la temperatura y el encendido y apagado del dispositivo. Esta placa fue diseña- da para ser compatible con el HVAC de Mitsubishi situado en el laboratorio, su esquemático puede ser encontrado en el AnexoB. El microprocesador ESP fue aportado por un módu- lo NodeMCU ya que es una solución barata de microprocesador con WiFi para soluciones

IOT.

Para la fabricación de esta placa, se hizo uso de la herramienta de diseño de Placas de Circuito Impreso (PCB) DesignSparkPCB y de una máquina de fabricación LPKF. Todo el

35 4. Desarrollo del Proyecto proceso, tanto de fabricación, diseño e instalación, puede ser encontrado en el AnexoA.

Tras la fabricación, se llevo a cabo un proceso de aprendizaje de la programación del microcontrolador ESP8266, así como del uso del middleware para sistemas de bajas presta- ciones ICEC.

4.2 Iteración 2: Estudio de sistemas de automatización

En esta iteración, se llevó a cabo un proceso de reflexión sobre como dotar de inteligencia y automatizar el escenario de confort térmico, contando con la placa de control fabricada en la Sección 4.1, y con diferentes sensores de temperatura.

Al final, se concluyó que el modo más apropiado de automatizar el escenario que se nos presentaba era el de diseñar un sistema, el cual poseyese un lenguaje y su correspondiente compilador que permitiese al usuario especificar escenarios de automatización en su entorno. El diseño de este lenguaje propiciaría una solución flexible, aplicable a una gran variedad de escenarios, sin necesidad de aplicarlo obligatoriamente al confort térmico, pudiendo au- tomatizar entornos inteligentes de una manera sencilla. Este sistema fue nombrado como Automaker, formado por el lenguaje scn que permitiese al usuario escribir automatizaciones, y un compilador, que a partir del código fuente scn genere un lenguaje destino de provisio- nado, denominado prv, que realizará los despliegues necesarios para la automatización. El concepto provisionado se refiere a la instanciación de los componentes necesarios para llevar a cabo la automatización.

Para afrontar la creación de este sistema, se procedió a la investigación y estudio de los sistemas de automatización domóticos y de entornos inteligentes que hay en el mercado. La finalidad de este estudio fue la de conocer si había algún lenguaje que fuese útil para nuestro desarrollo, así como para conocer las características, limitaciones y bondades de estos sistemas. El resultado de este estudio puede ser observado en la Sección 1.5.2.

Con los resultados del estudio, se concluyó que el sistema de automatización buscado, en esencia se podía reducir a un sistema de reglas, como lo pueden ser algunos sistemas expertos como CLIPS y PyKnow, por lo que también se estudiaron este tipo de sistemas (ver Sección 1.6).

El lenguaje scn con el que el usuario definirá los escenarios de automatización, a efectos prácticos, puede parecer un motor de inferencia con hechos del mundo real, por lo que se decidió que este lenguaje estuviese inspirado en CLIPS, permitiendo definir automatizaciones y desplegarlas al mundo real a partir de una serie de reglas. Este lenguaje será escrito en el lenguaje de programación Python, debido a su gran flexibilidad.

36 Iteración 3: Sintaxis del lenguaje scn

4.3 Iteración 3: Sintaxis del lenguaje scn

El primer paso en el desarrollo del sistema Automaker será crear el lenguaje scn, definien- do su sintaxis y desarrollando los mecanismos necesarios para capturar la información del código fuente escrito por el usuario, por medio de introspección. Debido a que el lenguaje a desarrollar se va a basar en un sistema de reglas que repre- sentarán las automatizaciones, la primera tarea a realizar será la creación del concepto regla y de una clase escrita en Python que represente lo denominado Rule. Una regla, represen- tará una automatización que quiere realizar el usuario y ha de estar formada por una serie de condiciones que se deben cumplir para ejecutar la escena y una serie de acciones que se ejecutarán en el caso de que se cumplan las condiciones. El formato elegido será el presente en el Listado 4.1. Cabe destacar la influencia del sistema experto CLIPS a la hora de definir esta sintaxis.

1 Rule( 2 event, 3 condition_1, 4 condition_2, 5 condition_3, 6 [...] 7 )( 8 action_1, 9 action_2, 10 action_3, 11 [...] 12 )

Listado 4.1: Sintaxis de una regla

Para implementar esta sintaxis en Python de la manera apropiada, la clase Rule hará uso de dos métodos, el método __init__, para añadir el evento y una serie de condiciones a una regla, y el método __call__ para añadir las acciones. Tanto las acciones como las condiciones necesitan un mecanismo para poder comprobar cuando son válidas o e invalidas, para ese fin, en el caso de las condiciones se ha desarrollado la clase Statement, representando un enunciado que representa un hecho de la realidad. Por otro lado para las acciones se ha creada una clase homónima Action, representando una modificación del estado del mundo real.

La inclusión de una condición o una acción errónea que no sean del tipo Statement y Action respectivamente, ocasionaría la elevación de las excepciones InvalidCondition o In- validAction, informando al usuario del error, para que pueda realizar las transformaciones pertinentes al código fuente en el que se ha aplicado el compilador. La implementación de la clase Rule está detallada en el Listado E.1. Una vez sentadas las bases del lenguaje y de lo que sintácticamente representa una regla, se

37 4. Desarrollo del Proyecto decidió profundizar un poco en la semántica que ofrecía la definición de una regla. Hasta el momento, una regla se compone de una serie de condiciones, instancias de la clase Statement, y una serie de acciones las cuales son instancias de la clase Action.

4.3.1 Modelado de condiciones Dentro de las condiciones hay que diferenciar un elemento muy importante para una au- tomatización; este es el evento. Un evento, es en si un cambio en el estado de un elemento, objeto o dispositivo del mundo real que puede disparar una regla. Un evento podría ser con- siderado una condición, pero hay que tener claras sus diferencias, una condición es un estado del mundo real, un hecho, en cambio, un evento es una modificación del estado de un ele- mento del mundo, en un momento determinado, que produce que se dispare una regla. Puede darse el caso en el que un evento dispare una regla, pero al no cumplirse las condiciones res- tantes, las acciones de la regla no se ejecuten (señalar que no es lo mismo la ejecución de una regla, que la ejecución de sus acciones).

Un ejemplo para aclarar la diferencia entre una condición y un evento puede ser el siguien- te. Imaginemos una habitación con un sensor de presencia, cuya automatización sea que se encienda la luz cuando haya alguien en la habitación y sean mas de las 21:00. El evento sería un mensaje del sensor de presencia indicando que hay alguien en la habitación, la condición para que se encienda la luz una vez se ha disparado la regla sería que fuesen más de las 21:00 de la noche.

Para modelar un evento en este lenguaje se ha creado una subclase de Statement denomi- nada Event. En su constructor recibe un Statement que contiene un enunciado que representa un dispositivo y el estado de dicho dispositivo que dispara la regla.

4.3.2 Modelado de acciones

Ya se ha comentado anteriormente que una acción es una instancia de la clase Action, pero hasta el momento no se ha concretado que contiene esta clase. A efectos prácticos, se puede decir que una acción es un enunciado que define el estado que debe tener un elemento de la realidad. Un enunciado esta modelado en el lenguaje por un Statement, por lo que todo parece indicar que las acciones tienen una relación con esta clase.

Para modelar las acciones se ha creado una clase Modify, subclase de Action, que recibe en su constructor un Statement, representando el estado con el que se debe modificar un elemento del mundo real una vez que se ejecuten las reglas.

4.3.3 Almacenamiento de las reglas La introspección de las reglas es un elemento muy importante del sistema que se esta construyendo, ya que aporta la información de las automatizaciones que quiere provisionar el usuario. Para ello, es necesario almacenar la información de todas las reglas, para más

38 Iteración 3: Sintaxis del lenguaje scn

tarde acceder a ella.

Con el objetivo de almacenar estas reglas se hará uso de la clase Engine (ver Listado 4.2). Esta será una clase con métodos estáticos que contendrá una lista de reglas, cada vez que se instancie una regla, esta debe ser almacenada en dicha lista. Para ello, en el constructor de la clase Rule, la lista de reglas anteriormente mencionada se actualizará con la regla que se está instanciando.

1 class Engine: 2 rules = []

4 @classmethod 5 def reset(cls): 6 cls.rules = []

Listado 4.2: Clase Engine

4.3.4 Representación de los elementos del mundo real Las reglas del lenguaje representan condiciones y acciones sobre elementos del mundo real. Ya se ha descrito como definir tanto las condiciones y las acciones del lenguaje, pero no se ha comentado como se modelan los servicios del mundo real que el usuario quiere automatizar. En esencia, un elemento de la realidad, es un conjunto de datos que representan el estado de un objeto o dispositivo. Para representar este estado se ha decidido crear dis- tintas plantillas para diferentes clases de dispositivos, como switches, sensores de presencia, sensores de temperatura, etc.

La creación de las plantillas anteriormente mencionadas se realizará en un método deno- minado Template (ver Listado 4.3), el cual recibirá un parámetro name y una serie de campos. Este método hará uso de la clase namedTuple del módulo collections para crear una estructu- ra de datos denominada como el parámetro name y formado por el resto de campos pasados por parámetro al método. La elección de la clase namedTuple se debe a que es una estructura de datos del módulo collections de Python3, que permite crear una tupla en la que a cada elemento de la tupla le corresponde un campo con un nombre.

Por ejemplo, gracias a Template se podría crear un tipo switch con la línea de código Switch=Template(’Switch’, ’identifier’, ’status’), y a partir de esta estructura de da- tos, crear diferentes representaciones de switches de la forma sw1=Switch(identifier=’sw1’, status=False). En el ejemplo anterior, se podría acceder al valor de los campos de sw1 como si de atributos se tratasen, en el caso de querer acceder el valor de status bastaría con hacer sw1.status.

39 4. Desarrollo del Proyecto

1 def Template(name, *fields): 2 return collections.namedtuple(name, list(fields))

Listado 4.3: Clase Template

4.3.5 Retrospectiva Con el trabajo realizado durante esta primera iteración, se ha obtenido la primera sintaxis del lenguaje. Con esta primera sintaxis, una automatización para encender un switch deno- minado sw-02 cuando se encienda un switch con identificador sw-01 se escribiría tal y como se puede observar en el Listado 4.4.

1 Switch = Template(’Switch’,’identifier’,’status’) 2 Rule( 3 Event(Switch(identifier=’sw-01’, status=True)) 4 )( 5 Modify(Switch(identifier=’sw-02’, status=True) 6 )

Listado 4.4: Escenario con la sintaxis actual del lenguaje

En esta iteración se han observado una serie de problemas que deberán ser solucionados más adelante. En principio, en este ejemplo es visible la necesidad de contar con el campo identifier obligatoriamente, ya que es el único mecanismos para representas un servicio con- creto de forma unívoca en el sistema, y es la única forma que permite al usuario referirse un dispositivo.

Queda pendiente forzar al usuario que cuando cree un tipo de objeto con Template, esta deba poseer el campo identifier.

4.4 Iteración 4: Creación del Generador de Código Con la definición de las reglas, se poseen los mecanismos necesarios para capturar la se- mántica de una automatización escrita por el usuario. El siguiente paso a realizar, es dotar a nuestro procesador del lenguaje, de la función necesaria para todo compilador, y esta es po- der obtener un nuevo código escrito en el lenguaje destino (lenguaje prv) a partir del lenguaje fuente (lenguaje scn). El código generado, debe ser capaz de conectar los dispositivos que el usuario quiere automatizar, más concretamente debe conectar los dispositivos que producen eventos, con los servicios en los que se debe ejecutar las acciones. El instrumento para esta conexión es lo que se ha denominado Operador, un elemento del grid conectado a diferentes dispositivos que recibirá un evento, y en función de su valor decidirá si realizar las acciones pertinentes, modificando los dispositivos apropiados. Como se puede observar, los operado- res tienen un comportamiento diferente según lo requiera la automatización, son elementos configurables, por lo que se plantean las opciones de hacer pocos operadores flexibles pero

40 Iteración 4: Creación del Generador de Código

complejos o muchos operadores simples.

Figura 4.1: Representación de un operador

Con la información obtenida de las distintas reglas, el procesador de lenguaje debe crear un código de salida que permita realizar el provisionado de los distintos operadores anterior- mente mencionados. El lenguaje prv se ha decidido que tendrá el formato del Listado 4.5, donde los campos poseen el siguiente significado:

1 provide(Template, ServerName, when, then, source, sink)

Listado 4.5: Línea de código para desplegar un operador

Template: Plantilla de Icegrid para la creación del servidor ICE del operador. Esta plan- tilla es necesario para instanciar los servidores de forma automática.

ServerName: Nombre del servidor ICE que ejecutará el operador. Este nombre será distinto según el tipo de datos que maneje el operador, con el formato Operator. Por ejemplo un operador que maneje datos booleanos se denominará BoolOperator. when: Valor del evento que dispara la ejecución de la regla. then: Estado que debe tener el servicio sink si el evento se cumple. source: Id del servicio origen del evento. sink: Id del servicio que debe ser modificado.

Un aspecto importante es el mapeo de reglas a operadores. En un principio se pensó la posibilidad de realizar un operador por regla, lo cual parece coherente, pero este requisito podría complicar el diseño de los operadores, incluso podría haber problemas en el desarrollo futuro. Por lo tanto, se ha decidido que se provisione un operador por acción en cada regla, haciéndolos flexibles a la vez que se gana en simplicidad.

El generador de código corresponderá a una clase, denominada CodeGenerator, la cual recibirá una tabla de símbolos formado por una lista de reglas. A partir de estas reglas, el generador debe crear tantas líneas de código con el formato del Listado 4.5 como acciones

41 4. Desarrollo del Proyecto

hay presentes en las reglas. La generación de una línea de código se realizará a partir de una serie de plantillas, según el tipo de dato del evento (int, float, bool, etc...). Una vez generado el código este es escrito en un archivo de salida.

1 def build_rule(self, rule): 2 status_type = type(rule.conditions[0].statement.status) 3 template = self.templates[status_type] 4 code = [] 5 code.append(template.format( 6 rule.conditions[0].statement.status, 7 rule.actions[0].statement.status, 8 rule.conditions[0].statement.identifier, 9 rule.actions[0].statement.identifier)) 10 return code

Listado 4.6: Generación de una línea de código a partir de una regla

En el Listado 4.6, se puede observar la introspección necesaria en una regla para obtener una línea de código que provisione un operador. En esta generación de código se hicieron algunas asunciones, como que todas las reglas constasen únicamente de una acción, que la primera condición de una regla sea el evento, así como que todos lo servicios poseyesen un campo primario que aporta el estado principal de un objeto, denominado status.

4.4.1 Retrospectiva Llegados a este punto, el sistema es capaz de generar el lenguaje destino a partir del código fuente escrito por el usuario. Hasta el momento, se ha asumido en el código que todos los servicios tienen un campo status, que representaría un campo primario, pero en un futuro hay que buscar un modo más adecuado de realizar esta representación. Además, una regla solo puede generar un operador, cuando teóricamente, una regla con varias acciones debería generar tantos operadores como acciones existan. Por último, el nombre del servidor del operador es siempre el mismo, sin importar que regla y acción sea. Esto puede ocasionar problemas, porque en el momento que exista mas de un operador, es absurdo tener dos servidores con el mismo nombre ya que puede llevar a confusión. Este problema debe ser paliado más adelante.

4.5 Iteración 5: Creación del Parser Tras diseñar, de formar independiente, tanto la sintaxis del lenguaje como su generador de código, hacía falta la pieza que conectase ambas funcionalidades, la cual, a partir de un archivo, generase una lista de reglas correspondiente a la tabla de símbolos del lenguaje.

Esta responsabilidad recaerá en la clase Parser, la cual obtendrá el archivo de entrada del compilador, lo ejecutará gracias a la función de Python exec(), y tras su ejecución, leerá todas las reglas contenidas en el código fuente haciendo uso de la clase Engine, anteriormente

42 Iteración 5: Creación del Parser explicada (ver Seccion 4.3).

4.5.1 Lectura de argumentos

El Parser del compilador requiere de un modo por el que se le pueda pasar el documento con el código fuente scn escrito por el usuario. Tomando como referencia los compiladores disponibles, como por ejemplo GNU Compiler Collection (GCC), se tomó como la mejor opción pasar la ruta del archivo a compilar por línea de argumentos.

Dado que el compilador tiene esencialmente dos tareas, la compilación del código fuente, y el provisionado de los operadores a partir de la ejecución del código generado, se decidió aportar una funcionalidad que permita al usuario dividir, de forma explícita, la realización de cada una de esas dos tareas, para lo cual, el uso de la línea de argumentos también parecía una buena idea.

Teniendo en cuenta las dos consideraciones anteriores, se planteó la ejecución del compi- lador con la estructura del Listado 4.7.

scn [-c] [-p] file --Ice.Config=

Listado 4.7: Sintaxis de llamada al compilador

De este modo, la presencia de la opción -c indica que el usuario quiere compilar un archi- vo cuyo código fuente es del lenguaje scn, en cambio la presencia de la opción -p, indicaría que el usuario le pasa al compilador un archivo de provisionado en el lenguaje prv para provisionar los operadores que permitan las automatizaciones. La ausencia de las dos opcio- nes anteriormente comentadas, significarían que el usuario quiere compilar y provisionar un archivo scn.

Por último, se tiene el argumento -Ice.Config, el cual no debe ser procesado, ya que es responsabilidad de ICE. Este argumento es necesario debido a que el provisionado de operadores y enlazado de servicios se realiza por medio de ICE, siendo los escenarios una aplicación distribuida que usarán al servicio IceGrid para la resolución de proxies indirectos y objetos bien conocidos, por lo que hay que indicar la dirección del registry de IceGrid a partir de un archivo de configuración.

Para realizar el procesado de argumentos de una forma sencilla y estandarizada se decidió hacer uso del módulo argparse de Python. Este procesado se realizará en la función parse_- args la cual devolverá los argumentos procesados, y se lo dará al constructor de cada clase para que dispongan de ella.

43 4. Desarrollo del Proyecto

1 def parse_args(): 2 parser = argparse.ArgumentParser(description=’Compiler to provision operators’) 3 parser.add_argument(’-c’, action=’store_true’, 4 help=’compile the program to create the provide code’) 5 parser.add_argument(’-p’, action=’store_true’, 6 help=’make the provisioning’) 7 parser.add_argument("infile", type=argparse.FileType(’’), 8 help="file with the source code") 9 return parser.parse_args()

Listado 4.8: Procesado de argumentos

4.5.2 Retrospectiva

Con el desarrollo del Parser, se obtiene un mecanismo por el cual el usuario puede comu- nicar a Automaker que automatizaciones quiere realizar. Una peculiaridad que existe en este punto es el uso del archivo de configuración, este archivo no solo se usará para localizar el registry, si no que también será usado para realizar una correspondencia entre identificado- res de objetos y proxies en el sistema. La correspondencia proxy-identificador no debería ser responsabilidad del usuario, en su lugar debería haber un servicio denominado WelcomeSer- vice, que será llamado por cualquier dispositivo al conectarse al grid, enviándole el proxy del sensor o actuador. Una vez el WelcomeService reciba los proxies de un dispositivo, asignará un identificador a ese dispositivo, creando así la correspondencia identificador-proxy.

4.6 Iteración 6: Implementación de un escenario con dos switches

De forma paralela a la implementación del sistema, se empezó a desarrollar el escenario de un caso de uso, el cual, más adelante será integrado con el lenguaje y ejecutado de forma automática. El caso de uso representará una automatización en la que existan dos switches, denominados sw-01 y sw-02, de modo que sw-02 se encienda cuando se encienda sw-01.

Este escenario consistirá esencialmente en un operador que acepte datos booleanos, un provisionador, que simulará una el provisionado de una escena ad-hoc, y un archivo de- nominado app.xml, una aplicación IceGrid que representará todos los elementos del mundo real, en este caso, dos switches, que en este escenario serán emulados gracias a la implemen- tación de unos dummies.

El elemento esencial de este escenario es el operador, el cual será implementado, para más tarde, reutilizarlo en el provisionado de automatizaciones en el entorno. Para realizar las

comunicaciones entre el operador y los diferentes servicios por medio de ICE, se necesitan una serie de interfaces que permitan a los servicios comunicar sus datos. Con este propósito

se hará uso de las interfaces de Smart Transducer (st), presentes en el Listado 4.9. Estas interfaces fueron creadas con el propósito de ser muy simples y permitir la comunicación de una serie de datos primitivos, así como permitir realizar el enlace entre estos servicios gracias a la interfaz Linkable. En el caso concreto de este escenario, el operador y los dummies de

44 Iteración 6: Implementación de un escenario con dos switches

los switches deben implementar las interfaces IBool y Linkable, cuya implementación debe ser la siguiente:

Interfaz Linkable: Esta interfaz debe implementar el método linkto. A este método se le debe pasar como argumento un proxy a un objeto remoto, el cual será fijado como un observador. De este modo el objeto que implemente esta interfaz podrá notificar un

dato a su observador, por medio del método set de la interfaz ST correspondiente.

Interfaz IBool: Una clase que implemente esta interfaz debe tener un método set, con la lógica que quiera darle el usuario cuando el objeto reciba un mensaje con un valor.

1 module st { 2 interface IBool { void set(bool v, string sourceAddr); }; 3 interface IByte { void set(byte v, string sourceAddr); }; 4 interface IFloat { void set(float v, string sourceAddr); }; 5 interface IString { void set(string v, string sourceAddr); }; 6 interface Linkable { void linkto(string observerAddr); }; 7 };

Listado 4.9: Interfaces de smart-transducer

En el caso concreto del operador, el método linkto será el encargado de asignar como ob- server el servicio sink (servicio que deber ser modificado por la automatización), y el método set se encargará de invocar el método set del observador con el valor recibido cuando se ha invocado su propio método set.

En este escenario el método set del operador recibirá un dato del primer switch, lo evalua- rá, y en el caso de que su valor sea True, se modificará el estado de su observador (el switch ’sw-02’) invocando su llamada set con True.

Para que el provisionado de un operador se pueda realizar de forma automática, es nece- sario el uso de dos servicios ya implementados: Factory y Wirer.

4.6.1 Factory La factoría es un servicio implementado como parte del proyecto SymbIoT 1 que se en-

cuentra disponible dentro de la misma aplicación distribuida ICE donde se desplegarán las automatizaciones. Esta Factoría permitirá el provisionado de operadores en un grid de forma automática, únicamente indicándole la plantilla Icegrid que debe usar. La interfaz de este servicio corresponde con la presente en el Listado E.2 del AnexoE. Para hacer uso de la fac-

toría, es necesario que exista una plantilla del servidor de ICE, de este modo, la configuración de los operadores se realizarán indicándole a cada plantilla una serie de parámetros, todos en formato de cadena de texto.

1Proyecto de investigación en curso del grupo ARCO

45 4. Desarrollo del Proyecto

Gracias a este servicio se pueden crear servidores implementando Operadores de forma automática.

4.6.2 Wirer

Otro servicio de soporte para los operadores es el Wirer 2. Este servicio permite, a partir de dos proxies, realizar el enlazado de los objetos referenciados por estos proxies, la interfaz

ICE de este servicio se puede ver en el Listado E.3. Para que el enlazado pueda ser realizado de formar apropiada, el objeto productor debe implementar la interfaz Linkable.

4.6.3 Retrospectiva En esta iteración se ha conseguido desarrollar un escenario, en el cual, las automatizacio- nes se realizan «a mano». Este escenario, más tarde, debe ser integrado con el lenguaje scn para comprobar su correcto funcionamiento.

4.7 Iteración 7: Implementación del Provisioner Cogiendo como referencia el escenario creado en la Sección 4.6, se comenzó a añadir la funcionalidad necesaria para provisionar3 operadores en el compilador scn. Esta funcionali- dad será responsabilidad de la clase Provisioner.

Uno de los principales problemas que se encontraron en esta implementación, fue la nece- sidad de usar un comunicador de ICE. Esta necesidad se debe a que, como se ha comentado en el escenario de los switches, se requiere de los servicios Wirer y Factory registrados co- mo unos objetos remotos de IceGrid. Para poder recuperar estos objetos ICE, el Provisioner necesita hacer uso de un comunicador. Una opción sería que Provisioner fuese una subclase de Ice.Application, pero esto podría complicar el diseño de la clase al asignarle demasiadas responsabilidades. Una segunda opción, y la que se ha decidido implementar, es el uso de un mixin (clase que ofrece una funcionalidad para ser heredada por una subclase), denominado IceMixin (ver Listado 4.10), que se encargue de gestionar la resolución de los proxies de

ICE. En el caso de la factoría y el servicio de cableado, estarán registrados como objetos bien conocidos, y sus objetos ICE pueden ser obtenidos resolviendo las identidades factory y wirer respectivamente.

La clase Provisioner heredará de IceMixin, e implementará el método provide, diseñado cuando definimos anteriormente la sintaxis que se obtenía al ejecutar el generador de có- digo (ver Sección 4.4). Para poder ejecutar el código generado, se usará el método exec(), añadiendo al diccionario global el método provide que implementa el provisionador (ver Listado E.4). Para crear el operador, se llama al método make de la factoría, y para con-

2También parte del proyecto SymbIoT 3El concepto provisionar se refiere al hecho de instanciar un operador en un nodo, sin necesidad de desplegar el código fuente a dicho nodo

46 Iteración 7: Implementación del Provisioner

1 class IceMixin: 2 def __init__(self, args): 3 self.ic = Ice.initialize(args)

5 def obtain_object(self, identity, cast_object): 6 proxy = self.ic.stringToProxy(identity) 7 return cast_object.uncheckedCast(proxy)

9 def __del__(self): 10 self.ic.destroy()

Listado 4.10: Clase IceMixin

figurarlo, como se ha comentado anteriormente, se usarán parámetros de una plantilla de icegrid, siendo todos los parámetros del tipo str. Las variables sources y sinks representan los identificadores de los servicios envueltos en la automatización, para obtener los proxies correspondientes a esas identidades se usarán las propiedades en un archivo de configuración

de ICE, con el método identity_to_proxy.

4.7.1 Refactorización del provisioner

El uso de IceMixin permite aislar toda la funcionalidad necesaria para el provisionador, pero puede producir un problema importante, la falta de gestión del comunicador. Para paliar este problema, en el mixin se puede observar que se ha sobrecargado el método __del__, de modo que cuando dejen existir referencias de una clase que herede IceMixin, el comunicador se destruya apropiadamente. El problema de delegar esta responsabilidad al método __del__, es que solo se ejecuta cuando no exista ninguna referencia a un objeto que implemente este método, en el caso de que existan varias referencias al mismo objeto, puede que Python no gestione bien el número de referencias, produciendo que este método no llegue a ejecutarse y el comunicador nunca se destruya.

ICE provee un mecanismo para gestionar de forma apropiada los comunicadores, y es el uso de la clase Ice.Application, de modo que una clase que herede de esta super clase, tendrá un comunicador disponible en la ejecución de su método run, y una vez este método termine, el comunicador será destruido. Esta idea en un principio fue desechada por no delegar muchas responsabilidades en el provisionador, pero para la gestión del comunicador es una solución mucho más elegante.

Dado que finalmente se decidió usar Ice.Application se hizo una refactorización en todo el código, creando la clase Compiler (ver Listado 4.11). Esta clase heredará de Ice.Application, y contendrá todo el programa principal del compilador, asegurando que el comunicador es- tará disponible en toda la ejecución del programa, y que cuando el programa termine, el comunicador sera destruido de forma apropiada. Aprovechando esta refactorización del có- digo principal del programa, se tomó como decisión de no incluir la información de la línea de argumentos en el constructor de las clases Parser, CodeGenerator y Provisioner, ya que

47 4. Desarrollo del Proyecto

esto solo producía dependencias innecesarias y un aumento de la complejidad. En su lugar, se decidió pasarle a estas clases la información estrictamente necesaria para su funcionamiento (por ejemplo el Parser necesita únicamente el nombre del archivo con el código fuente).

1 def main(argv, communicator=None): 2 config = parse_args(argv[1:])

4 if config.compile: 5 symbol_table = Parser.from_filename(config.scene_filename).run()

7 generator = CodeGenerator(symbol_table) 8 generator.build() 9 generator.write_to_filename(config.provision_filename)

11 if config.provision: 12 print(communicator) 13 provisioner = Provisioner.from_str_proxies( 14 config.provision_filename, communicator, Resolver(communicator)) 15 provisioner.run()

18 class Compiler(Ice.Application): 19 def run(self, args): 20 main(args, self.communicator())

Listado 4.11: Clase Compiler y main del compilador

4.7.2 Retrospectiva

Llegado a este punto, ya se poseería un prototipo totalmente funcional del sistema Automaker, desde la definición del lenguaje, pasando por la compilación, hasta el provisionado de ope- radores. En la Figura 4.2 se puede observar el flujo que sigue el código fuente. Primeramente se posee un archivo del tipo .scn, que contiene una serie de reglas. El archivo scn se compila, y se obtiene un archivo .prv, el cual contendrá tantas líneas provide como acciones tenían las reglas del archivo original. Por último, al ejecutar un archivo, cada línea provide se convertirá en un operador, que formarán el núcleo de las automatizaciones creadas por el usuario.

4.8 Iteración 8: Implementación de nueva sintaxis Tras una reflexión sobre el estado en el que se encontraba el lenguaje, se concluyó que la sintaxis actual producía una perdida de semántica para el usuario, incluso a la hora de pro- cesar el código, puede ser confuso saber que es lo que se quiere automatizar. Para solventar este problema se procedió a actualizar la sintaxis, de modo que para el usuario fuese más claro que es lo que desea automatizar, y para el compilador fuese más fácil saber que es lo que el usuario quiere. Hasta esta iteración, los servicios del grid consistían en una estructura de datos y eran

48 Iteración 8: Implementación de nueva sintaxis

Figura 4.2: Construcción automática de los operadores a partir de un archivo scn

identificados por un campo «identifier». Aunque no sea muy complejo, tener que indicar siempre el campo «identifier», tanto en las acciones como en las condiciones, puede resultar algo redundante y propenso a errores. Siempre se pueden dar los casos en los que el usuario se olvide de añadir este campo, o incluso que se equivoque a la hora de introducirlo.

Para paliar los problemas anteriores se planteó la siguiente sintaxis, presente en el Lista- do 4.12. Aquí se puede ver como los dispositivos del grid pasan a ser instancias de clases, estas clases son creadas a partir de la clase Template, diciendo que campos debe tener el dispositivo y el tipo de estos campos. Estas instancias poseen esencialmente dos métodos, el método when, que indicará una condición, que se cumplirá cuando el valor de los campos corresponda con el introducido por el usuario en el método, y el método modify, el cual in- dica la modificación del objeto que llama al método con el valor de los campos pasados por parámetros.

1 Light = Template(identifier=str, status=bool) 2 light_01 = Light(identifer=’light-01’) 3 light_02 = Light(identifer=’light-02’)

5 Rule( 6 Event(motion_01.when(status=True)), 7 Day(status=False) 8 )( 9 light_01.modify(status=True), 10 light_02.modify(status=True) 11 )

Listado 4.12: Regla con la nueva sintaxis

Para lograr satisfacer esta nueva sintaxis se realizaron una serie de modificaciones que se pueden ver a continuación.

49 4. Desarrollo del Proyecto

4.8.1 Refactorización de Template Anteriormente, los servicios del mundo real eran representados por una estructura de da- tos, pero los nuevos cambios en la sintaxis obligan a que estos servicios sean instancias de clases definidas a partir de Template, para poder invocar los método when para crear condi- ciones y modify para crear acciones.

Para comenzar, dado que la responsabilidad de la clase Template va a ser la creación de distintas clases, de modo que se permite al usuario crear instancias de esas clase, Template debe pasar a ser una metaclase. Una metaclase en orientación a objetos, es una clase cuyas instancias son clases, de modo que una metaclase define el comportamiento de las clases que crea y de sus instancias [Jon13]. En Python las metaclases son modeladas heredando de la super clase type y sobrescribiendo el método __new__.

En el Listado 4.13 se puede observar la metaclase Template. El método __new__ obtiene por parámetro un diccionario formado por los campos que el usuario quiere que formen la clase a crear junto con el tipo de datos de cada campo. Dado este diccionario comprueba que entre los campos que lo forman esté presente el campo identifier, si este campo no está, avisará al usuario de que esta intentando crear un tipo de dispositivo inválido. Una vez comprobados los campos, con la llamada type(), crea un objeto que herede de la clase Statement, con el nombre de la clase que ha definido el usuario, y con los atributos definidos en la variable fields.

1 class Template(type): 2 def __new__(cls, class_name, **fields): 3 cls.fields = fields 4 cls.check_fields()

6 new_cls_dict = { 7 "fields": fields 8 } 9 return type(class_name, (Statement,), new_cls_dict)

11 @classmethod 12 def check_fields(cls): 13 if"identifier" not in cls.fields.keys(): 14 raise InvalidType(’identifier field is mandatory’)

Listado 4.13: Metaclase Template

4.8.2 Refactorización clase Statement

Template se convierte en una metaclase, que permite al usuario crear clases para represen- tar un servicio. Todas las clases creadas a partir de Template heredan toda su funcionalidad de la clase Statement, la única diferencia será los campos que decida el usuario que tenga ña clase a crear.

50 Iteración 8: Implementación de nueva sintaxis

Para cumplir con su trabajo, la clase Statement básicamente será una estructura de datos, que almacenará enunciados los cuales representarán el estado deseado de los dispositivos del mundo real para las acciones y condiciones. Para ello Statement será una subclase de dict, y permitirá el uso de los métodos when y set, para indicar cuando una sentencia es una condición o una acción, así como para que el usuario pueda reflejar los campos del objeto y los valores que componen ese enunciado. Como se puede ver en el Listado 4.14, la clase Statement sobrecarga el método update de dict, el cual se ejecuta cuando se modifica un diccionario, de modo que cuando una instancia suya actualice su diccionario, este método se ejecutará, comprobando que el campo que se quiere modificar exista y que sea del tipo que se definió al crear la clase con Template.

1 class Statement(dict): 2 def __init__(self, **kwargs): 3 self.update(kwargs)

5 def when(self, **kwargs): 6 self.update(kwargs) 7 return Condition(self[’identifier’], **kwargs)

9 def set(self, **kwargs): 10 self.update(kwargs) 11 return Action(self[’identifier’], **kwargs)

13 def update(self, new_attrs): 14 for attr, value in new_attrs.items(): 15 if attr not in self.fields.keys(): 16 raise AttributeNotFound 17 if not isinstance(value, self.fields[attr]): 18 raise TypeConflict 19 super().update(new_attrs)

Listado 4.14: Clase Statement

Las clases Condition y Action son subclases de dict, y almacena el identificador del objeto al que se refiere la acción o la condición, así como los campos del objeto que el usuario ha indicado en los métodos when o set respectivamente.

4.8.3 Refactorización Evento

La nueva sintaxis también obliga a producir ciertos cambios en la clase Event. Un evento, tal y como es visto en la nueva sintaxis, recibe como parámetro una condición. A nivel de implementación, un evento no deja de ser parecido a una condición, simplemente es una es- tructura de datos que debe almacenar la información del enunciado4 de la condición. Al igual que las clases Condition y Action esta clase heredará de dict, y almacenará la información (id y campos) de la condición pasada por parámetros.

4Recordar al lector que en resumen un enunciado está representado por un diccionario con los campos y valores que representan el estado de un dispositivo del mundo real

51 4. Desarrollo del Proyecto

4.8.4 Retrospectiva Esta iteración deja pendiente alguna modificación. De momento, esta nueva sintaxis se ha implementado y es funcional, pero no es la solución más elegante. En un futuro, se pretende crear una jerarquía de clases, siendo Statement la superclase de Event, Action y Condition.

4.9 Iteración 9: Añadir condiciones al lenguaje de provisionado Hasta el momento, el usuario puede definir condiciones en el lenguaje scn, gracias al método when, pero internamente no se ha añadido la funcionalidad de manejarlas, ni de re- presentarlas en el lenguaje de provisionado. Para comenzar hay que decidir que estructura de datos usar para la representación de estas condiciones. Se barajaron varias posibilidades, la que parecía mejor opción era la de un diccionario de diccionarios, en el que el primer diccionario estaría indexado por los objetos, y el segundo indexado por los campos que formen el objeto. Esta primera solución tenía un problema, y era que no permitía múltiples valores para el mismo campo de un objeto, funcionalidad que podría resultar interesante cuando hubiese que afrontar el uso de umbrales. Al final, la solución que se decidió adoptar fue el uso de una lista de tuplas formada por tres elementos, con el formato (id_dispositivo, campo, valor). Para construir esta lista, se obtenía una lista con todas las condiciones definidas por el usuario en el lenguaje scn, y a partir de estas condiciones, se extraían todos los atributos y valores añadiéndolos a la lista de retorno. La implementación de la construcción de esta lista se puede observar en el método build_conditions presente en el Listado 4.15.

1 def build_conditions(self, conditions): 2 retval = [] 3 forc in conditions: 4 for attr, value in c.items(): 5 if attr !=’id’: 6 retval.append((c.id, attr, value)) 7 return retval

Listado 4.15: Método para construir las condiciones del lenguaje prv

Una vez se tiene la estructura de datos, hay que decidir como mapearla al lenguaje de provisionado. Con el fin de añadir la estructura de datos al lenguaje de provisionado, se le añadió un parámetro denominado met que es inicializado con la lista de tuplas que represente las condiciones. Tras esta modificación, el método de provisionado sería el que se puede observar en el Listado 4.16.

1 provide("OperatorTemplate,"BoolServer", when=True, met=[(’Day’,’status’, True)], then=True, source =’sw_01’, sink=’sw_02’)

Listado 4.16: Provisionado de un operador con condiciones

52 Iteración 10: Creación de escenario con condiciones

4.10 Iteración 10: Creación de escenario con condiciones Una vez que el lenguaje soportaba las condiciones, se creyó conveniente crear un nuevo escenario que necesitase del uso de condiciones, con el fin de implementar un escenario de ejemplo. Para la implementación de este escenario, se partirá del estado del escenario explicado en la Sección 4.6. El escenario a desarrollar elegido poseía una gran similitud con el primer escenario imple- mentado. Al igual que el anterior, este también consistía en dos switches, una que propicia el evento y otro que recibe la acción, pero en este caso, el encendido del switch sw-02 estará condicionado por la luz del día, este switch solo se encenderá cuando se encienda sw-01 y sea de noche, añadiendo la complejidad de una condición al escenario de la Sección 4.6. Aplicando este escenario al lenguaje scn, y asumiendo que se posee una plataforma con identificador «Day», se obtendría la automatización presente en el Listado 4.17.

1 Switch = Template(’Switch’, id=str, status=bool) 2 Day = Template(’Day’, id=str, status=bool) 3 sw_01 = Switch(id=’sw-01’) 4 sw_02 = Switch(id=’sw-02’) 5 day = Day(id=’Day’)

7 Rule( 8 Event(sw_01.when(status=True)), 9 day.when(status=False) 10 )( 11 sw_02.set(status=True) 12 )

Listado 4.17: Ejemplo de especificación para el escenario

Para implementar este escenario, se creó un dummy que realizase la función de indicar al operador si era de día o no. Esta funcionalidad se realiza simplemente comprobando la hora, considerando que las horas de luz solar son de 9 de la mañana de 9 de la noche. Esta funcionalidad podría haber sido realizada por el mismo operador, lo cual reduciría latencias y podría simplificar el sistema, pero la simplificación del sistema produciría un incremento en las responsabilidades del operador. Dado que ninguna de las soluciones era claramente mejor que la otra, se decidió optar porque fuese un servicio externo el que le diese la información al operador. Llegado a este punto, era necesario que el operador tuviese conocimiento del estado de su entorno, para así poder evaluar de forma correcta las condiciones con las que fuese con- figurado. Para hacer efectivo este conocimiento, se plantearon las siguientes posibilidades basadas en el diseño de sistemas distribuidos [Bur18].

1. Modelo Asíncrono: En este modelo, existiría una única caché en el sistema con el estado de todos los dispositivos del entorno. Para poder conocer el estado del entorno, el operador se subscribiría a esta caché, y cuando la caché fuese modificada, esta pu-

53 4. Desarrollo del Proyecto

blicaría su estado, y cada operador subscrito al canal almacenaría localmente el último estado de la caché. Dado que cada operador tendría el estado actual de esta caché, cuando llegue un evento, para evaluar la condiciones se cotejaría el estado de la caché local, concluyendo si se debe o no propagar el evento.

2. Modelo Síncrono: Al igual que en el modelo anterior existe una caché en todo el sistema que contiene el estado de todos los dispositivos del entorno. Cuando un evento llega al operador, el operador pregunta a la propia caché si se cumplen las condiciones necesarias para propagar el evento. La caché responderá con True en el caso de que todas se cumplen, y con False en el caso contrario.

3. Modelo Mixto: En este modelo no existe una caché de sistema, en cambio cada ope- rador posee una única caché. Los operadores se encargarán de suscribir la caché a aquellos dispositivos del entorno cuyo estado deban conocer, de este modo cuando el estado de un dispositivo cambie, este notificará a la caché para ser modificada. De este modo la caché del operador siempre va a estar actualizada. Cuando llegue un evento, un operador únicamente tiene que comprobar las condiciones en su caché y actuar en consecuencia.

Al final, debido a su simplicidad, su baja latencia, y ser la solución menos centralizada, se decidió optar por el modelo mixto, es decir, cada operador tendrá una caché, esta caché reflejará el estado de todos los dispositivos en la realidad, y para actualizarla, el operador se subscribirá a un canal de eventos por dispositivo, donde publicarán su estado. Para enmas- carar toda esta problemática para el operador, se creó la clase Subscribers, entidades que se subscribirán a los canales de eventos de los dispositivos (serán observadores de los dispositi- vos), y a partir de su información, modificarán la caché de los operadores. Para poder recibir la información de los dispositivos, los Subscribers usarán las interfaces de ST, propiciando que existan tantos suscriptores como tipos, en concreto para el escenario a desarrollar es necesario un BoolSubscriber.

Dado que habrá tantos suscriptores como tipos de datos permiten las interfaces st se hará uso del patrón de diseño Factoría, creando una factoría de suscriptores que creará un sus- criptor dado el tipo de datos requerido, en este caso de ejemplo como ya se ha comentado se necesita un tipo de datos bool.

Una vez solventado el problema de la caché, cuando el operador recibe el evento de que sw-01 ha sido encendido, comprobará con la caché si se han cumplido las condiciones con las que se ha configurado el operador, si las condiciones se satisfacen, modificará sw-02 con el valor conveniente, en este caso lo encenderá.

54 Iteración 11: Añadir soporte para condiciones con umbrales

4.11 Iteración 11: Añadir soporte para condiciones con umbrales Hasta el momento, al usuario se le da la posibilidad de crear condiciones con valores exactos, como por ejemplo status=True, temp=20, etc..., pero por ejemplo no es posible para un usuario con la sintaxis disponible, crear una automatización que haga que se encienda la calefacción cuando la temperatura sea menor a 15o. Para añadir esta funcionalidad se barajaron varias posibilidades, de las cuales dos fue- ron bastante convincentes. Para facilitar la explicación de esta sintaxis veamos un ejemplo. Imaginemos que tenemos un sensor de temperatura, representado por la variable temp_01 con el campo status indicando la temperatura del entorno. Para crear una condición que se cumpla cuando la temperatura que marque el sensor sea menor de 20o, se tendrían estas dos sintaxis:

1a sintaxis: temp_01.when(status=“< 20”) 2a sintaxis: Check(temp_01, “status < 20”)

Ambas son bastante viables y entendibles para el usuario, y para el desarrollo, ninguna representaba una ventaja significativa a largo plazo frente a la otra, por lo que se decidió soportar las dos sintaxis. Para permitir la primera sintaxis solo fue necesaria una pequeña modificación en la clase Statement. Hasta el momento, si modificabas un atributo de un objeto creado a partir de Template, el tipo de ese atributo debía coincidir con el definido en el momento de crear la clase, pero al permitir umbrales representados por una cadena, la cosa cambia, ahora se debe permitir que un campo de tipo int permita almacenar str. Para realizar este cambio se debe modificar el método update de la clase Statement, permitiendo que se almacenen cadenas, este cambio de puede observar en el Listado 4.18.

1 if not isinstance(value, (self.field_spec[name], str)): 2 raise TypeConflict("filed ’{}’ type should be ’{}’, but value was ’{}’".format( 3 name, self.field_spec[name].__name__, value))

Listado 4.18: Comprobación de tipos permitiendo str

La segunda sintaxis requirió una mayor cantidad de cambios. En primer lugar fue ne- cesario la creación del método Check, que recibiese las cadenas y las convirtiese en una condición como la de la primera sintaxis, manteniendo una uniformidad a la hora de proce- sar internamente las condiciones. Con ese objetivo, se comprobaba que la cadena contuviese un operador (en principio se desarrolló únicamente la funcionalidad para el operador <), si lo contenía la cadena se particionaba en tres, quedando la cadena dividida en campo, operador y umbral. Con estos tres datos y el identificador del objeto, se creaba la condición requerida. La implementación de esta lógica es observable en el Listado 4.19.

55 4. Desarrollo del Proyecto

1 def Check(device, condition): 2 if’<’ in condition: 3 cond_partitioned = condition.partition(’<’) 4 return Condition(device[’identifier’], 5 **{cond_partitioned[0]: cond_partitioned[1] + cond_partitioned[2]}) Listado 4.19: Función Check

4.11.1 Refactorización Jerarquía de clase Statement Durante el desarrollo de esta funcionalidad, se detectó una incongruencia respecto a las clases Statement, Action, Condition y Event. Todas ellas eran diccionarios, y a efectos prác- ticos, las tres últimas eran una especialización de la primera, lo que tiene toda la pinta de ser una herencia de clases (ver Sección 4.8.4).

Para cumplir con la herencia de clases, en primer lugar se debió modificar la clase Sta- tement, añadiendo una variable field_spec, que contiene un diccionario donde almacenar la especificación de los campos de los objetos creados. Además se modificaron los méto- dos when y then, que con los cambios requeridos, simplemente crean un nuevo diccionario, añaden la información de los campos estrictamente necesarios para la condición o la acción (identificador del dispositivo y campos marcados por el usuario) y se crea la condición o acción necesaria con este nuevo diccionario.

Al heredar Action y Condition de Statement, estas clases estarán vacías, simplemente he- redarán la funcionalidad de Statement, funcionalidad necesaria para cumplir su función y almacenar la información de los enunciados.

La clase Event también heredará de Statement, pero esta si tendrá una funcionalidad míni- ma, comprobar que como parámetro se le ha introducido una condición, en el caso de que no se le pase una condición, debe elevar una excepción IllegalEvent para informar al usuario. El resto de su funcionalidad también sera delegada a Statement ya que también almacena información sobre un enunciado.

Para cumplir con este herencia se tuvo que modificar la clase Template, simplificándola un poco, dejándole como responsabilidad comprobar que entre los campos pasados por el usuario para la nueva clase se encuentra el identificador, crear la nueva clase que herede de Statement, y actualizar la variable field_spec de la nueva clase, de modo que contenga los campos definidos por el usuario.

Por último se tomó la decisión de cambiar el nombre del campo del identificador, de identifier a id.

4.11.2 Retrospectiva La definición de umbrales ha creado dentro del propio lenguaje un sublenguaje, el cual añade un incremento de complejidad considerable, ya que conlleva realizar un procesamiento

56 Iteración 12: Definición de interfaz para la comunicación con los operadores

de este sublenguaje en las fases de análisis léxico, semántico y sintáctico. Abordar esta complejidad no es una tarea imposible, aunque si complicado, por lo que en un futuro se debe encontrar algún otro mecanismo en la sintaxis para reflejar estos umbrales, intentado evitar trabajar con cadenas de texto.

4.12 Iteración 12: Definición de interfaz para la comunicación con los operadores Hasta el momento, la integración con los escenarios ha sido configurando el operador a

partir de los parámetros de la plantilla de ICE, lo cual no era muy buena solución además de ser algo engorrosa. Esa solución se decidió descartar y abrir paso a la configuración por medio de funciones. Para poder configurar un operador desde el compilador, después de

provisionarlo, hace falta una interfaz ICE que permita comunicar los parámetros de configu- ración. Durante la definición de la interfaz, se llegó a la conclusión que toda la información ha de estar representada por datos del tipo str, ya que los tipos de datos a usar no se sabrán hasta tiempo de ejecución, por lo que la única forma de crear una interfaz genérica para cualquier escenario es usando cadenas de texto para representar los datos. De este modo la interfaz para configurar un operador se puede observar en el Listado 4.20.

1 module AutomakerServices {

3 sequence ConditionPredicate; 4 sequence ConditionList; 5 dictionary ConditionDict;

7 interface Operator { 8 void setEvent(string when); 9 void setAction(string then); 10 void setConditions(ConditionDict conditions); 11 void commit(); 12 }; 13 };

Listado 4.20: Automaker.ice

Como consecuencia de que tanto el evento, acciones y condiciones van a ser una cadena de texto para cumplir con la interfaz, se tuvo que hacer una refactorización de código, con- virtiendo todos los datos para configurar el operador a una cadena por medio de la llamada str(). El operador será el encargado de obtener el valor a partir de la cadena gracias a la función eval(). Un error del compilador que se detectó al intentar la integración fue un problema de la elección de las plantillas de código del provisioner. Si recuerda el lector, las plantillas eran elegidas según el tipo de dato del evento (bool, int, float...) (ver Sección 4.4). En los casos de

57 4. Desarrollo del Proyecto los umbrales, puede que se escoja una plantilla str, desplegando un operador str de formar incorrecta. Para solucionar ese error, se modificó el método de construcción de reglas, y en el caso de que el evento sea una cadena, se evalúa con eval() toda la cadena excepto el primer carácter, el cual se supone que es el operador, y de la cadena evaluada se averigua el tipo. Por ejemplo si se tuviese la cadena «< 20», se evaluaría toda la cadena menos el primer carácter, dando resultado al método eval(“20”), cuyo valor devuelto sería 20 y su tipo int. De esta forma, el tipo correcto que debe tener el operador sería averiguado.

Una vez creada esta interfaz de comunicación, se modificaron los operadores creados para que cumpliesen con esta interfaz.

4.12.1 Refactorización jerarquía de operadores Tras implementar la interfaz de configuración de los operados se noto como su implemen- tación se estaba complicando, y como la creación de operadores para otros tipos (float, int, string, etc...) podría ser una tarea muy repetitiva, ya que parte de la implementación de los operadores sería idéntica.

Para subsanar este problema se decidió extraer la implementación de la configuración de los operadores, e introducirla en una superclase de la que heredasen todos los operadores.

Debido a que ICE no permite implementar la interfaz de una superclase a la vez que se im- plementa otra interfaz (en el caso del operador las interfaces de st y Automaker), esta clase será un mixin, es decir una clase que ofrece una funcionalidad, pero que no está desarrollada para trabajar de forma autónoma, y será denominada OperatorMixin.

OperatorMixin implementará todas las funciones correspondientes a la configuración de un operador (a pesar de no implementar la interfaz Automaker.Operator), incluida las distintas funciones auxiliares que este proceso puede necesitar. Gracias a esto, los operadores de un tipo específico, como lo puede ser un operador booleano, se simplifican, encargándose de lo referente a la recepción de eventos, procesado de condiciones y ejecución de acciones en los dispositivos.

4.12.2 Factoría de predicados Observando las interfaces creadas se puede ver como los operadores son configurados únicamente con cadenas de texto. El uso de cadenas, añade una complejidad innecesaria al sistema, la cual sería conveniente eliminar lo antes posible.

Las cadenas permiten dar homogeneidad a la hora de representar datos, evitando la necesi- dad de crear un conjunto de interfaces por cada tipo de dato, siendo el único mecanismo para configurar correctamente los operadores, ya que la serialización de objetos no está permitida con ICE. Dado que la complejidad de las cadenas debe ser eliminada tan pronto como sea po- sible, es responsabilidad del operador, tras ser configurado, convertir estas cadenas en algo con lo que sea fácil de operar, estos serán instancias de objetos denominados Predicates.

58 Iteración 13: Refactorización del lenguaje de provisión

Un Predicate o predicado será un objeto que recibirá un valor y decidirá si ese valor cumple o no con el predicado (devolverá True o False). Para comenzar se decidieron crear lo siguientes predicados:

greaterThan: Sus instancias se construyen a partir de un entero o un flotante, y su invocación con otro número indicará si este es mayor que el número con el que se instanció el predicado.

lessThan: Sus instancias se construyen a partir de un entero o un flotante, y su invoca- ción con otro número indicará si este es menor que el número con el que se instanció el predicado.

equals: Sus instancias se construyen con un elemento de cualquier tipo (booleano, entero, flotante, cadena de texto), y al invocar la instancia con cualquier valor indicará si cumple con el valor del predicado o no.

Para hacer simple la creación de predicados, se ha desarrollado lo denominado factoría de predicados en la clase PredicateFactory, la cual recibe una cadena y crea el predicado acorde a la semántica de la cadena. Por ejemplo en el caso de encontrar una cadena «< 20» se deberá crear un predicado lessThan instanciado con el valor 20. En el Listado 4.21 se puede observar la implementación de esta factoría y como, en los casos en los que hay presente un operador mayor o menor, se crea un predicado de un umbral con el valor numérico de la cadena (que debe situarse en la cadena justo después del operador, siendo el operador el primer carácter siempre). En los casos en los que no haya ningún operador en la cadena, se considera un literal.

1 class PredicateFactory: 2 def make(self, condition): 3 if’<’ in condition: 4 return lessThan(int(condition[1:])) 5 elif’>’ in condition: 6 return greaterThan(int(condition[1:])) 7 else: 8 return equals(eval(condition))

Listado 4.21: Factoría de Predicados

Una vez se obtienen los predicados a partir de las condiciones y el valor esperado del evento, para que el operador comunique la acción a su destinatario, solo tiene que comprobar que los predicados tanto del evento como de la condición se cumplen para el evento recibido y para los datos que disponga en la caché.

4.13 Iteración 13: Refactorización del lenguaje de provisión En esta iteración de analizó el estado del lenguaje de provisionado y como su complejidad iba aumentando. En un principio no parecía un problema provisionar un operador en una

59 4. Desarrollo del Proyecto

línea de código, pero conforme el problema ha crecido, se ha visto una desventaja importante, y es su poca legibilidad una vez añades un par de condiciones. Por ejemplo, observemos el Listado 4.22, la longitud es excesiva, lo cual puede complicar la lectura por parte del usuario, eso sin contar con que únicamente se está haciendo uso de dos condiciones ¿qué pasaría si en vez de dos fuesen ocho? No sería un formato manejable.

1 provide("OperatorTemplate,"BoolServer", when=True, met=[(’Day’,’status’, True), (’sw _02’,’status ’, True)], then=True, source=’sw_01’, sink=’sw_03’)

Listado 4.22: Ejemplo de lenguaje provisioner con condiciones

Para paliar el anterior problema, se decidió dividir la línea provide en varias líneas, más concretamente en los métodos createOperator, configureOperator y linkServices, quedando el código de provisión mucho más legible. El ejemplo de la sección anterior con este nuevo lenguaje de provisión quedaría como en el Listado 4.23. La inclusión de una gran cantidad de condiciones seguiría complicando la lectura, pero con esta nueva sintaxis, este efecto se palia considerablemente.

1 op = createOperator(’OperatorTemplate’,’BoolServer’) 2 configureOperator(op, when=True, 3 met=[(’Day’,’status’, True), (’sw _02’,’status’, True)], then=True) 4 linkServices(op_str_proxy, source=’sw_01’, sink=’sw_03’)

Listado 4.23: Ejemplo con la nueva sintaxis

Este nuevo lenguaje obliga a la modificación del método provide de la clase Provisioner, dividiendo su funcionalidad en los tres métodos expuestos en la nueva sintaxis.

4.13.1 Refactorizaciones de código en esta iteración Durante esta iteración se han detectado algunas mejoras que realizar a la implementa- ción. La primera de ellas ha permitido completar un poco más el análisis semántico, compro- bando que a la hora de utilizar la metaclase Template, los tipos de datos indicados en los campos existan. Por ejemplo, no es posible crear un switch que tenga un campo status del tipo byte, ya que byte no representa ningún tipo existente en Python. Esta funcionalidad se realiza comprobando en el método __new__ que todos los valores de los campos de la clase a crear son instancias de type, ya que todo tipo de datos en Python es instancia de esta clase. Si queremos que un campo tenga un tipo de datos que no sea instancia de type, ese tipo de datos no puede existir. Otra funcionalidad añadida ha sido el chequeo de las cadenas con umbrales. Al añadir cadenas en nuestro lenguaje, surge un problema, y es que estamos creando un sublenguaje, el

60 Iteración 13: Refactorización del lenguaje de provisión

cual por muy simple que sea, puede complicar el desarrollo. Para asegurar que la sintaxis es la correcta se han añadido dos comprobaciones, dar como ilegales las cadenas que no contengan un operador (hasta el momento únicamente incluido el operador <) y quitar espacios en blanco sobrantes a las cadenas, de modo que a la hora de trocear la cadena, no se filtre ningún espacio en blanco no deseado.

4.13.2 Modificación almacenamiento interno de condiciones Hasta el momento las condiciones han sido almacenadas en el formato de una tupla con tres elementos, el id, el atributo y el valor del campo. Esta forma de almacenamiento, aunque simple no tiene la capacidad de ser indexada. Para solucionar este problema, un diccionario puede ser una buena opción, aunque un diccionario de diccionarios que indexe dispositivo y variable puede imponer ciertas limitaciones, ya que si por ejemplo queremos que una variable cumpla con varios umbrales, esta no podrá disponer de varios valores.

Tras discutir ventajas y desventajas se decidió desarrollar una solución intermedia, un diccionario indexado por dispositivo que contenga tuplas del formato (campo, valor). Para construir estas condiciones se modificó el método build_conditions, su resultado se puede observar en el Listado 4.24.

1 def build_conditions(self, conditions): 2 retval = {} 3 forc in conditions: 4 retval[c.id] = [] 5 for attr, value in c.items(): 6 if attr !=’id’: 7 retval[c.id].append((attr, value)) 8 return retval

Listado 4.24: Cambios del método build_conditions

4.13.3 Retrospectiva Realizadas las modificaciones de esta iteración, el lenguaje poseía todas las funcionalida- des básicas para ponerse en práctica y realizar automatizaciones completas realmente útiles. Para el usuario que escriba estas automatizaciones es importante hacerle señalar ciertos as- pectos.

A la hora de crear un evento, el compilador solo tendrá en cuenta el campos status del dispositivo que produce el evento. Como se ha podido apreciar, un evento es transformado en el lenguaje de provisionado al parámetro when, el cual consta de un único valor de un tipo de datos primitivo.

Al igual que en los eventos, en las acciones se encuentra una situación similar. Una acción del lenguaje scn es mapeada al lenguaje prv con el parámetro then, y este parámetro contiene

61 4. Desarrollo del Proyecto

únicamente un valor primitivo. En el caso de las acciones, el campos escogido también será el referente al campo status, ya que es en teoría el campo primario de un dispositivo.

Estas limitaciones están impuestas debido al uso de las interfaces ST, ya que limitan el contenido del mensaje a una variable de un tipo primitivo, impidiendo que un dispositivo comunique todos los campos o variables que representan su estado.

4.14 Iteración 14: Creación de escenarios HVAC

En esta iteración se procedió al desarrollo de un tercer escenario, correspondiente al esce- nario que va a ser llevado a cabo en la realidad. En este escenario, se contará con los dummies de un sensor de temperatura, que notificarán cual es la temperatura actual de la habitación, así como el dummy de un HVAC, que permitirá la modificación de un punto de consigna con la temperatura deseada para la sala. Este escenario se corresponde en realidad con dos distintos:

1. Un escenario que contará con un dummy de un termostato, el cual contendrá toda la inteligencia del escenario, sin las necesidad de requerir ningún operador ni crear automatización alguna. Esta parte enlazará el sensor de temperatura con el HVAC, y elegirá según la temperatura y el punto de consigna elegido, si el HVAC debe dar frío, debe dar calor o debe estar apagado.

2. Un segundo escenario, con los dummies de un sensor de temperatura y un HVAC total- mente independientes, que a partir de una automatización escrita con el lenguaje scn

se dote de inteligencia a este escenario. La interfaz ST del HVAC será IFloat, ya que se simulará el siguiente comportamiento. Si HVAC recibe un cero se apagará, si recibe un número positivo se pondrá la máxima temperatura disponible y se calentará la ha- bitación, si recibe un número negativo, se marcará la temperatura mínima disponible y se enfriará la habitación. Dado que el sensor de temperatura produce eventos del tipo flotante(una temperatura suele ser marcada por un cifra del tipo 23.8), el operador que conecte los dos servicios debe implementar una interfaz IFloat para recibir eventos flotantes.

Observando estos dos escenarios, se puede ver el gran potencial que el sistema Automaker posee. La primera solución dota al escenario de inteligencia, de una forma muy simple y rígida. En cambio, el segundo escenario puede ser dotado de la misma inteligencia que el primero, simplemente creando una automatización, incluso se pueden escribir escenarios más sofisticados únicamente usando Automaker, propiciando una solución muy flexible que puede ser aplicar a diversos campos de la domótica.

62 Iteración 15: Consulta del estado de los dispositivos en tiempo de ejecución

4.15 Iteración 15: Consulta del estado de los dispositivos en tiempo de ejecución Una funcionalidad muy interesante, y que muchos sistemas de automatización poseen es el almacenamiento de variables. El uso de una variable puede ser útil por ejemplo para mo- dificar el estado de un dispositivo en función de otro. Pensemos en el escenario en el que un switch se enciende y apaga del mismo modo que lo hace un segundo switch, sin el uso de va- riables se precisarían de dos reglas, una para encender el segundo switch cuando se encienda el primero y otra para cuando se apague. Con el uso de las variables, esta automatización no puede ser más sencilla, bastará con almacenar el estado del primer switch, y en la acción usar esa variable para indicar el estado del segundo switch. La sintaxis propuesta para la anterior automatización sería la presente en el Listado 4.25. Como se puede observar, el campos status de sw_02 es definido en función del mismo campo de sw_01, el cual será consultado en tiempo de ejecución por parte del operador. En la sintaxis de scn para el uso de variables se aprovecha el hecho de que se poseen instancias de objetos, representando los dispositivos del mundo real, evitando tener que capturar el estado en algún momento del programa scn creado. En el Listado 4.25 puede parecer extraño ver un evento formado por un enunciado que no sea una condición, haciendo uso de la función when, pero existen casos en el que el valor del evento es irrelevante como es el caso aquí comentado, donde lo único importante es la ocurrencia del evento.

1 Rule( 2 Event(sw_01) 3 )( 4 sw_02.set(status=sw_01.status) 5 )

Listado 4.25: Uso de variable en una automatización

Para representar la consulta del estado de un dispositivo en el lenguaje de provisión se ha creado la estructura Copy en la interfaz Automaker, estructura formada por el id del dispo- sitivo y el campo que debe ser consultado en tiempo de ejecución. Esta estructura de datos definida en el slice automaker.ice (ver Listado 4.26) será enviada al operador, para que lle- gado el momento de aplicar la acción, el operador obtenga el valor del campo del dispositivo correspondiente, pudiendo modificar el dispositivo destino de la acción con los datos ade- cuados.

Con el fin de que el operador opere correctamente la estructura Copy una vez recibida, hay que modificar su implementación, para que resuelva la variable a la que se refiere dicha estructura.

El momento más adecuado para resolver el contenido de Copy, es en el método set, una

63 4. Desarrollo del Proyecto

1 module Automaker{

3 struct Copy { 4 int deviceId; 5 int field; 6 };

8 sequence ConditionPredicate; 9 sequence ConditionList; 10 dictionary ConditionDict;

12 interface Operator { 13 void setEvent(string when); 14 void setAction(string then); 15 void setActionWithVar(Copy var); 16 void setConditions(ConditionDict conditions); 17 void commit(); 18 }; 19 };

Listado 4.26: Slice de Automaker con la estructura Copy

vez se ha evaluado el evento y las condiciones, y se sabe si el evento debe ser propagado. El campo del dispositivo al que se refiere esta estructura debe ser consultada en la caché del operador, ya que en teoría, es la información más actualizada que tiene el operador acerca de la realidad. La implementación de la consulta de variables por parte de un operador está presente en el Listado 4.27.

1 def set(self, new_value, sourceAddr=None, current=None): 2 if(self.match(new_value) and self.eval()): 3 if isinstance(self.then, Automaker.Copy): 4 then_value = self.get_var(self.then.deviceId, self.then.field) 5 else: 6 then_value = eval(self.then)

8 self.observer.set(then_value,"operator")

10 def get_var(self, id, field): 11 device_status = dict(self.cache[id]) 12 return device_status[field]

Listado 4.27: Consulta de una variable en tiempo de ejecución por parte de un operador

4.15.1 Inclusión del servidor de propiedades En el lenguaje, el usuario identifica en todo momento un dispositivo del mundo real gra-

cias a su identificador. En una aplicación distribuida ICE, ese identificador no es suficiente para poder identificar a un objeto y acceder a sus operaciones, para ello es necesario un proxy de un objeto. Dado lo anterior, en algún punto, el compilador debe convertir esos identifica- dores de dispositivos en proxies de los objetos, y hasta el momento, esta tarea se realizaba

64 Iteración 15: Consulta del estado de los dispositivos en tiempo de ejecución

en un archivo de configuración de ICE que contenía la correspondencia entre identidades y proxies. Como es obvio, el uso de un fichero de configuración puede ser útil en una fase temprana del sistema , e incluso en un entorno de pruebas, pero no puede ser la solución definitiva que queramos para el sistema. Dado este problema, y dada la cercanía de la entrega del proyecto, se decidió usar un servidor de propiedades. El servidor de propiedades utilizado es un servicio que ya estaba implementado, y que permite cargar un archivo con la correspondencia entre identidades y proxies, para más tarde, por medio de peticiones, obtener los proxies correspondientes a partir de las identida- des. La interfaz del servidor de propiedades puede ser observada en el Listado E.5.

Para hacer esta correspondencia de id con proxy, en el compilador se tiene la clase Resolver, la cual realiza una consulta con un id al servidor de propiedades. El código de la clase Resolver se corresponde con el presente en el Listado 4.28.

1 class Resolver: 2 def __init__(self, communicator): 3 self.ic = communicator

5 def resolve(self, identity, property_server): 6 return json.loads(property_server.get("{}| proxy".format(identity)))

Listado 4.28: Clase Resolver

4.15.2 Cambios en Condition, Event y Action Implementando las nuevas funcionalidades de esta iteración, así como observando los tests del sistema, se observó que había un bug que hacía que la comprobación de tipos creados por el usuario a partir de la clase Template no funcionase correctamente.

Si el lector recuerda, en la Sección 4.8 se explicó la metaclase Template, y como a partir de Statemente se generaban las acciones y condiciones. A la hora de usar Template para crear un objeto que heredase de Statement, se actualizaba la variable field_spec de la última clase mencionada, esta variable debe contener la especificación del tipo de los campos del objeto a crear.

El problema encontrado fue, que la variable field_spec era una variable de clase, que se actualizaba con el método update de la clase dict de Python, produciendo que la especifica- ción de campos de objetos creados con anterioridad se quedase almacenada en el diccionario e incluso que alguna especificación se sobreescribiese. Por ejemplo en el lenguaje, si se de- finía un Switch con un campo status booleano y mas tarde se definía un TemperatureSensor con un campo status entero, la especificación del campo status del Switch se modificaría a entero, produciendo un error en la comprobación de tipos del Switch.

65 4. Desarrollo del Proyecto

Para solventar esta problemática, en primer lugar se modificó Template, de modo que field_spec dejó de actualizarse con el método update, y se cambió por el operador =, eli- minando así todo el contenido previo de field_spec.

A continuación se debieron modificar los métodos when y set de la clase Statement, para que a la hora de generar instancias de Condition y Action, la especificación de campos que se le asigne fuese la correcta. Con este objetivo, primeramente Action y Condition dejaron de heredar de Statement, y en los métodos when y set se creaba un nuevo tipo de objeto (con la llamada type), que heredase la clase de la instancia que ha llamado a los métodos (como por ejemplo Switch) para que heredase el contenido de field_spec correspondiente. Para clarificar un poco, el código correspondiente a esta funcionalidad está presente en el Listado 4.29.

1 def when(self, **kwargs): 2 updated = dict() 3 updated[’id’] = self[’id’] 4 updated.update(kwargs) 5 condition_class = type(’Condition-{}’.format(random.randint(1,100)), (self.__class__, Condition), {}) 6 return condition_class(**updated)

8 def set(self, **kwargs): 9 updated = dict() 10 updated[’id’] = self[’id’] 11 updated.update(kwargs) 12 action_class = type(’Action-{}’.format(random.randint(1,100)), (self.__class__, Action), {}) 13 return action_class(**updated) Listado 4.29: Métodos when y set para la generación de condiciones y acciones

La clase Event también tuvo que ser modificada, convirtiéndose en una metaclase debido a la necesidad de sobrecarga el método __new__. Para heredar el valor correcto de field_- spec, hay que crear una nueva clase que hereda de la clase Event y de la clase que posea la condición pasada como parámetros, todo este proceso se realiza en el método __new_ _- anteriormente comentado. Al igual que Condition y Action, Event deja de ser una subclase de Statement. La nueva implementación es la clase Event, es visible en el Listado 4.30.

4.15.3 Nuevo nombre para el servidor de los Operadores Como ya se comentó en la Sección 4.14, es necesario modificar el nombre de los operado- res, con el fin de que cada regla genere un servidor con un nombre distinto. El primer paso será definir cual debe ser el contenido de estos nombres, para que sean los suficientemente descriptivos para poder identificar una acción en una regla. Tras un periodo de reflexión se decidió que todos los operadores partirán de un nombre base, el cual representará el tipo de datos que maneja el operador (Bool, Byte, Float, Int...).

66 Iteración 16: Implementación del escenario real

1 class Event: 2 def __new__(cls, condition): 3 event_class = type(’Event-{}’.format(random.randint(1, 100)), (Event, condition.__class__), {}) 4 return condition.__new__(event_class)

6 def __init__(self, condition): 7 if isinstance(condition, Statement) and isinstance(condition, Action): 8 raise IllegalEvent

10 super().__init__(**condition)

Listado 4.30: Clase Event

Para identificar la acción que corresponde al operador, al nombre del tipo de operador, se la debe añadir el nombre del archivo con el código fuente de las reglas que se están provi- sionando, la posición numérica que ocupa esa regla en el archivo, y la posición numérica de la acción dentro de la regla. Por ejemplo, en un archivo example.scn, una acción con un evento booleano situada en la segunda posición de la segunda regla del archivo, produciría el servidor de un operador con el nombre BoolexampleRule2Op2.

En resumen, el nombre de todos los operadores representarán una acción con el formato RuleOp.

4.16 Iteración 16: Implementación del escenario real

Para finalizar el proyecto, en esta iteración se va a proceder a implementar el escenario real correspondiente al escenario con dummies de la Sección 4.14. Para ello se necesitan dos componentes, un sensor de temperatura y una solución que permita controlar la temperatura del entorno, realizando la funcionalidad de un sistema HVAC.

Para el sensor de temperatura se ha elegido hacer uso de los sensores de domótica de Xiaomi denominados Aqara/Mijia. Los componentes necesarios serán el Gateway de Xiaomi, el cual centraliza y recibe los datos de los sensores, y un sensor de temperatura emparejado con el gateway.

Para el control del entorno, dado que el proyecto comenzó como una solución para el confort térmico en espacios inteligentes, se eligió el laboratorio de investigación del grupo ARCO situado en el ITSI de la UCLM. En este laboratorio se cuenta con un sistema HVAC, fabricado por Mitsubishi, al que se conectará la placa fabricada en la Sección 4.1, controlada por un microprocesador ESP8266 incorporado en una placa NodeMCU.

Una vez elegidos los dispositivos y el entorno en el que poder desplegar las automatiza- ciones, hay que prepararlo y programarlo para que los dispositivos ofrezcan servicios que puedan conectarse. En primer lugar, los dispositivos de Xiaomi tienen la peculiaridad de que toda la información de los sensores es recogida por el gateway, por lo que se debe desarrollar

67 4. Desarrollo del Proyecto

Figura 4.3: Solución fabrica para el control del HVAC

Figura 4.4: Gateway y sensor de temperatura de Xiaomi un programa que recoja la información del gateway, y notifique la temperatura cada cierto tiempo. El servicio del sensor de temperatura no lo va a dar el sensor como tal, sino un ser- vicio intermediario. Este servicio va a estar programado en Python, y para comunicarse con el gateway, va a hacer uso de la librería mijia, desarrollada por el grupo de investigación ARCO. La función de este servicio será consultar al gateway cada cierto tiempo la tempe- ratura que marca el sensor, para más tarde notificarla a un observador, en el caso de que lo tenga.

Por parte de la solución del HVAC, su funcionalidad será la de modificar el estado del

HVAC según la información que reciba por medio de la interfaz ST. Se pueden observar los siguientes tres casos:

Recepción de un valor 0: Si el nodo recibe un valor de 0, el HVAC se apagará.

Recepción de un valor mayor que 0: Si el nodo recibe un valor positivo, significa que el usuario quiere que el sistema caliente la habitación, por lo que pondrá la temperatura

68 Iteración 16: Implementación del escenario real

del sistema al máximo.

Recepción de un valor menor que 0: Si el nodo recibe un valor negativo, significa que el usuario quiere que el sistema enfríe la habitación, por lo que se pondrá la temperatura mínima del sistema.

Una limitación del escenario real respecto a los dummies del escenario de la Sección 4.14 es la imposibilidad de que el sistema de frío o calor a voluntad, esta decisión se encuentra centralizada para todos los HVAC del edificio, por lo que en esa parte no se poseía control. Para simular un comportamiento similar, se ha cambiado el dar frío por poner la mínima temperatura en el sistema, y dar calor por poner la máxima temperatura.

Una vez definidos los servicios, se procedió a realizar el grid con todos los servicios nece- sarios para poder provisionar escenarios de automatización.

En primer lugar, es necesario crear un servicio, que a partir del sensor de temperatura, pueda publicar la temperatura actual del entorno. Este servicio será un digital twin del sensor de temperatura de Xiaomi y estará escrito en Python. Para que el servicio a crear pueda comunicarse con el sensor de temperatura, se requerirá usar la librería mijia-smart-home, la cual se encuentra en el repositorio de pike5. Esta librería permite que, a través del gateway de Xiaomi el cual centraliza todos los datos, se puedan obtener los datos de todos los sensores e incluso añadir manejadores a los eventos generados por los sensores. El digital twin añadirá un manejador de eventos al sensor de temperatura, el cual cada vez que reciba un evento, lo propagará a su observador en el caso de que exista.

Además del sensor de temperatura, se requiere el nodo de control de temperatura. En este caso, el nodo debe ser programado en C, haciendo uso de PlatformIO (PIO) e ICEC. El comportamiento de este nodo ha de ser el mismo que el explicado en la escenario con dummies de la Seccion 4.14, por medio de la interfaz IFloat recibirá un valor numérico, y dependiendo de su valor realizará una de las siguientes acciones:

Recepción de un valor 0: Apagará el HVAC

Recepción de un valor positivo: Encenderá el HVAC y pondrá la temperatura máxima posible.

Recepción de un valor negativo: Encenderá el HVAC y pondrá la temperatura mínima posible.

De estos dos servicios, solo el primero, el de temperatura, estará registrado en una aplica- ción de IceGrid por lo que poseerá un proxy indirecto. En cambio el nodo de control HVAC, al usar ICEC no puede ser registrado en IceGrid, obligando a estar registrado en el servidor de propiedades con un proxy directo.

5http://pike.esi.uclm.es/

69 4. Desarrollo del Proyecto

El uso de un proxy directo puede ocasionar problemas en el caso que la dirección IP del nodo cambie. Esta problemática se solucionaría con el WelcomeService comentado en la Sección 4.5.2. Para que el escenario sea operativo, tanto el nodo de control como el digital twin del sensor de temperatura deben estar conectados al mismo punto de acceso, en el caso del escenario montado para este proyecto, ambos estaban conectados al punto de acceso citisim, situado en el laboratorio del grupo ARCO del ITSI. Una vez el escenario esté preparado, basta con escribir una automatización en el lenguaje scn y provisionarla para que nuestro entorno esté automatizado.

4.17 Iteración 17: Adición de soporte para Delays A pesar de no ser necesario para automatizar el entorno de confort térmico, y debido a la buena gestión del tiempo, se decidió añadir una funcionalidad al lenguaje que puede resultar interesante. Esta funcionalidad es la de permitir que el usuario ponga un Delay en una automatización, permitiendo que ciertas acciones de una regla se ejecuten unos segundos más tarde respecto a otras. Por ejemplo, en el Listado 4.31 se observa la forma en la que se pretende modelar estos delays. En esta regla, cuando se encienda el switch sw-01, el switch sw-02 se encenderá y a los 10 segundos se apagará.

1 Switch = Template(’Switch’, id=str, status=bool) 2 sw_01 = Switch(id=’sw-01’) 3 sw_02 = Switch(id=’sw-02’)

5 Rule( 6 Event(sw_01.when(status=True)) 7 )( 8 sw_02.set(status=True), 9 Delay(10), 10 sw_02.set(status=False) 11 )

Listado 4.31: Ejemplo de regla con Delay

Para la implementación de los Delays se ha decidido aprovechar la ventaja de tener un operador por acción. Todos los operadores de una regla que sean producto de una acción que se encuentren tras un Delay, harán un time.sleep con el tiempo requerido, antes de modificar el estado de un dispositivo. De este modo en el ejemplo del Listado 4.31, el operador que pone el estado de sw_02 a False esperará 10 segundos antes de realizar la acción. El tiempo que debe dormir un operador antes de aplicar un acción se señalará en la configuración del operador, por lo tanto la interfaz de automaker.ice vuelve a ser modificada, añadiendo soporte para el método setDelay (ver Listado E.6).

70 Capítulo 5 Conclusiones

N este capítulo se analizará el resultado obtenido una vez terminado el desarrollo, así E como el análisis de los distintos objetivos que se plantearon al principio del proyec- to. Una vez visto lo conseguido, se comentarán algunos de los trabajos futuros que se han planteado como necesarios durante el desarrollo.

5.1 Resultado del Proyecto El proyecto, inicialmente comenzó con la necesidad de dotar de inteligencia a un entorno, con el objetivo de ser confortable térmicamente para el usuario que lo habitase. El entorno elegido para realizar las pruebas y desarrollo de este proyecto fue el laboratorio de ARCO, situado en el ITSI, en el cual el sistema de control HVAC no funciona apropiadamente.

Dada la necesidad anterior, primeramente se solucionó el problema de las plataformas físicas que nos permitiesen tener un control absoluto sobre el confort térmico del entorno. Los dos aspectos básicos para el control térmico son, conocer cual es la temperatura del entorno y poder modificar esta temperatura. Como solución a la necesidad de conocer la temperatura, se decidió hacer uso de un sensor de temperatura del sistema Xiaomi Aqara. Respecto al control de temperatura, en el entorno ya se contaba con un HVAC como se ha comentado anteriormente, con el objetivo de controlar este sistema se fabricó una placa de control, la cual junto a un microprocesador ESP8266 pudiese controlar el encendido/apagado y la temperatura de consigna del HVAC (proceso de diseño, fabricación e instalación de la placa en el AnexoA).

Para poseer un control sobre el nodo HVAC se requería de un modelo semántico, que diese al usuario una relación entre los datos enviados al nodo y las acciones que deben ser tomadas. En este modelo se decidió que el nodo podía recibir tres tipos de datos, y por lo tanto podría tener tres acciones diferentes. Si recibe un 0 se apagaría el HVAC, si recibe un número positivo se encendería el HVAC y se calentaría el entorno y si recibe un número negativo se encendería el HVAC y enfriaría el entorno. Con el sensor de temperatura y el nodo de control fabricados ya se poseían las herramientas necesarias para controlar el entorno, el siguiente paso era dotar de inteligencia a estas herramientas.

Con el objetivo de obtener un entorno inteligente se decidió crear un sistema que per-

71 5. Conclusiones

mitiese especificar escenarios de automatización, pudiendo así automatizar el escenario de confort térmico que se nos presentaba, dotándolo de inteligencia. Este sistema es Automa- ker, cuya primera versión funcional ha sido desarrollada en este proyecto. Este sistema está compuesto por la sintaxis del lenguaje scn, un compilador para interpretar el código escrito por los usuarios y convertirlo en el lenguaje prv y una serie de operadores que permitan el conexionado entre los distintos servicios que pueda haber en el grid distribuido.

Con los dispositivos desplegados, y con el sistema Automaker, es posible especificar es- cenarios, permitiendo automatizar el entorno. Por ejemplo, observemos el funcionamiento del sistema con una automatización escrita en el lenguaje scn, cuyo propósito sea calentar el entorno cuando la temperatura sea menor a 20oC (ver Listado 5.1). El primer paso será compilar el archivo scn para obtener un archivo .prv que permita llevar la automatización al mundo real. Al ejecutarse el archivo prv, en primer lugar se provisionará un operador gracias a la factoría, para a continuación ser configurado, creando así un operador con la inteligencia necesaria para la automatización, en este caso la inteligencia consistirá en comprobar que la temperatura sea menor a 20o. Este operador, por medio del servicio Wirer, será enlazado con el sensor de temperatura y con el nodo HVAC, siendo el operador observador del sensor y el HVAC observador del operador provisionado. De este modo, cuando la temperatura del sensor cambie, ejecutará una llamada set a su observador (el operador), informándole así de la temperatura. El operador, a partir de su configuración, decidirá si la temperatura recibida cumple los requisitos (ser menor que 20), en el caso de que se cumplan, ejecutará el método set del HVAC con el número 5, consiguiendo que caliente el entorno según su modelo semán- tico. Este escenario se puede ver de una forma más visual en la Figura 5.1 para facilitar la comprensión del lector.

1 Thermometer = Template(’Thermometer’, id=str, status=int) 2 HVAC = Template(’HVAC’, id=str, status=int) 3 th_01 = Thermometer(id=’th-01’) 4 hvac_01 = HVAC(id=’hvac’)

6 Rule( 7 Event(th_01.when(status="<20")) 8 )( 9 hvac_01.set(status=5) 10 )

Listado 5.1: Código fuente del escenario de ejemplo

Uno de los resultados más interesantes obtenidos en este sistema, y que lo diferencia del resto de sistemas del mercado, es que las automatizaciones están soportadas por un sistema distribuido, por medio de los distintos operadores que pueden estar desplegados en diferentes nodos. Todos los sistemas presentados en la Sección 1.5.2 poseen un servidor centralizado, que soporta todas la carga de los mensajes. El sistema aquí presentado como ventaja, pre-

72 Resultado del Proyecto

Figura 5.1: Funcionamiento del sistema Automaker en el escenario del confort térmico

senta una mayor tolerancia a fallos, propiciando que el fallo en un servidor (en el caso de Automaker los servidores serían los operadores) no ocasione la caída de todo el sistema. Al ser un sistema distribuido, también hay un mayor reparto de la carga, al ceder la responsabi- lidad de las automatizaciones a los distintos operadores, y no dejarle toda la responsabilidad a un sistema central.

En definitiva, el sistema Automaker desarrollado en este proyecto, permite dar una solu- ción distribuida a la necesidad de confort térmico planteada inicialmente por el escenario realizado, pero este sistema no se reduce únicamente al confort térmico. Automaker puede ser una solución para la automatización de los entornos inteligentes, pudiendo facilitar el uso de las tecnologías domóticas, gracias a la integración de cualquier tipo de dispositivo y la posibilidad de realizar todo tipo de automatizaciones de una forma sencilla e intuitiva.

El código fuente del sistema Automaker puede ser encontrado en el repositorio del pro- yecto SymbIoT1, proyecto para el cual se ha desarrollado el sistema.

Los escenarios usados durante el desarrollo, el código fuente de esta documentación, así como los distintos operadores y suscriptores que se han necesitado en los escenarios de prueba pueden ser vistos en el repositorio de este TFG2.

1https://bitbucket.org/arco group/prj.symbiot/src/master/ 2https://bitbucket.org/arco group/tfg.jesus.fernandez/src/default/

73 5. Conclusiones

5.2 Objetivos Cumplidos Al principio de este documente en el Capítulo2 se plantearon una serie de objetivos a cumplir durante el desarrollo del proyecto. Tras repasar cuales fueron los objetivos planteados, el estado actual de los mismos es el siguiente:

Estudio comparativo de los lenguajes y sistemas existentes: Para lograr desarrollar el lenguaje, fue necesario el estudio de las distintas posibilidades que se ofrecían el mercado. Este estudio permitió tener un conocimiento general sobre las soluciones ya existentes, comprendiendo el estado del arte y adquiriendo el conocimiento necesario para el desarrollo de un sistema propio. Estudios de las necesidades de automatización: Con un conocimiento general de que sistemas ofrecía el mercado, se procedió a un estudio en profundidad sobre que limitaciones ofrecían estos sistemas y que podría necesitar el usuario que los siste- mas existentes no ofreciesen ya. Una vez hecho este estudio, se comprendieron los principales inconvenientes que tenían estos sistemas, llegando a la conclusión de que funcionalidades debía ofrecer nuestro sistema para diferenciarse del resto. Diseño de lenguaje de especificación: Una vez concluidos los estudios, se desarro- lló una sintaxis que fuese cómoda para el usuario, intuitiva y fácil de comprender y dominar. Este lenguaje estuvo muy inspirado por los sistemas expertos, realizando un lenguaje basado en reglas, que permitiese definir automatizaciones y bautizado con el nombre scn. Desarrollo de un procesador de lenguaje: Partiendo de la sintaxis, se desarrolló el procesador de lenguaje o compilador, únicamente con la capa semántica, que permitía analizar y almacenar la información de un archivo escrito en el lenguaje scn. Partiendo de esta información, se creó la sintaxis del lenguaje de provisionado prv, correspon- diente al lenguaje resultado de la compilación. Diseño y desarrollo de un sistema de provisionado: Al procesador de lenguaje, se le añadió la funcionalidad de permitir provisionar operadores para componer servicios, a partir de un archivo prv. La funcionalidad del sistema de provisionado en teoría no iba a formar parte del compilador, pero por comodidad, tanto para el usuario como para el desarrollador, se decidió añadir esta funcionalidad al procesador de lenguaje. Elaboración de escenarios relacionados con el control de temperatura: Una vez concluido el desarrollo del sistema, se desplegaron una serie de dispositivos reales ofreciendo una serie de servicios, más concretamente, un sensor de temperatura y una placa de control para el HVAC de un entorno. Con el sistema desarrollado, y los ser- vicios desplegados, se procedió a realizar una serie de automatizaciones relacionadas con el confort térmico para probar el sistema en un entorno real.

74 Trabajos Futuros

Observando el trabajo desarrollado en cada objetivo, así como el resultado del proyecto, se puede concluir que los objetivos han sido satisfactoriamente cumplidos.

5.3 Trabajos Futuros A pesar de que el desarrollo del proyecto ha concluido con todos los objetivos plantea- dos inicialmente, existen una serie de trabajos que no se han desarrollado, ya sea por su complejidad o por falta de tiempo, que son vitales para el correcto funcionamiento del siste- ma y para considerar que se han implementado todas las funcionalidades que un sistema de automatización de estas características exige. A continuación se explicarán algunos de los trabajos futuros planteados para este proyec- to.

5.3.1 Provisionado de operadores en un escenario anteriormente provisio- nado En el proyecto explicado en este documento, en todo momento se ha asumido que las automatizaciones que quiere el usuario en el entorno son las correspondientes a un único ar- chivo scn. En la realidad esto no es así, el usuario puede tener una serie de automatizaciones ya desplegadas, de distintos archivos scn, y seguir desplegando distintas automatizaciones. Estas situaciones pueden crear un problema ¿Qué se debe hacer con el sistema provisionado cuando el usuario quiera provisionar una nueva automatización? La respuesta más senci- lla sería provisionar el escenario de nuevo, pero al ser muy poco eficiente no es una buena solución. La mejor solución sería tener una mecanismo de persistencia (como una base de datos) donde tener almacenado que hay actualmente provisionado en el entorno, y cuando el usuario quiera provisionar alguna nueva automatización, comprobar el estado actual del entorno y hacer exclusivamente las modificaciones necesarias para incorporar la nueva auto- matización. De este modo, se podría tener constancia del estado actual del entorno en todo momento y se obtendría un sistema muy eficiente.

5.3.2 Incremento del análisis semántico Una parte muy importante de un compilador es la correspondiente al análisis semántico, ya que permite detectar inconsistencias en el programa escrito, tomando como referencia la definición del lenguaje. Por ejemplo, algunas de las inconsistencias más comunes a la hora de escribir un programa son la inconsistencia de operadores, cuando se intenta realizar una operación entre dos tipos no permitido, como puede ser sumar a un entero una cadena de texto. Además de detectar este tipo de errores, el analizador semántico debe ser capaz de ofrecer al usuario un mensaje de error significativo, con el que el usuario pueda detectar y solucionar su error. En el caso del sistema aquí desarrollado, estamos hablando de un compilador formado principalmente por la capa de análisis semántico, por lo que el análisis de la semántica del

75 5. Conclusiones

código escrito por el usuario es la parte más importante del compilador. En el estado actual, este análisis semántico no está muy desarrollado detectando únicamente pequeñas inconsis- tencias en reglas aisladas.

Como trabajo futuro, hay que mejorar la parte del análisis semántico, por medio de la adición de distintas funcionalidades. La principal de ellas será la comparación de las reglas definidas por el usuario, tanto las que ya están provisionadas como las que no, con el obje- tivo de asegurar que no se provisionen dos reglas contradictorias, ocasionando un mal fun- cionamiento del sistema. En el caso de que reglas inconsistentes sean detectadas, se deberá informar al usuario de su error para que pueda realizar las modificaciones pertinentes.

Un ejemplo de dos reglas contradictorias podría ser la presenta en el Listado 5.2. En esta regla el usuario está creando dos reglas, que dadas las mismas condiciones, debe modificar el mismo dispositivo con valores contradictorios, produciendo una inconsistencia, la cual es imposible llevarla a la realidad.

1 Rule( 2 Event(sw1.when(status=True)) 3 )( 4 sw2.set(status=True) 5 )

7 Rule( 8 Event(sw1.when(status=True)) 9 )( 10 sw2.set(status=False) 11 )

Listado 5.2: Dos reglas inconsistentes

5.3.3 Temporalidad en el sistema El sistema desarrollado, una vez compila y despliega una escena, da como resultado un sistema distribuido, formado por los dispositivos que se encuentran en el entorno y los opera- dores que los conectan. Un problema muy importante que sufren los sistemas distribuidos es la ausencia de reloj global, produciendo una serie de complicaciones a la hora de sincronizar los distintos procesos.

Esta problemática está presente en este sistema, siendo los mensajes los eventos produ- cidos por los dispositivos, las acciones que deben ser aplicadas en los mismos y las actua- lizaciones de caché de los operadores. El envío de todos estos mensajes pueden producir problemas e inconsistencias en el sistema, ya que si un mensaje es enviado antes que otro, nada asegura que este llegue primero. Por ejemplo, imaginemos una regla que dependa del estado de un sw1 como condición, si el evento se produjese antes que el cambio de estado del sw1, pero la caché del operador se actualizase un poco antes de la llegada del evento,

76 Trabajos Futuros el resultado de la automatización no sería el deseado. Estas circunstancias dotarían de cierta incertidumbre al sistema, provocando resultados impredecibles. Para solucionar esta problemática, se podría hacer uso de lo denominado relojes lógicos o de Lamport[CDKB12]. Un reloj lógico simplemente es un contador software con el que cuenta cada proceso del sistema, que se incrementará con cada evento en el proceso, y cuyo valor en el momento de envío de un mensaje será el timestamp de ese mensaje. Siendo los eventos e y e’, se considera que e fue anterior a e’ si L(e) es menor que L(e’), siendo L el valor del reloj lógico del evento correspondiente. Estos relojes permiten obtener una ordenación de los eventos, a pesar de que estos eventos puedan haber sido concurrentes. La aplicación de los relojes lógicos no permitirá a nuestro sistema una correcta ordenación temporal de los mensajes, pero paliará un error muy importante, la incertidumbre del sistema. Gracias a los relojes lógicos, da igual las circunstancias que se produzcan, el sistema siempre se comportará del mismo modo, sin importar el orden en el que lleguen los mensajes al operador, ya que estos estarán ordenados lógicamente. El timestamp debe ser añadido a cada uno de los mensajes enviados en el sistema, para que el operador pueda conocer el orden de cada mensaje o evento.

5.3.4 Mejora semántica de los mensajes Dado el desarrollo del sistema explicado en este documento, los mensajes enviados por los distintos componentes que forman un entorno automatizado vienen definidos por las in- terfaces de ST. Esto produce que por ejemplo, un dispositivo pueda comunicar únicamente un dato primitivo para comunicar su estado. Durante el desarrollo de Automaker, y más con- cretamente del lenguaje scn, se ha considerado que el estado de un dispositivo del entorno se define por una serie de campos diferentes, habiendo siempre un campo principal denomina- do status. Dada esta peculiaridad, el uso de las interfaces ST limitan el sistema, produciendo que un dispositivo solo pueda comunicar un campo de su estado, y no lo que realmente sería su estado completo. Para que un dispositivo pudiese comunicar su estado completo, se debe usar otro meca- nismo que no sean las interfaces ICE de ST. La solución que se plantea aquí, para realizar en un futuro, es el uso de Protocol Buffers, un método de comunicación que permite la serialización de datos y que está soportado por ICE. Gracias a Protocol Buffers3, un método de serialización de datos estructurados, se podría definir una nueva interfaz genérica, que contenga un hecho del mundo, formado por el estado de un dispositivo. La nueva interfaz propuesta está presente en el Listado 5.3. Como se puede observar, en el método modify se define un objeto del tipo Fact, que teóricamente debe contener el estado de un objeto, formado por varios campos con su valor correspondiente. En la práctica, la implementación de Fact se realiza por medio de Protocol Buffers, y un ejemplo

3https://developers.google.com/protocol-buffers/

77 5. Conclusiones

simple se encuentra en el Listado 5.4.

En este ejemplo, Fact es un mensaje, que a su vez se forma por dos mensajes definidos anteriormente. El primero es una cabecera, que contendrá información obligatoria para ca- da mensaje, sin importar de que dispositivo provenga. El segundo mensaje es un mensaje selectivo, es decir puede ser o un tipo de mensaje Motion o Temperature, diferenciando así el mensaje para cada tipo de dispositivo, y la información que contiene. De este modo, un dispositivo no tiene que enviar únicamente el valor de un campo, envía un mensaje con la información que requiera según el tipo de dispositivo que sea.

1 module semantic { 2 ["python:protobuf:fact_pb2.Fact"] sequence Fact;

4 interface FactSink { 5 void modify(Fact f); 6 }; 7 };

Listado 5.3: Interfaz haciendo uso de Protocol Buffers

1 syntax = "proto3";

3 import "/protobuf/timestamp.proto";

5 message Header { 6 string id = 1; 7 google.protobuf.Timestamp t = 2; 8 }

10 message Motion { }

12 message Temperature { 13 float status = 3; 14 }

16 message Fact { 17 Header header = 1; 18 oneof body { 19 Motion motion = 2; 20 Temperature temp = 3; 21 } 22 }

Listado 5.4: Definición de Fact con Protocol Buffers

5.4 Justificación de Competencias: Ingeniería de Computadores A lo largo del desarrollo de este proyecto y Trabajo Fin de Grado, se han desarrollado las siguientes competencias, relacionadas con la intensificación de Ingeniería de Computado-

78 res.:

1. Capacidad de diseñar y construir sistemas digitales, incluyendo computadores, siste- mas basados en microprocesador y sistemas de comunicaciones. 2. Capacidad de desarrollar procesadores específicos y sistemas empotrados, así como desarrollar y optimizar el software de dichos sistemas. 3. Capacidad de analizar y evaluar arquitecturas de computadores, incluyendo platafor- mas paralelas y distribuidas, así como desarrollar y optimizar software para las mis- mas. 4. Capacidad de diseñar e implementar software de sistema y de comunicaciones. 5. Capacidad de analizar, evaluar y seleccionar las plataformas hardware y software más adecuadas para el soporte de aplicaciones empotradas y de tiempo real. 6. Capacidad para analizar, evaluar, seleccionar y configurar plataformas hardware para el desarrollo y ejecución de aplicaciones y servicios informáticos. 7. Capacidad para diseñar, desplegar, administrar y gestionar redes de computadores.

La realización del prototipo de confort térmico, que implica el diseño e implementación de un sistema empotrado con capacidades avanzadas de comunicación justifica las compe- tencias 1, 2, 4, 5 y 7. El desarrollo del compilador, configuración y despliegue de la plataforma distribuida que da soporte a la funcionalidad del sistema cubre las competencias 1, 3, 4, 6, 7 y 8.

79

ANEXOS

81

Anexo A Desarrollo de la placa de control para el HVAC

A.1 Fabricación de la placa de control

A lo largo de esta sección se explicará todo el proceso requerido para el diseño, fabricación e instalación de la placa necesaria para controlar la centralita HVAC de Mitsubishi, usada para modificar la temperatura del entorno en este proyecto. Para guiar el proceso de fabricación, se tomó como referencia [Kha05].

A.1.1 Diseño de la placa con DesignsparkPCB En este proceso se revisó un diseño anteriormente desarrollado. Este diseño, se empezó a realizar en base a la centralita Mitsubishi (ver Figura A.1) que se tenía en el laboratorio de investigación del grupo ARCO en el ITSI.

En un principio, la solución planteada debía ser lo menos invasiva posible y requerir de una modificación del HVAC que no fuese muy significativa, por lo que se optó por crear un sistema que emulase la pulsación de los botones disponibles en la centralita. Para este proceso se abrió la centralita de Mitsubishi, y se comprobó el contacto y cableado de cada uno de los botones. La funcionalidad de la placa a fabricar debía ser, a partir de una salida del microprocesador, poder cerrar los contactos de cada uno de los botones. Para lograr esta funcionalidad, había dos opciones, el uso de relés, los cuales eran una solución muy voluminosa y poco eficiente, o la solución por la que se optó que fue el uso de octacopladores cuya salida pudiese sustituir a un relé. Además, una gran ventaja de los octacopladores es que proporcionan aislamiento eléctrico.

Además de la pulsación de los botones, sería deseable una solución en la que se obtuviese información de si la centralita está encendida o apagada, esto también es conseguido colo- cando un octacoplador serie al lado del led de encendido de la centralita, pudiendo leer su estado como entrada del microcontrolador.

Por último, la placa fue diseñada como una placa apilable de NodeMCU, obteniendo una solución reutilizable, junto a una solución barata de un módulo WiFi como la que ofrece NodeMCU.

El esquemático resultante de este proceso de diseño puede ser encontrado en el AnexoB.

83 Figura A.1: Centralita Mitsubishi

A.1.2 Fabricación de la placa Una vez revisado y verificado el diseño es el momento de fabricar el PCB. Para ello se hizo uso de las siguientes herramientas:

Máquina de prototipado para PCB de la empresa LPKF Software CircuitCam Software BoardMaster Herramientas de la máquina LPKF Placa de fibra de vidrio recubierta de cobre En el caso práctico que se va a estudiar, para el uso de software compatible con la máquina de fabricación LPKF que se poseía, se usó una máquina virtual Windows XP con el software necesario instalado.

Operación con CircuitCam En primer lugar, a partir de nuestro diseño, se deben obtener unos archivos compatibles con la máquina LPKF para su fabricación. Con este objetivo se va a hacer uso del progra- ma CircuitCam, importando los archivos con formato Gerber resultado del diseño de la placa con DesignSparkPCB. Estos archivos pueden ser encontrados en la carpeta plots del proyecto. Los pasos a seguir son los siguientes: 1. Para empezar, se abre CircuitCam, y se deben importar los archivos Gerber que des- criben las capas de la placa (File ->Import...), obtenidos al realizar el diseño con el software elegido (en el caso de ejemplo DesignSparkPCB). Para ser concretos, los ar- chivos Gerber que se deben importar son los correspondientes a las capas top, bottom,

84 de contorno y de taladrado, sus respectivos nombres en el diseño son Top Copper.gbr, Bottom Copper.gbr, Board Outline.gbr y Drill Data.drl 2. El programa pedirá una identificación por cada capa que se quiera importar, es decir, CircuitCam necesita saber a que capa corresponde cada uno de los archivos. Por lo tanto, a cada archivo se le debe asignar su Layer/Template correspondiente (ver Figu- ra A.2). A la hora de hacer la correspondencia hay que tener cuidado con las escalas de la capa de taladrado (DrillData), abajo a la derecha en el apartado digits hay que cambiar la escala 2:4 que viene por defecto por la escala 2:5.

Figura A.2: Correspondencia de cada archivo con su capa

3. Una vez importados los archivos se presentará una interfaz que representará nuestra placa (Ver Figura A.3). Observando la interfaz, a la izquierda, se pueden observar seis iconos (los cuales están marcados en rojo). Estos iconos corresponde con los seis pasos ordenados que hay que seguir para obtener los archivos de salida deseados. El primer icono corresponde con la importación de archivos, paso que ya ha sido completado y que también podría haber sido realizar pulsando dicho botón. 4. El segundo paso corresponde con el segundo icono de la izquierda, y su objetivo es el de indicar como se quiere realizar el contorno o corte externo de la placa. Hay que pensar que la placa debe ser extraída y cortada de la placa recubierta de cobre, por lo que si la máquina LPKF realizase el corte completo, al llegar a la última esquina, la broca seguiría rozando la placa, la cual se quedaría totalmente libre y saldría volando. Con el objetivo de evitar este hecho, la máquina no cortará la placa por completo, dejando algunos pequeños trozos sin cortar del contorno, para que el usuario la extraiga como si la placa estuviese situada en un molde. Al pulsar sobre el botón, aparecerá la

85 Figura A.3: Interfaz CircuitCam

ventana de configuración del contorno (ver Figura A.4), en la que hay que dejar la mayoría de parámetros por defecto, solo hay que indicar que la máquina debe dejar cuatro uniones sin cortar en los laterales de la placa (4 edges) con un ancho de un milímetro (Tab Width: 1mm). Una vez elegidos los parámetros se debe pulsar el botón Run ya que con el botón Ok el contorno no se realizaría. 5. El paso correspondientes al tercer icono no es necesario en nuestro diseño, ya que su objetivo es el de realizar cortes internos, los cuales nos están presentes en la placa que se está diseñando. 6. El objetivo del cuarto icono es el de realizar limpieza completa de cobre en algunas zonas de la placa. Ya que la placa que esta siendo diseñada no requiere de limpieza de cobre, este paso también puede ser ignorado. 7. En el quinto paso se aislarán las capas y su ejecución es tan simple como pulsar el quinto icono. 8. El sexto y último paso correspondiente al sexto icono es el de exportar el proyecto. En este paso únicamente se debe elegir la ruta donde almacenar el proyecto, el cual estará preparado para su interpretación y ejecución por parte de la máquina LPKF por medio de BoardMaster. Como resultado se obtendrá un archivo del tipo LMD

Operación con BoardMaster Una vez finalizado el proceso de operación con CircuitCam se tendrán las condiciones óptimas para comenzar la fabricación de la placa y para ello se hará uso del software Board-

86 Figura A.4: Modificar parámetros del contorno

Master y de la máquina de impresión LPKF. A continuación, se muestran los pasos a seguir para finalizar la impresión de forma ordenada, intercalando instrucciones tanto del manejo del software como del manejo de la máquina.

Figura A.5: Máquina LPKF usada para la impresión de la placa

Antes de iniciar el programa BoardMaster es muy importante que la máquina LPKF se encuentre encendida, en caso contrario el software no detectará la máquina correctamente. Una vez la máquina esté encendida ya se podrá iniciar el software BoardMaster.

87 El propio software al iniciarse preguntará al usuario, por medio de una ventana, si hay alguna herramienta insertada en la máquina con la pregunta «¿Dónde está la herramien- ta?». Las herramientas son unas pequeñas brocas que se colocan en unos orificios metálicos, situados al border de la mesa de trabajo (Ver Figura A.6). Tras comprobar que en efecto la máquina se encuentra limpia y que no posee ninguna herramienta en su interior se debe clickar en OK.

Figura A.6: Mesa de trabajo de la máquina LPKF

A continuación en pantalla aparecerá la interfaz de usuario de BoardMaster. Esta interfaz puede parecer algo compleja por lo que a continuación se explicarán algunos de los detalles y funcionalidades más importantes que se usarán a lo largo del proceso de impresión (ver Figura A.7): 1. Esta lista desplegable contiene los distintos pasos que se deben seguir a lo largo del proceso de impresión.

2. Lista desplegable con el nombre de las herramientas configuradas en el software para el proceso de impresión.

3. Herramientas representadas gráficamente conforme deben estar situadas en la mesa de trabajo. Como se puede observar, a cada herramienta le corresponde un color, el cual posee la herramienta real. Por ejemplo el color naranja representa herramientas de limpieza, el rosa herramientas de limpieza de mayor grosor, el verde taladros, el blanco representa que no hay ninguna herramienta colocada y el amarillo herramientas de corte.

4. Cruceta de selección que permite seleccionar una coordenada concreta de la mesa de trabajo para situar el cabezal sobre ella.

88 5. Botón que extrae la mesa de trabajo para que se pueda operar con ella, por ejemplo para situar placas de cobre y colocar las herramientas. Será referido como botón de parking debido a su semejanza con la señal vial. 6. Flechas de desplazamiento que nos permiten desplazar la broca manualmente. Las flechas de la izquierda nos permiten desplazar el cabezal en los ejes X e Y las flechas de la derecha nos permiten desplazarlo en el eje Z. El número indicado en cada grupo de flechas es las unidades que se va a desplazar el cabezal por un click en una flecha. 7. Estos 4 botones forman un conjunto que permite manejar el footprint de la placa. El botón de abajo a la izquierda permite mover la placa por el área de trabajo, y el de abajo a la derecha duplicarla. Los de arriba son botones de selección que permiten indicar pads y pistas que se quieren seleccionar, el de la izquierda solo seleccionará aquello que se le haya indicado y el de la derecha seleccionará todos lo que esté conectado a las pistas y pads indicadas. 8. Botón para iniciar y parar los distintos pasos que se deben seguir para realizar la im- presión. 9. Representación virtual de la mesa de trabajo. 10. Botones de adición de pads y pistas. Una vez se tiene el footprint cargado en el pro- grama, el botón + permite añadir algunos pads y pistas para operar con ellos y el botón - permite quitar la adición. Los botones Alt+ y Alt- añaden y eliminan todos los elementos del footprint respectivamente. En los pasos de la impresión ningún pad o pista se imprimirá hasta que no sean añadidos con estos botones, a pesar de que sean seleccionados con los botones de selección. Una vez el programa esté abierto la máquina debe ser preparado para el proceso de im- presión. En primer lugar, hay que colocar la placa recubierta de cobre en la que se realizará el recorte para extraer la placa en la mesa de la máquina; la placa tiene dos agujeros en los laterales, los cuales deben encajar a la perfección con dos puntos de enganche que tiene la mesa de la máquina, con el objetivo de que los pads y las pistas de las dos capas de la placa coincidan correctamente. Importante, siempre que se maneje una placa con las manos obligatorio el uso de guantes ya que la grasa de las manos con el tiempo produce oxidación. Una vez colocada la placa, se debe proceder a la colocación de las herramientas. Es muy importante que en la máquina se coloquen las mismas herramientas que aparecen en BoardMaster en su sitio correspon- diente, si no es así el proceso de impresión del PCB puede ser defectuoso. Lo esencial es que al colocar las herramientas, la máquina y el entorno virtual de BoardMaster queden en el mismo estado. Al cargar un diseño el software sabe que herramientas necesita, por lo que si en BoardMaster falta alguna herramienta el software avisará al usuario. Las herramientas deben ser colocadas con cuidado siendo introducidas con la broca bo-

89 Figura A.7: Interfaz del software BoardMaster ca abajo en los orificios de las herramientas, y en este caso prescindiendo del uso de los guantes para no mancharlos. Las herramientas que se usaron para la impresión de esta placa fueron: 1. Universal Cutter 0.2 mm marking 2. End Mill 1.0 mm 3. Universal Cutter 0.2 mm 4. Spirall Drill 0.7 mm 5. Spiral Drill 0.8 mm 6. Spiral Drill 0.9 mm 7. Spiral Drill 1.0 mm 8. Spiral Drill 1.2 mm 9. Sin herramienta 10. Contour Router 2.0 mm Cuando todas las herramientas estén colocadas, se debe cerrar la tapa y volver a la interfaz BoardMaster para señalar un área de trabajo donde se moverá el cabezal de la máquina. Para señalar el área deseada, lo primero hay que ir a la lista desplegable de las herramientas y seleccionar la primera, acto seguido, el cabezal se moverá hasta coger la primera herramienta. Una vez que la máquina tenga la herramienta, hay que desplazar el cabezal (ya sea con la cruceta de selección o las flechas de desplazamiento) a la zona que va a ser la esquina inferior

90 Figura A.8: Herramientas colocadas en la máquina LPKF izquierda del área de trabajo, y cuando se haya llegado al punto deseado se debe confirmar la selección con Configuración->Material->Seleccionar Esquina Inferior. El siguiente paso será señalar la esquina superior derecha, se procede del mismo modo para desplazar el cabezal de la máquina y cuando se llegue al punto deseado Configuración->Material- >Seleccionar Esquina Superior. Como se podrá observar en la interfaz, habrá un recuadro más oscuro que representará el área de trabajo elegida (ver Figura A.9). Es recomendable que el eje de simetría atraviese la mitad del área de trabajo para hacer unas impresiones más precisas, puesto que cuanto mas se aleje el cabezal del eje de simetría, peor será su precisión. A continuación, hay que importar el archivo LMD resultado del trabajo realizado con CircuitCam, para ello se debe seleccionar Archivo->Importar->LMD y después introducir la ruta donde se almacenó el fichero. Tras importarlo, el footprint de la placa aparecerá en el área de trabajo (si es necesario hacer zoom para observar mejor). Llegados a este punto es el momento de seguir los pasos de impresión que se pueden encontrar en la lista desplegable (algunos pasos no deben ser realizados por lo que simplemente serán omitidos): 1. Marking Drills: Primer paso del proceso de impresión, su objetivo es el de marcar los taladros, para que llegada la hora de taladrar, el taladro no resbale y los pads y pistas se desplacen. Se seleccionan todos los pads y pistas con el botón Alt+ y se pulsa el botón Start. Una vez termine el proceso, se puede observar si el proceso se ha realizado correctamente pulsando sobre el botón parking y viendo el resultado en la placa.

2. Drilling Plated: En este paso la broca atravesará la placa y creará los pads. Dado que tampoco es una tarea muy delicada se pueden añadir todos los pads con el botón Alt+ e iniciar el proceso con Start.

91 Figura A.9: Área de trabajo seleccionada

Figura A.10: Footprint de la placa tras importar el archivo

3. Milling Bottom: Aquí la máquina realizará las pistas que conectan los pads. Para comprobar que la máquina está calibrada, con el botón de selección de la derecha se deben indicar pequeñas pistas aisladas que rodeen los pads de la placa, añadirlos con el botón + y realizar la impresión. Si tras la impresión, se ve que la pista está limpia,

92 se pulsa sobre el botón Alt+ para realizar la impresión completa de las pistas. 4. Ya se ha terminado la impresión de la capa bottom, por lo que se debe abrir la tapa de la máquina y con los guantes, girar la placa, colocándola correctamente sobre los puntos de sujeción de la mesa. 5. Milling Top: Con este paso se llega a los momentos más críticos de la impresión. Al girar la placa se puede dar el caso de que las pistas no correspondan con los de la capa bottom, pudiendo ocasionar malas conexiones. Para solventar este problema, se puede proceder como en el caso anterior, imprimiendo pequeñas pistas que rodean pads y comprobando su impresión. Si las pistas no coinciden bien con el pad, se debe modifi- car el origen de la máquina. Con este fin se pulsa sobre Configuración->Selecciones de Máquina, y en la ventana que aparece (ver Figura A.11) se pulsa sobre Desblo- quear para mediante prueba y error, imprimir distintas pistas, modificando las coor- denadas del Home hasta que las pistas coincidan correctamente con el pad.

Figura A.11: Ventana de modificación de las coordenadas del Home

6. Cutting Outside: Última etapa en el software. En esta etapa la máquina realizará el corte externo, dejando los espacios sin cortar que se indicaron en CircuitCam. Cuando los pasos hayan finalizado, se pulsa sobre el botón parking para extraer la mesa de trabajo, y con los guantes, coger la placa de cobre y extraer los PCBS impresos. Una vez extraídas se las aplica una laca protectora y se liman los bordes para poder cogerla con las

93 manos desnudas. Se extraen las herramientas y se apaga la máquina. El proceso de impresión ha finalizado.

Figura A.12: Ejemplo de dos placas tras la impresión. En esta foto es observable las uniones de 1 mm que se indicaron a CircuitCam que no se debían cortar

A.1.3 Soldado de componentes Llegados a este punto la placa está impresa, pero aún no tiene ninguna utilidad práctica, puesto que hay que soldarle todos los componentes que se tuvieron en cuenta a la hora de realizar el diseño. Los elementos necesarios para realizar el soldado son:

Estación de soldadura.

Componentes Surface Mounted Device (SMD): cuatro Resistencias de 330 Ω, una Re- sistencia de 750 Ω y un Condensador de 100 nF.

Estaño.

Chip PC817. Octacoplador de cuatron pines.

Chip TLP597GA. Octacoplador de seis pines.

Tiras de pines.

Patillas de condensadores para las vías.

Flux para mejorar el agarre del estaño.

Polímetro.

Conexión molex

La primera tarea a ejecutar es la comprobación de las conexiones de las pistas, mediante un polímetro se debe comprobar que las pistas estén aisladas del resto del cobre para confirmar que el proceso de fabricación ha sido el adecuado.

A continuación, se enciende la estación de soldadura, fijando su temperatura a unos 400 oC. Debido a la laca que se echó sobre la placa como protección al finalizar el proceso de

94 Figura A.13: Placa lista para ser soldada impresión, es recomendable rascar con una lima las zonas donde se van a soldar componentes para una conexión más limpia y estable.

En primer lugar, se deben soldar todos los SMDs en la capa BOTTOM, en el caso de esta placa se necesita soldar cuatro resistencias de 330 Ω, la resistencia de 750 Ω y el conden- sador de 100 nF. Estos componentes SMD deben ser colocados en las figuras rectangulares impresas en la placa (observar atentamente Figura A.13), si al lector le es difícil encontrar la localización de cada componente, se puede ayudar del diseño realizado en secciones ante- riores, observando el footprint de DesignSparkPCB, además es de gran utilidad saber a que chip va conectado cada SMD; por ejemplo el condensador está conectado al octacoplador de cuatro pines y es el único componente situado verticalmente (observando la placa tal y como está en la Figura A.13), lo que facilita encontrar su localización.

Para un soldado apropiado de los componentes, primero hay que echar flux (resina adhe- rente que mejora sustancialmente la adherencia del estaño), aplicar un puntito de estaño en la conexión donde se debe soldar el componente, y con cuidado soldar ambos lados (como ayuda para el soldado de SMDS ver Figura A.14).

Una vez se tengan los componentes SMDs soldados, se comprueba que su conexión es la apropiada midiendo la resistencia o capacidad del componente entre dos conexiones de la placa, y comparándolo con le medida esperada (por ejemplo si entre dos conexiones hay una resistencia de 330 Ω el resultado debe ser también de 330 Ω). Una vez comprobado que el soldado de los componentes ha sido el adecuado, se procede del mismo modo para el soldado de las vías en los pads correspondientes (para reconocer las vías ver el footprint de DesignSparkPCB puede ser de gran ayuda) aprovechando las patillas de unos condensadores.

95 Figura A.14: Componentes SMD soldados en la placa

Al finalizar el soldado de las vías, observar con un polímetro que hay conexión entre las dos capas de la placa. Por último, cambiando a la capa TOP, hay que soldar el conector molex que conectará con la terminal de la calefacción y los chips PC817 y TLP597GA (estas conexiones son fáciles de encontrar ya que son componentes through-hole y corresponden con los pads que se en- cuentran en la zona central de la placa). Además, se deben soldar en los pads de los extremos de la placa unas tiras de pines, que permitan que en la placa se acople un NodeMCU como si de un shield se tratase. Si las tiras de pines son muy grandes pueden ser recortadas. Cuando todos estos pasos estén completados la fabricación de nuestra placa habrá finali- zado, teniéndola preparada para su correcto funcionamiento.

A.1.4 Instalación del PCB Por último, una vez fabricada la placa es necesario realizar su conexionado con la centralita del laboratorio. Para realizar esta tarea, se volvió a abrir la centralita y se extrajo la placa que la compone (ver Figura A.15). Una vez extraída la placa, se procedió al soldado de los cables con el PCB fabricado, para después incorporar de nuevo la placa en la centralita con el PCB ya conectado.

Terminado este paso, el nodo para el control del HVAC estaba preparado para ser utiliza- do.

96 Figura A.15: Placa extraída de la centralita

97

Anexo B Esquemático de la placa

En este Anexo se muestra el esquemático que se diseñó con DesignSpark y que fue uti- lizado para realizar la impresión de la placa de control del HVAC. En la imagen se puede observar como fueron realizadas las conexiones internas entre NodeMCU y la centralita, así como los distintos componentes que se necesitaron para realizar las conexiones de forma que la placa se comportase tal y como se quería.

99 $ % & ' ( )

 iuaB1 sumtc el lc econtrol de placa la de Esquemático B.1: Figura

 100



 352-(&7 6PDUW%XLOGLQJ '5$:,1*7,7/( (63EDVHG7HPSHUDWXUH&RQWURO '5$:1%< ;DYLHUGHO7RUR-HV¼V)HUQ£QGH] 5(9,6,21 Y

6+((72)  67$786 '$7(  '(6,*163$5.3&%DYDLODEOHIRU)5((DWZZZ'HVLJQ6SDUNFRP3&% Anexo C Diagrama de clases

A continuación se puede observar el diagrama de las clases colaboradoras del sistema Automaker, las cuales permiten la generación de los archivos en el lenguaje destino y el pro- visionado de operadores (ver Figura C.1). El lector ya habrá notado que el sistema parece dividirse en dos aplicaciones, ya que el dia- grama se puede dividir en dos conjuntos de clases. Esto se debe a que en definitiva, Automaker divide su trabajo en dos tareas esenciales, primeramente la compilación del archivo con el código fuente, y posteriormente el provisionado de operadores dado el código generado.

Figura C.1: Diagrama de clases

101

Anexo D Manual de usuario

D.1 Introducción En este Anexo se explicará al usuario como hacer uso del sistema Automaker, para escribir sus propias automatizaciones del modo correcto. El principal conocimiento que debe tener un usuario para hacer uso de Automaker, es el de conocer el lenguaje scn, el cual es utilizado para especificar escenarios de automatización.

El lenguaje scn permite escribir escenarios de automatización definiendo reglas, formadas por una serie de condiciones y acciones.

El código fuente del sistema automaker se encuentra en el repositorio del proyecto Sym- bIoT1

D.2 Creación e Instanciación de tipos de Dispositivos

El elemento esencial sobre el que se trabaja en scn son los dispositivos. Un dispositivo es una entidad, que representa un sensor o actuador del mundo real dentro del lenguaje. Los dispositivos de scn serán instancias de objetos, cada instancia representando un servicio del mundo real.

El primer paso para hacer uso de scn es el de poder definir tipos de dispositivos, a partir de los cuales se puedan instanciar representaciones de elementos del mundo real dentro del lenguaje. Con el fin de crear estos tipos, scn cuenta con la utilidad Template, la cual permite definir clase de dispositivos, a partir de un nombre de clase, los campos que van a formar el dispositivo, y el tipo de dato de cada campo.

Debido a la ausencia de un modelo semántico, aunque scn permita definir tantos campos como quiera el usuario, es recomendable que solo se definan dos campos, el campo id, un campo del tipo str, el cual será obligatorio para cada tipo de dispositivo, ya que será usado para identificar unívocamente un servicio, y el campo status, el cual representará el estado primario de un dispositivo y será del tipo de datos que mejor se ajuste al dispositivo que representa. La creación de un tipo de dispositivo que no posea el campo id no está permitida.

1https://bitbucket.org/arco group/prj.symbiot/src/master/

103 Teniendo en cuenta lo anteriormente explicado, veamos algún ejemplo que ayude a com- prender la creación de tipos. Un dispositivo simple que puede estar desplegado en el en- torno podría ser por ejemplo un switch. Para poder realizar automatizaciones sobre cualquier switch, en primer lugar habría que definir un tipo de dispositivo Switch que permitiese crear instancias de él. Dado que un switch se puede encontrar encendido o apagado, la información del estado de un switch se puede relacionar con una variable booleana. Habiendo analizado la información de un switch, podemos concluir en que el tipo Switch estará formado por los campos id del tipo str y status del tipo bool, creando el nuevo tipo a partir de Template con la línea Switch=Template(id=str, status=bool). Para definir cualquier tipo distinto se seguiría el mismo proceso que el realizado para el switch, deduciendo que tipos de datos manejan y asignando este tipo al campo status. Recalcar de nuevo que el uso del campo status como campo primario para la definición de tipos es únicamente una solución propuesta a falta de un modelo semántico de datos, además de ser únicamente una recomendación, a la hora de usar Automaker, el usuario puede denominar tantos campos campos como quiera, siempre y cuando el campo id se encuentra entre ellos.

A partir de los tipos de dispositivos, scn posee el mecanismo para crear instancias. Para crear una instancia de un dispositivo, el único dato impresncindible que debe ser indicado es el identificador. En el caso de ejemplo del switch, se podría crear una instancia con el id «sw-01» con la línea sw1=Switch(id="sw-01"). El lenguaje scn no permite instancias dispo- sitivos con campos no existentes para sus tipos o con el tipo de datos erróneo, además, es recomendable que a la hora de instanciar un dispositivo, únicamente se le de valor al campo id, para asegurar un correcto funcionamiento de las automatizaciones escritas. El id debe identificar a un dispositivo desplegado en el mundo real.

D.3 Definición de una regla

Una regla de scn está formada por dos componentes, las condiciones y las acciones. Para poder representar las condiciones y acciones del lenguaje, toda instancia de un dispositivo posee dos métodos, when y set:

when: Permite definir una condición para el objeto que lo invoca. Por parámetros se le debe pasar el valor que deben tener los campos del objeto para que se cumpla la con- dición. Por ejemplo, si quisiésemos definir una condición para el switch anteriormente definido cuando este se encienda, la sintaxis correspondiente sería sw1.when(status=True). Notar que, como status es el campo que representa si el switch está encendido o apa- gado, es el campo que el usuario debe modificar y consultar para controla el switch.

set: Permite definir una acción para modificar el estado del dispositivo que invoca este método. Este método modificará los campos del dispositivo que le sean pasado como parámetros. Por ejemplo la sintaxis para apagar el switch anteriormente definido sería

104 sw1.set(status=False).

Dentro de las condiciones hay que distinguir un elemento muy importante, un Evento, el cual representa un cambio en un instante determinado del tiempo, que producirá que se ejecute la regla. Un evento es un elemento imprescindible para una regla, no se pueda crear ninguna regla en el lenguaje scn que no posea un evento. Además de ser un elemento impres- cindible, este es único, esto significa que en una regla solo puede existir un único evento.

Sintácticamente, un evento se modela con la función Event() que puede recibir como parámetro o una condición o simplemente la instancia de un dispositivo. Si recibe como parámetro una condición, cuando el dispositivo correspondiente cumpla con la condición la regla será ejecutada, si en cambio recibe una instancia de un dispositivo, cualquier cambio en el estado de este dispositivo disparará la regla. Vamos a ver dos ejemplos para clarificar la explicación de esta sección. Para ambos ejem- plos se va a suponer que se poseen dos instancias de la clase Switch, sw1 y sw2.

En el primer ejemplo se pretende construir una automatización, en la que sw2 se encienda únicamente cuando sw1 se apague. La sintaxis correspondiente a esta automatización sería la presente en el Listado D.1. Observar como antes de escribir la automatización, el primer paso es instanciar los dispositivos que van a representar elementos del mundo real en el programa.

1 sw1 = Switch(id=’sw1’) 2 sw2 = Switch(id=’sw2’)

4 Rule( 5 Event(sw1.when(status=False)) 6 )( 7 sw2.set(status=True) 8 )

Listado D.1: Automatización para los switches sw1 y sw2

El segundo ejemplo va a ser un ejemplo similar, pero en este caso queremos que sw2 se encienda siempre que cambie el estado de sw1, sin importar si sw1 está encendido o apagado. Para implementar este escenario se tienen dos opciones, presentes en los Listados D.2y D.3. Las dos opciones son prácticamente iguales, salvo que la segunda ofrece una sintaxis más explícita, pero ambas pueden ser usadas indistintamente.

D.4 Condiciones con umbrales Hasta el momento, se ha explicado como es posible realizar automatizaciones que conten- ga como condición únicamente literales. Cuando se manejan dispositivos que manejan datos

105 1 sw1 = Switch(id=’sw1’) 2 sw2 = Switch(id=’sw2’)

4 Rule( 5 Event(sw1) 6 )( 7 sw2.set(status=True) 8 )

Listado D.2: Encender sw2 cuando cambie el estado de sw1

1 sw1 = Switch(id=’sw1’) 2 sw2 = Switch(id=’sw2’)

4 Rule( 5 Event(sw1.any()) 6 )( 7 sw2.set(status=True) 8 )

Listado D.3: Automatización con sintaxis explícita en sw1

en formato numérico (como por ejemplo un sensor de temperatura), definir condiciones con literales puede producir ciertas limitaciones. Para ello, el lenguaje scn permite la creación de condiciones con umbrales.

Los umbrales en scn son representados mediante cadenas de texto del formato «operador- valor», siendo el operador los símbolos < y >, y el valor un valor numérico. Por ejemplo, la cadena de texto para definir un umbral que se cumple cuando un valor numérico sea mayor que 30 sería «> 30».

A continuación vamos a ver el ejemplo de una regla con umbrales. En primer lugar se deberían definir dos tipos de dispositivos a partir de Template, que manejen datos numéricos. Para esta automatización se va a hacer uso de un sensor de temperatura y un termostato, por lo que se necesitan dos tipos distintos. Para representar el sensor de temperatura se creará el tipo Thermometer y para el termostato el tipo Thermostat, ambos con un campo status que debe ser del tipo int. Para realizar por ejemplo una automatización que produzca que la temperatura de consigna del termostato (representado por status) cambie a 25o cuando la temperatura del entorno sea inferior a 15o, la automatización sería la correspondiente al listado D.4.

D.5 Utilización del estado de los dispositivos

El lenguaje scn permite modificar el valor de los dispositivos en función del estados de otros, permitiendo simplificar la escritura de las reglas, e incluso asignar valores que no se conocen en el momento de compilación.

106 1 Thermostat = Template(’Thermostat’, id=str, status=int) 2 Thermometer = Template(’Thermometer’, id=str, status=int) 3 temp1 = Thermometer(id=’temp1’) 4 th1 = Thermostat(id=’th1’)

6 Rule( 7 Event(temp1.when(status="<15")) 8 )( 9 th1.set(status=25) 10 )

Listado D.4: Automatización con variables

Un ejemplo podría ser la necesidad de vincular dos switches, de modo que ambos posean el mismo estado siempre, produciendo que cuando el primero se encienda o se apague, el segundo actúe en consecuencia. Con los conocimientos que se tienen hasta el momento del lenguaje scn, esta comportamiento conllevaría al menos dos automatizaciones.

Supongamos que los dos switches son los ya mencionados sw1 y sw2, esta automatización sería tan simple como la presente en el Listado D.5. Como se puede observar scn permi- te asignar directamente a la variable status de sw2 el valor de sw1.status, facilitando la vinculación del estado entre distintos dispositivos, y permitiendo modificar el estado de un dispositivo en función de otro del entorno.

2 Rule( 3 Event(sw1.when(status=True)) 4 )( 5 sw2.set(status=sw1.status), 6 )

Listado D.5: Automatización haciendo uso del estados de los dispositivos

D.6 Uso de Delays Es posible que en el momento de escribir una automatización, un usuario quiera que exista una diferencia temporal entre la aplicación de dos acciones, por ejemplo que la segunda acción ocurra diez segundos a continuación de la primera. Esta funcionalidad está soportada por scn gracias al uso de Delays.

Un Delay en scn es una función que recibe el número de segundos que deben pasar hasta ejecutar la siguiente acción. Por ejemplo, imaginemos que tenemos de nuevo los switches sw1 y sw2, y queremos que cuando se encienda sw1, sw2 se encienda y a los cinco segundo se apague. Esto es posible gracias al uso de Delay, y la automatización sería la correspondiente al Listado D.6.

107 1 sw1 = Switch(id=’sw1’) 2 sw2 = Switch(id=’sw2’)

4 Rule( 5 Event(sw1.when(status=True)) 6 )( 7 sw2.set(status=True), 8 Delay(5), 9 sw2.set(status=False) 10 )

Listado D.6: Automatización con Delay

D.7 Compilación de un archivo fuente

El compilador necesario para la ejecución de los archivos scn se encuentra en el repo- sitorio https://bitbucket.org/arco group/prj.symbiot/, en la carpeta automaker, con nom- bre scn.py. Para poder compilar un archivo satisfactoriamente, dado que Automaker es un

sistema distribuido, es necesario un archivo de configuración de ICE que indique direc- ción y puerto del registry, por lo que como se puede deducir, también se necesita un re- gistry de IceGrid. También es necesario un entorno con dispositivos y una serie de ser- vicios como la factoría y el wirer, todo ello gestionado por IceGrid. En el repositorio https://bitbucket.org/arco group/tfg.jesus.fernandez/, en el directorio src/scenaries se dispone de algunos escenarios listo para ejecutar programas scn. El archivo de configuración de Ice debe ser similar al presenta en el Listado D.7, donde se representa el archivo locator.config.

1 Ice.Default.Locator=IceGrid/Locator -t:tcp -h 127.0.0.1 -p 4061

Listado D.7: Archivo locator.config

Si se poseen los elementos necesarios, la compilación y ejecución de un programa scn de- nominado example.scn sería tan simple como ejecutar la línea presenta en el Listado D.8.

$ ./scn.py example.scn --Ice.Config=locator.config

Listado D.8: Ejecución de un archivo denominado examples.scn

108 Anexo E Listados de código

1 class Rule: 2 def __init__(self, *conditions): 3 self.conditions = self.check_conditions(conditions) 4 self.actions = []

6 def check_conditions(self, conditions): 7 forc in conditions: 8 if not isinstance(c, Statement): 9 raise InvalidCondition(c)

11 return list(conditions)

13 def __call__(self, *actions): 14 self.actions = self.check_actions(actions) 15 return self

17 def check_actions(self, actions): 18 fora in actions: 19 if not isinstance(a, Action): 20 raise InvalidAction

22 return list(actions)

Listado E.1: Código fuente de la clase Rule

1 module IceCloud {

3 dictionary Parameters; 4 exception CreationError { string reason; };

6 interface ServerFactory { 7 Object* make(string node, string serverTemplate, Parameters params) 8 throws CreationError; 9 }; 10 };

Listado E.2: Interfaz de la Factoría

109 1 module SmartStuff {

3 enum WireExceptionReason { 4 NotObervableProducer, 5 InvalidProducerAddress, 6 InvalidConsumerAddress, 7 };

9 exception WireException { 10 WireExceptionReason reason; 11 };

13 interface Wirer { 14 void addObserver(string producer, string consumer) throws WireException; 15 void removeObserver(string producer, string consumer); 16 void clearObservers(string producer); 17 }; 18 };

Listado E.3: Interfaz del Wirer

1 def run(self): 2 exec(self.provision_file.read(), dict(provide = self.provide)) 3 def provide(self, template, name, when, then, sources, sinks): 4 node = self.ic.getProperties().getProperty(’node’) 5 operator = str(self.factory.make( 6 node, template, {’name’: name,’when’: when,’then’: then})) 7 for item in sources: 8 item_string_proxy = self.identity_to_proxy(item) 9 self.wiring.addObserver(item_string_proxy, operator) 10 for item in sinks: 11 item_string_proxy = self.identity_to_proxy(item) 12 self.wiring.addObserver(operator, item_string_proxy)

14 def identity_to_proxy(self, identity): 15 return self.ic.getProperties().getProperty(identity)

Listado E.4: Ejecución del provisionamiento

110 1 module PropertyService {

3 enum ExceptionReason { 4 InvalidPropertyName, 5 PropertyNotFound, 6 UnsupportedProperty, 7 FixedProperty, 8 ReadOnlyProperty, 9 TypeError, 10 };

12 exception PropertyException { 13 ExceptionReason reason; 14 };

16 dictionary ReasonDict;

18 exception MultipleException { 19 ReasonDict exceptions; 20 };

22 interface PropertyServer { 23 string get(string path) throws PropertyException; 24 void set(string path, string value) throws PropertyException;

26 void remove(string path) throws PropertyException; 27 string keys(string path) throws PropertyException; 28 string values(string path) throws PropertyException; 29 int len(string path) throws PropertyException; 30 void clear() throws PropertyException; 31 }; 32 };

Listado E.5: Interfaz Ice del servidor de propiedades

1 module Automaker{

3 struct Copy { 4 string deviceId; 5 string field; 6 };

8 sequence ConditionPredicate; 9 sequence ConditionList; 10 dictionary ConditionDict;

12 interface Operator { 13 void setEvent(string when); 14 void setAction(string then); 15 void setActionWithVar(Copy var); 16 void setDelay(int delay); 17 void setConditions(ConditionDict conditions); 18 void commit(); 19 }; 20 };

Listado E.6: Ultima versión de Automaker.ice

111

Anexo F GNU Free Documentation License

Version 1.3, 3 November 2008

Copyright c 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.

Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

0. PREAMBLE

The purpose of this License is to make a manual, textbook, or other functional and useful document “free” in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.

This License is a kind of “copyleft”, which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.

We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.

1. APPLICABILITY AND DEFINITIONS

This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The “Document”, below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as “you”. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.

A “Modified Version” of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.

A “Secondary Section” is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document’s overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.

The “Invariant Sections” are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.

The “Cover Texts” are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.

113 A “Transparent” copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not “Transparent” is called “Opaque”.

Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modifi- cation. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.

The “Title Page” means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, “Title Page” means the text near the most prominent appearance of the work’s title, preceding the beginning of the body of the text.

The “publisher” means any person or entity that distributes copies of the Document to the public.

A section “Entitled XYZ” means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as “Acknow- ledgements”, “Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” of such a section when you modify the Document means that it remains a section “Entitled XYZ” according to this definition.

The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.

2. VERBATIM COPYING

You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.

You may also lend copies, under the same conditions stated above, and you may publicly display copies.

3. COPYING IN QUANTITY

If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document’s license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.

If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.

If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.

It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.

114 4. MODIFICATIONS

You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:

A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.

B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.

C. State on the Title page the name of the publisher of the Modified Version, as the publisher.

D. Preserve all the copyright notices of the Document.

E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.

F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.

G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document’s license notice.

H. Include an unaltered copy of this License.

I. Preserve the section Entitled “History”, Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled “History” in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.

J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the “History” section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.

K. For any section Entitled “Acknowledgements” or “Dedications”, Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.

L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.

M. Delete any section Entitled “Endorsements”. Such a section may not be included in the Modified Version.

N. Do not retitle any existing section to be Entitled “Endorsements” or to conflict in title with any Invariant Section.

O. Preserve any Warranty Disclaimers.

If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version’s license notice. These titles must be distinct from any other section titles.

You may add a section Entitled “Endorsements”, provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.

You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.

The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS

You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.

115 The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.

In the combination, you must combine any sections Entitled “History” in the various original documents, forming one section Entitled “History”; likewise combine any sections Entitled “Acknowledgements”, and any sections Entitled “Dedications”. You must delete all sections Entitled “Endorsements”.

5. COLLECTIONS OF DOCUMENTS

You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.

You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.

6. AGGREGATION WITH INDEPENDENT WORKS

A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an “aggregate” if the copyright resulting from the compilation is not used to limit the legal rights of the compilation’s users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.

If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document’s Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.

7. TRANSLATION

Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.

If a section in the Document is Entitled “Acknowledgements”, “Dedications”, or “History”, the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.

8. TERMINATION

You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.

However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.

Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.

Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.

116 9. FUTURE REVISIONS OF THIS LICENSE

The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.

Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License “or any later version” applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy’s public statement of acceptance of a version permanently authorizes you to choose that version for the Document.

10. RELICENSING

“Massive Multiauthor Collaboration Site” (or “MMC Site”) means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A “Massive Multiauthor Collaboration” (or “MMC”) contained in the site means any set of copyrightable works thus published on the MMC site.

“CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not- for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.

“Incorporate” means to publish or republish a Document, in whole or in part, as part of another Document.

An MMC is “eligible for relicensing” if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.

The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before

August 1, 2009, provided the MMC is eligible for relicensing.

117

Referencias

[ALSU08] Alfred V. Aho, Monica S. Lam, Ravi Sethi, y Jeffrey D. Ullman. Compiladores. Principios, técnicas y herramientas. Pearson, Educación, 2008.

[ASOT+18] Robert A. Sowah, Abdul Ofoli, Michael Tetteh, Richard A. Opoku, y Step- hen Armoo. Demand Side Management of Smart Homes Using OpenHAB Framework for Interoperability of Devices. 2018 IEEE 7th International Con- ference on Adaptive Science Technology (ICAST), páginas 1–8, 08 2018. url: https://ieeexplore.ieee.org/document/8506917.

[Ass] Home Assistant. Home Assistant: Cookbook. Último acceso 04-07-2019. url: https://www.home-assistant.io/cookbook/.

[Bur18] Brendadn Burns. Designing Distributed Systems: Patterns and Paradigms for Scalable, Reliable Services. O’Reilly, 2018.

[CDKB12] G. Coulouris, J. Dollimore, T. Kindberg, y G. Blair. Distributed Systems Con- cepts and Design. Addison-Wesley, 2012.

[ESP] ESPHome. ESPHome: Cookbook. Último acceso 08-07-2019. url: https:// esphome.io/cookbook/index.html.

[Fer06] David Vallejo Fernández. Documentación de ZeroC ICE. Universidad de Castilla-La Mancha, 2006.

[Gia07] J. C. Giarratano. CLIPS User’s Guide. Quicksilver Beta, 2007.

[GR04] J. C. Giarratano y Riley. Expert Systems: Principles and Programming. Course Technology, 2004.

[Jon13] B. K. Jones. Python Cookbook. O’Reilly Media, 2013.

[Jur10] C. Blé Jurado. Diseño Ágil con TDD. iExpertos, 2010.

[KBR+18] J. Kim, F. Bauman, P. Raftery, E. Atens, H. Zhang, G. Fierro, y D. Culler. Oc- cupant comfort and behavior: High-resolution data from a 6-month field study

119 of personal comfort systems with 37 real office workers. Building and Envi- ronment, 2018. url: https://doi.org/10.1016/J.BUILDENV.2018.11.012.

[Kha05] R. S. Khandpur. Printed Circuit Boards: Design, Fabrication and Assembly. McGraw-Hill Electronic Engineering, 2005.

[KSB18] J. Kim, S. Schiavon, y G. Brager. Personal comfort models – A new paradigm in thermal comfort for occupant-centric environmental control. Building and Environment, 132:114–124, 2018. url: https://doi.org/10.1016/J.BUILDENV. 2018.01.023.

[Lin] Robert W. B. Linn. Domoticz Home Automation Workbook. Último acceso 19-07-2019. url: https://github.com/rwbl/domoticz-homeautomation-workbook/ blob/master/domoticz-homeautomation-workbook.pdf.

[LWB+18] M. Luo, Z. Wang, G. Brager, B. Cao, y Y. Zhu. Indoor climate experience, migration, and thermal comfort expectation in buildings. Building and Envi- ronment, 141:262–272, 2018. url: https://doi.org/10.1016/J.BUILDENV.2018. 05.047.

[McC96] Steve McConnell. Rapid Development. Microsoft Press, 1996.

[MPA18] D. Marikyan, S. Papagiannidis, y E. Alamanos. A systematic review of the smart home literature: A user perspective. Technological Forecasting and So- cial Change, 2018. url: https://doi.org/10.1016/J.TECHFORE.2018.08.015.

[Smi91] M. F. Smith. Software prototyping: adoption, practice, and management. McGraw-Hill software engineering series, 1991. url: https://books.google.es/ books?id=s79QAAAAMAAJ.

[SR16] M. Schluse y J. Rossmann. From simulation to experimentable digital twins: Simulation-based development and operation of complex technical systems. ISSE 2016 - 2016 International Symposium on Systems Engineering - Procee- dings Papers, 2016. url: https://doi.org/10.1109/SysEng.2016.7753162.

[Ste15] Rod Stephens. Beginning Software Engineering. Wrox, 2015.

[SVA+18] M. J. Santofimia, D. Villa, O. Aceña, X. del Toro, C. Trapero, F. J. Villanueva, y J. C. López. Enabling smart behavior through automatic service composition for Internet of Things–based Smart Homes. International Journal of Distribu- ted Sensor Networks, 2018. url: https://doi.org/10.1177/1550147718794616.

[SVV+16] M. J. Santofimia, D. Villa, F. J. Villanueva, S. Escolar, y J. C. Lopez. A semantic middleware architecture for supporting real smartness. IECON 2016 - 42nd

120 Annual Conference of the IEEE Industrial Electronics Society, páginas 6925– 6930, 2016.

[VA+17] D. Villa, , O. Aceña, , F. J. Villanueva, M. J. Santofimia, X. del Toro, y J. C. López. IDM: An Inter-Domain Messaging Protocol fot IoT. Industrial Elec- tronics Society, IECON 2017-43rd Annual Conference of the IEEE, 2017. url: https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=8217467.

[VFA16] D. Villa, F.Moya, y O. Aceña. Computación Distribuida con ZeroC Ice. Uni- versidad de Castilla-La Mancha, 2016.

121

Este documento fue editado y tipografiado con LATEX empleando la clase esi-tfg (versión 0.20181017) que se puede encontrar en: https://bitbucket.org/esi atc/esi-tfg

[respeta esta atribución al autor]

123