scieee AI-readable full text Open interactive document viewer

Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía

Pozo Prior, José Antonio

Abstract

Los invernaderos actuales buscan un equilibrio entre productividad y eficiencia energética. Para lograrlo, este proyecto utiliza el Internet de las Cosas (IoT), un concepto que permite conectar objetos cotidianos a Internet para monitorizarlos y controlarlos de forma remota, para optimizar ese balance mediante una aplicación Android desarrollada para controlar distintos elementos (como sistemas de riego y sensores) y consultar en tiempo real los precios horarios de la electricidad. Esta información permite automatizar decisiones como, por ejemplo, activar equipos en horas de menor coste. Entre las tecnologías usadas en el proyecto destacan OpenHAB, núcleo para la integración de dispositivos IoT y Fiware Orion responsable del intercambio de mensajes entre los elementos del sistema mediante suscripciones que permiten que cuando se actualicen los valores de un elemento los componentes del sistema reciban esta nueva información. Por último, cabe destacar que se ha usado una placa ESP32 programada mediante el IDE de Arduino para la gestión de los distintos elementos del invernadero

Full text

Equation Chapter 1 Section 1 Trabajo Fin de Grado en Ingeniería de las Tecnologías de Telecomunicación Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía Autor: José Antonio Pozo Prior Tutor: María Teresa Ariza Gómez Dpto. de Ingeniería Telemática Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2025 iii Trabajo Fin de Grado en Ingeniería de las Tecnologías de Telecomunicación Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía Autor: José Antonio Pozo Prior Tutor: María Teresa Ariza Gómez Profesor titular Dpto. de Ingeniería Telemática Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2025 v Trabajo Fin de Grado: Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía Autor: José Antonio Pozo Prior Tutor: María Teresa Ariza Gómez El tribunal nombrado para juzgar el Proyecto arriba indicado, compuesto por los siguientes miembros: Presidente: Vocales: Secretario: Acuerdan otorgarle la calificación de: Sevilla, 2025 El Secretario del Tribunal vii A mi familia A mis maestros ix Agradecimientos En primer lugar, me gustaría agradecer a mis padres y a mi hermana por todo el apoyo que he recibido de su parte durante mi carrera universitaria, que tanto en los buenos como en los malos momentos me han escuchado y dado su consejo. También me gustaría agradecer a mi tutora del proyecto, María Teresa, por la ayuda prestada y por la cercanía que me ha demostrado a lo largo de su desarrollo. Por último, deseo recordar a todos los miembros de mi familia que nos han dejado y agradecerles por los momentos que he vivido junto a ellos. José Antonio Pozo Prior Sevilla, 2025 5.1.4 Consultar registros de los sensores 51 5.1.5 Consultar registro del motor 52 5.1.6 Consultar perfil 53 5.1.7 Establecer limites 54 5.1.8 Consultar precio de la luz 55 5.1.9 Consultar pronóstico del tiempo 56 5.1.10 Controlar actuadores 57 5.1.11 Ficheros de configuración 58 5.2 Aplicación Openhab 58 5.3 Resumen 62 6 Conclusiones y líneas futuras 63 Anexo A: Instalación de Fiware Orion usando Docker 64 Anexo B: Configuración del ESP32 66 Anexo C: Configuración de la base de datos 69 Anexo D: Construcción del sistema 72 Referencias 75 xvii ÍNDICE DE TABLAS Tabla 2-1. Características del Lenovo Legion 5 Pro 7 Tabla 2-2. Características del ESP32 8 Tabla 2-3. Características del módulo DTH11 10 Tabla 2-4. Características del módulo MH del sensor de luz 10 Tabla 2-5. Características del módulo de la humedad del suelo 11 Tabla 2-6. Características del módulo de nivel de agua 12 Tabla 2-7. Características del módulo del relé 12 Tabla 2-8. Características del motor de agua 13 Tabla 4-1. Peticiones respondidas por EstadoMotorController 40 Tabla 4-2. Peticiones respondidas por LimitesController 40 Tabla 4-3. Peticiones respondidas por LecturasSensoresController 41 Tabla 4-4. Peticiones respondidas por UsuariosController 41 Tabla 5-1. Ítems de los sensores 59 Tabla 5-2. Ítems de los límites 59 Tabla 5-3. Ítems de los actuadores 60 ÍNDICE DE FIGURAS Figura 1-1. Esquema de la arquitectura del Sistema 3 Figura 2-1. Lenovo Legion Pro 5 8 Figura 2-2. Placa ESP32 8 Figura 2-3. Punto de Acceso Numcom 9 Figura 2-4. Redmi Note 13 9 Figura 2-5. Placa Protoboard 9 Figura 2-6. Módulo DTH11 10 Figura 2-7. Módulo MH del sensor de luz 11 Figura 2-8. Módulo de la humedad del suelo 11 Figura 2-9. Módulo de nivel de agua 12 Figura 2-10. Módulo del relé 12 Figura 2-11. Porta pilas 4xAA 13 Figura 2-12. Pilas AA 13 Figura 2-13. Motor de agua 13 Figura 2-14. Resistencias, leds y cables 14 Figura 2-15. Multímetro 14 Figura 2-16. Soldador Eléctrico 14 Figura 2-17. OpenHAB 15 Figura 2-18. Fiware Orion 15 Figura 2-19. MongoDB 15 Figura 2-20. Docker 16 Figura 2-21. Máquina Virtual y Ubuntu 16 Figura 2-22. Spring 16 Figura 2-23. Android Studio 17 Figura 2-24. PostgreSQL 17 Figura 2-25. Arduino 17 Figura 2-26. Windows 11 Pro 17 Figura 2-27. C++ 18 Figura 2-28. JSON 18 Figura 2-29. REST 18 Figura 2-30. SQL 19 Figura 2-31. HTTP 19 Figura 2-32. Java 19 Figura 3-1. Pines ESP32 22 xix Figura 3-2. Configuración del Wifi 22 Figura 3-3. Enviar los datos de los sensores 23 Figura 3-4. Función para obtener los límites 25 Figura 3-5. Función de notificación del estado del aire acondicionado 26 Figura 3-6. Bloque de depuración 27 Figura 3-7. Entidades Fiware 29 Figura 3-8. Atributo de una entidad Fiware 29 Figura 3-9. Ejemplo de suscripción Fiware 30 Figura 4-1.Clase tipo modelo (EstadoMotor) 35 Figura 4-2. Clase tipo repositorio (EventosMotorRepository) 37 Figura 4-3. Clases de interfaz e implementacion (EstadoMotorService y EstadoMotorServiceImpl) 39 Figura 4-4. Documentación de Swagger 42 Figura 4-5. Tabla usuarios 43 Figura 4-6. Tabla limites 44 Figura 4-7. Tabla limites_horas_riego 44 Figura 4-8. Tabla lecturas_sensores 44 Figura 4-9. Tabla estado_motor 45 Figura 4-10. Tabla eventos_motor 45 Figura 4-11. Diagrama ER 45 Figura 5-1. Diagrama de casos de uso 47 Figura 5-2. Inicio de sesión 48 Figura 5-3. Barra de aplicación 49 Figura 5-4. Registro 50 Figura 5-5. Consultar valores actuales 51 Figura 5-6. Consultar registro de los sensores 52 Figura 5-7. Consultar registro del motor 53 Figura 5-8. Consultar perfil 54 Figura 5-9. Consultar límites 55 Figura 5-10. Consultar precio de la luz 56 Figura 5-11. Consultar pronóstico del tiempo 57 Figura 5-12. Controlar actuadores 58 Figura 5-13. Librerías del fichero build.gradle 58 Figura 5-14. Ítems de OpenHAB 61 Figura 5-15. Reglas de OpenHAB 62 Figura 0-1. Descargar Docker 64 Figura 0-2. Contenedor apagado 65 Figura 0-3. Contenedor encendido 65 Figura 0-1. Descarga de la versión de Arduino 66 Figura 0-2. Configuración de la Url de Arduino 66 Figura 0-3. Gestor de placas 67 Figura 0-4. Montaje del sistema 67 Figura 0-5. Esquema del sistema 68 Figura 0-1. Nuevo proyecto Android Studio. 72 Figura 0-2. Inicio del Servidor Rest 73 Figura 0-3. Instalar OpenHAB desde la página oficial 73 Figura 0-4 Iniciar OpenHab 74 xxi Notación AgIoT Agricultural Internet of Things OpenHAB Open Home Automation Bus JSON JavaScript Object Notation IoT Internet of Things SQL Structured Query Languaje REST Representational State Transfer BBDD Base de Datos PC Personal computer USB Universal Serial Bus UART Universal Asynchronous Receiver/Transmitter POJO Plain Old Java Objects JPA Java Persistence API API Application Programming Interfaces FK Foreing Key JDBC Java Database Connectivity UTF-8 8-bit Unicode Transformation Format UTC Coordinated Universal Time DAL Data Access Layer REE Red Eléctrica Española xxiii 1 1 INTRODUCCIÓN 1.1 Motivación Cuando mencionamos Internet de las Cosas (IoT) nos estamos refiriendo a una red de elementos físicos que están integrados con sensores, software y conectividad de red, de forma que pueden recopilar y compartir datos [1]. Los elementos pueden ir desde bombillas a robots lo que permite una gran diversidad de casos para los que se puede usar el IoT [2]. Esta diversidad ha provocado que el IoT se divida en distintas ramas, en las que destacan: • IoT Industrial (IIoT): Aplicado a maquinaria y procesos automatizados. • IoT de Consumo: Aplicado en la domótica y dispositivos inteligentes para el hogar. • IoT en Agricultura (AgIoT): Enfocado en monitoreo ambiental, riego inteligente y gestión automatizada de cultivos. Una rama muy importante que para 2026, se espera que el mercado global de IoT agrícola supere los $ 18.1 mil millones [3] Este proyecto se centra en el AgIoT, específicamente en la automatización de invernaderos enfocado en el ahorro energético, donde sensores y actuadores trabajan en conjunto para mantener las condiciones óptimas de crecimiento sin intervención humana constante y reducir el consumo de energía el máximo posible. Además, para mejorar el beneficio de las empresas dedicadas a la agricultura este proyecto también permite obtener el precio de la energía de manera sencilla para que se pueda decidir cuándo entrarán en uso los actuadores. 1.2 Objetivos Generales Este trabajo tiene como objetivos: - Analizar el funcionamiento de OpenHAB. - Usar el context broker Fiware Orion para conectar las tecnologías usadas en el proyecto. - Mostrar el clima actual. - Mostrar el precio de la luz actual. - Instalar sensores y actuadores con Arduino y comunicar al broker Fiware. - Crear un servidor REST. - Crear un cliente móvil. - Conectar la base de datos con el servidor REST. Antes de ser un dragón, hay que sufrir como una hormiga. - Proverbio chino- Recursos utilizados 8 Figura 2-1. Lenovo Legion Pro 5 2.1.2 Placa ESP32 Es la placa que maneja los sensores y actuadores, además, es compatible con Arduino IDE. Algunas de sus características técnicas son: Categoría Detalles Microcontrolador Xtensa® dual-core 32-bit LX6 (240 MHz) Memoria Flash 4 MB RAM 512 KB Conectividad Wi-Fi 802.11 b/g/n (2.4 GHz) + Bluetooth 4.2 (BLE y Classic) Interfaces I/O 34 GPIO (12 bits ADC, 2 DAC, UART, SPI, I2C, PWM, etc.) Protocolos Compatibles MQTT, HTTP, TCP/IP, LoRa (con módulos externos) Consumo Modo sleep: ~5 µA / Activo: ~160 mA (Wi-Fi/BT en uso) Tensión de Alimentación 3.3V (rango recomendado: 2.2V - 3.6V) Rango de Temperatura -40°C a +125°C (industrial) Dimensiones 25 mm x 18 mm (ESP32-WROOM-32) Cable de Alimentación Tipo C Tabla 2-2. Características del ESP32 Figura 2-2. Placa ESP32 9 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía 2.1.3 Punto de Acceso WIFI Punto de acceso WIFI que permite el establecimiento de la red local y de esta forma una comunicación entre los elementos software del proyecto. Específicamente ha sido el rúter nucom wireless 300mbps Figura 2-3. Punto de Acceso Numcom 2.1.4 Teléfono Móvil Es el dispositivo Android usado para la ejecución de la aplicación Android que permite al usuario la gestión y el control del invernadero. En este caso se ha usado el dispositivo simulado de Android Studio Pixel 4 XL API 35 y un dispositivo físico Android: Redmi Note 13. Figura 2-4. Redmi Note 13 2.1.5 Placa Protoboard La placa protoboard (o placa de pruebas) es un dispositivo en electrónica que permite montar y probar circuitos temporales sin necesidad de soldar. Está compuesta por una matriz de orificios interconectados eléctricamente mediante columnas, buses y filas, facilitando el rápido montaje de componentes como resistencias, leds y cables. En este proyecto se ha usado para unir los elementos del hardware con el ESP32. Figura 2-5. Placa Protoboard Recursos utilizados 10 2.1.6 Módulo DTH11 Contine el sensor DTH11 que permite medir la humedad ambiental y temperatura con una precisión básica (±2°C y ±5% HR). Utiliza un protocolo de comunicación serial de un solo cable y es ideal para proyectos IoT y domóticos donde no se requiera alta exactitud. Parámetro Especificación Rango de Temperatura 0°C a 50°C (±2°C) Rango de Humedad 20% a 80% HR (±5%) Alimentación 3V a 5.5V DC Salida Señal digital Uso típico Invernaderos, estaciones meteorológicas, domótica Tabla 2-3. Características del módulo DTH11 Figura 2-6. Módulo DTH11 2.1.7 Módulo MH del sensor de luz Contiene un fotorresistor LDR (Light Dependent Resistor) que mide la intensidad lumínica ambiental. Su resistencia varía inversamente con la luz: disminuye en ambientes brillantes y aumenta en la oscuridad. Se usa comúnmente en sistemas automáticos por su bajo costo y fácil integración con microcontroladores. Parámetro Especificación Rango de detección 0 a 100,000 lux Voltaje operativo 3.3V a 5V DC Salida Analógica (ADC) o digital Respuesta espectral ~550 nm (Similar al ojo humano) Aplicaciones Control de luces, alarmas, agricultura Tabla 2-4. Características del módulo MH del sensor de luz 11 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía Figura 2-7. Módulo MH del sensor de luz 2.1.8 Módulo de la humedad del suelo (HW-80 + HW-103) Está formado por el sensor HW-80 que mide la humedad del suelo mediante dos electrodos que detectan cambios en la conductividad eléctrica según el agua presente. Además, del convertidor HW-103 que transforma esta señal analógica en un valor digital (0-1023 ADC) para su lectura en los microcontroladores. Parámetro Especificación Voltaje operativo 3.3V - 5V DC Salida Analógica (HW-80) / Digital (HW-103, ADC) Rango de detección 0% (seco) - 100% (húmedo) Corrosión Electrodos no protegidos (vida útil limitada) Aplicaciones Riego automático, invernaderos, jardinería Tabla 2-5. Características del módulo de la humedad del suelo Figura 2-8. Módulo de la humedad del suelo Recursos utilizados 12 2.1.9 Módulo de nivel del agua Está formado por un sensor de nivel de agua resistivo que detecta la presencia y el nivel del agua mediante unos electrodos expuestos, que miden los cambios en la conductividad del medio. Al entrar en contacto con el agua, se cierra el circuito entre los electrodos y se genera una señal analógica que proporciona el nivel. Como tiene los electrodos expuestos es muy susceptible a la corrosión. Parámetro Especificación Voltaje operativo 3.3V - 5V DC Salida Señal analógica (0-1023 en ADC de Arduino) Detección Por contacto directo (electrodos sumergidos) Material Electrodos metálicos sin protección (cobre/acero) Aplicaciones Tanques, sistemas de riego, alarmas de inundación Tabla 2-6. Características del módulo de nivel de agua Figura 2-9. Módulo de nivel de agua 2.1.10 Módulo del relé Es un interruptor electromecánico controlado por señales de bajo voltaje. Activa o desactiva circuitos mediante un electroimán que mueve un contacto interno. Parámetro Especificación Voltaje de control 3.3V - 5V DC Carga máxima 10A 250V AC / 10A 30V DC Aplicaciones Domótica, control de motores, sistemas IoT Tabla 2-7. Características del módulo del relé Figura 2-10. Módulo del relé 13 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía 2.1.11 Porta pilas 4xAA Porta pilas para 4 pilas AA que proporcionará el voltaje para el funcionamiento del motor de agua. Figura 2-11. Porta pilas 4xAA 2.1.12 Pilas Son la fuente de alimentación del motor de agua. Figura 2-12. Pilas AA 2.1.13 Motor de agua Es el encargado de suministrar el agua a las plantas del invernadero. El motor usado en este proyecto bombea agua a un flujo de 25 ml por segundo. Parámetro Especificación Voltaje DC3-5 V Corriente 100-200 mA Elevación 0,3-0,8 m Flujo 1,2-1,6 l/min Aplicaciones Riego automático, fuentes decorativas Tabla 2-8. Características del motor de agua Figura 2-13. Motor de agua Recursos utilizados 14 2.1.14 Leds, cables y resistencias Los leds son componentes que se iluminan cuando pasa corriente eléctrica en polaridad directa, es decir, desde el ánodo a + al cátodo a -. Los cables conectan los leds a la fuente de alimentación, transmitiendo la corriente necesaria. Para evitar daños, se usan resistencias en serie con el led, con un valor calculado según la ley de Ohm, en este proyecto son de 220Ω pues la fuente ESP32 da 3,7V de alimentación. Se han usado 3 tipos de cables para la realización de este proyecto, cables macho-hembra, cables machomacho y cables hembra-hembra, que han permitido alargar las distancias entre los elementos. Figura 2-14. Resistencias, leds y cables 2.1.15 Multímetro Es un instrumento portátil que mide magnitudes eléctricas activas, como la tensión (V) y la corriente (A), y pasivas, como la resistencia (Ω). Funciona mediante puntas de prueba que se conectan al circuito. Figura 2-15. Multímetro 2.1.16 Soldador Eléctrico Es una herramienta que genera calor en su punta (entre 200°C y 450°C) al pasar corriente a través de una resistencia interna, fundiendo el estaño para unir componentes electrónicos. El calor se controla mediante una ruleta que indica la temperatura que va a alcanzar. Figura 2-16. Soldador Eléctrico 15 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía 2.2 Recursos Software Se entiende como recursos software a los programas o componentes listos para usar que han facilitado el desarrollo, la gestión y la ejecución del proyecto. 2.2.1 OpenHAB OpenHAB permite integrar los elementos IoT, los sensores, los actuadores y los límites establecidos por el usuario en una interfaz unificada. Además, permite personalizar reglas para la gestión de los elementos y es compatible múltiples protocolos. Figura 2-17. OpenHAB 2.2.2 Fiware Orion Context Broker Es el agente que sirve de intermediario entre los elementos del sistema y que mediante notificaciones y suscripciones notifica siempre los últimos valores de las entidades al resto de componentes mediante mensajes JSON. Figura 2-18. Fiware Orion 2.2.3 MongoDB Es la base de datos que permite la persistencia de las últimas entidades que Fiware ha recibido y las mantiene para que cuando se reinicie el sistema Fiware mantenga las últimas entidades. Esto permite que el resto de los elementos puedan obtener de Fiware las últimas versiones de las entidades. Figura 2-19. MongoDB Recursos utilizados 16 2.2.4 Docker Ha servido para alojar a Fiware Orion junto a MongoDB mediante un contenedor de software que tiene los dos programas. Para ver su instalación diríjase al Anexo A: Instalación de Fiware Orion usando Docker. Un contenedor es una unidad estándar de software que empaqueta el código y todas sus dependencias para que la aplicación se ejecute de forma rápida y fiable de un entorno informático a otro [4]. Figura 2-20. Docker 2.2.5 Máquina Virtual/Linux Se ha usado la máquina virtual VMware con el OS Ubuntu para ejecutar sobre Linux el servidor de Spring y la base de datos SQL, esto permite el funcionamiento de gran parte del proyecto. Figura 2-21. Máquina Virtual y Ubuntu 2.2.6 Spring Es un framework Java para el desarrollo de aplicaciones, es de código Abierto y se ha usado para la creación del servidor REST. Figura 2-22. Spring 17 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía 2.2.7 Android Studio Es el entorno de desarrollo oficial para aplicaciones Android y es el que se ha usado para la creación de la app de control del invernadero Figura 2-23. Android Studio 2.2.8 PostgreSQL Es una base de datos SQL que permite consultas complejas y es compatible con JSON por eso se ha usado para almacenar los valores que nos interesan de las entidades que monitorizamos. Figura 2-24. PostgreSQL 2.2.9 Arduino Es un IDE basado en C++ y se usa para la programación de microcontroladores. Concretamente, en este proyecto se ha usado el microcontrolador ESP32 y nos ha permitido programar las funciones que realizará el ESP32. Figura 2-25. Arduino 2.2.10 Windows 11 Pro Es el sistema operativo base donde se ha desarrollado el proyecto, pues en él se han instalado Docker, OpenHAB, Android Studio... Figura 2-26. Windows 11 Pro Dispositivo y Context Broker 24 3. A continuación, se comprueba si está activa la bandera de control manual. Si está activa, el proceso termina aquí; de lo contrario, se pasa al último paso. 4. Por último, se determina el estado que debería tener el motor (encendido si la humedad es menor que el mínimo configurado, o apagado en caso contrario) y se compara con el estado actual. Si no coinciden, se cambia el estado y se notifica al context broker. En segundo lugar, tenemos las comprobaciones para determinar el estado del aire acondicionado. 1. Primero, el código verifica si el control manual del aire está desactivado. 2. Si se cumple esta condición, se evalúan las condiciones ambientales: el aire se encenderá si la humedad está fuera de los límites configurados (por debajo del mínimo o por encima del máximo) o si la temperatura supera los umbrales establecidos. Si el estado actual del pin del aire no coincide con el requerido, se actualiza el pin, se notifica al context broker y se registra el cambio en los logs. 3. Si el control manual supera el tiempo permitido, se desactiva automáticamente y se registra un log de que ha expirado. Por último, tenemos las comprobaciones para determinar el estado de las luces. 1. Primero se verifica si el control manual de las luces está desactivado. 2. Si es así, se determina si las luces deben encenderse comparando los valores del sensor de luminosidad con los límites configurados. Si el estado actual del pin es distinto del requerido, se actualiza el pin, se notifica al context broker y se registra el evento en los logs. 3. Si el control manual excede el tiempo máximo permitido, se desactiva y se registra un log indicando que ha expirado. 3.1.3.4 Bloque para obtener del context broker Este bloque está formado por las 4 funciones que obtienen los datos del context broker, es decir, obtener: los límites, y el estado del motor, las luces y el aire acondicionado. Las 3 últimas funciones son iguales, excepto el endpoint al que hacen la solicitud y el pin en el que guardan los datos. Por otro lado, la función de los límites, aunque muy parecida tiene diferencias más significativas, así que voy a explicar la función para obtener los límites y el motor en detalle. La función para obtener el estado del motor consulta el estado actual del motor en el context broker para sincronizar el dispositivo físico con el estado registrado en el servidor. 1. Primero se verifica la conexión Wi-Fi, si no se cumple, se detiene. Si hay conexión, se realiza una petición HTTP GET al endpoint configurado. 2. Si la respuesta es exitosa, procesa el payload del JSON recibido: se extrae el valor del atributo estado y, si difiere del estado actual del motor, actualiza el pin físico, se activa el indicador de control manual, se registra el tiempo de inicio y se guarda el nuevo estado. Todo esto se registra en los logs. 3. Si hay errores, se notifica en los logs. 4. Finalmente, cierra la conexión HTTP. La función para obtener los límites se encarga de obtener y actualizar los límites de configuración del invernadero desde FIWARE Orion. 1. Primero verifica la conexión Wi-Fi y, si está activa, realiza una petición HTTP GET al endpoint. 2. Si la respuesta es exitosa, procesa el payload JSON recibido: a. Se limpian los arrays que almacenan las horas y minutos de riego. 25 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía b. Se extrae y se asignan los valores de los límites desde el JSON a la estructura “limites”, incluyendo: i. Consumo máximo de agua. ii. Horas programadas de riego, almacenando horas y minutos en arrays separados. iii. Rangos de humedad ambiental. iv. Rangos de humedad del suelo. v. Rangos de los niveles de luz. vi. Rango de temperaturas. vii. Volumen mínimo de agua. 3. Si la operación es exitosa, se registra un log de confirmación; y en caso de error, se registra un log con el error específico. Finalmente, cierra la conexión HTTP. Figura 3-4. Función para obtener los límites Dispositivo y Context Broker 26 3.1.3.5 Bloque de notificación al context broker Este bloque está compuesto por 3 funciones análogas: la función para notificar el estado del motor, la función para notificar el estado de las luces y la función para notificar el estado del aire acondicionado. La única diferencia entre las funciones es el endpoint al que se envía, así que se va a explicar la función para notificar el estado del aire acondicionado, ya que el funcionamiento es el mismo para el resto de las funciones que conforman este bloque. La función para notificar el estado del aire acondicionado se encarga de actualizar el estado del aire acondicionado en el context broker. 1. Primero, se verifica si hay conexión Wi-Fi; si no hay conexión, la función termina. 2. Si hay conexión, se inicia una petición HTTP al endpoint predefinido y se configura el encabezado para enviar los datos en formato JSON. 3. Luego, se construye un payload con el estado del aire (true o false) y un metadato que indica el origen del dato ("Arduino"). Se usa el método HTTP PATCH para enviar esta información al servidor FIWARE. 4. Si la respuesta es exitosa, se registra un mensaje de confirmación en los logs; en caso de error, se registra el problema con los detalles específicos. Finalmente, cierra la conexión HTTP para liberar recursos. Figura 3-5. Función de notificación del estado del aire acondicionado 3.1.3.6 Bloque de manejo de las suscripciones Este bloque está compuesto por la función que maneja las notificaciones que le llegan al servidor web configurado. Esta función procesa las notificaciones POST entrantes que provienen del context broker para actualizar el estado de los dispositivos o de los límites del invernadero. Siguiendo estos pasos: 1. Como primer paso, se realiza la recepción y validación de los datos mediante los siguientes subpasos: a. Se comprueba que sea el método HTTP POST. b. Se procesa el cuerpo de la petición, para ello: i. Se lee el cuerpo en formato JSON (server.arg("plain")). ii. Se valida que el JSON esté bien formado (usa StaticJsonDocument<1024>). iii. Se rechazan peticiones malformadas con código 400 Bad Request. 2. Una vez se ha comprobado que el mensaje es correcto, se filtran las notificaciones propias mediante una función que detecta y descarta actualizaciones que el propio Arduino envió al context broker. Esto se consigue comparando el campo de metadatos que contiene el origen de la notificación. 27 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía 3. Después de descartar las notificaciones propias, se procesan el resto de las notificaciones: a. Si la notificación contiene el atributo “estado”, actualiza el pin GPIO correspondiente, activa el control manual del dispositivo y registra el tiempo de inicio. b. Si la notificación es de tipo "Limites", actualiza todos los parámetros recibidos, limpiando y rellenando los arreglos de horas y minutos de riego. 4. Por último, envía una respuesta HTTP, al elemento que hizo la petición: a. Envía 200 OK si todo se procesó correctamente. b. Envía 405 Method Not Allowed si no es una petición POST. 3.1.3.7 Bloque de depuración En este bloque se explica cómo se ha logrado crear los elementos de depuración del código, es decir, cómo se ha conseguido crear tres niveles de registros y cómo lograr que aparezcan por el monitor serial. Para implementar un sistema de registros flexible con tres niveles de prioridad (ERROR, INFO, DEBUG), se ha creado un enum LogLevel donde cada nivel incluye a los anteriores (DEBUG muestra todo, ERROR solo lo crítico). Las macros LOG_ERROR, LOG_INFO y LOG_DEBUG imprimen mensajes en el monitor serial únicamente si están habilitadas y si el nivel actual es igual o superior al del mensaje. Además, la función que recibe los mensajes de la salida serial permite controlar el sistema en tiempo real: posibilita activar/desactivar registros y cambiar el nivel de detalle mediante comandos por el monitor serial, lo que facilita la depuración sin necesidad de modificar el código. Figura 3-6. Bloque de depuración 3.2 Context Broker Como ya se ha explicado anterior anteriormente, el context broker de este proyecto es Fiware Orion. Los datos que recibe FIWARE deben estar en formato JSON y se distinguen por entidades que tienen cada una su propia URL. Para la realización del proyecto se han usado las dos funciones principales de FIWARE: las entidades en el endpoint /v2/entities/ (más la entidad específica) y las notificaciones en el endpoint /v2/subscription. Ambos endpoint complementan a la URL base donde está Fiware que en este proyecto ha sido http://192.168.1.113:1026/ en el OS Windows. Para los elementos que se ejecutan en Windows (como OpenHAB), se puede sustituir la IP por localhost. Para persistir el último valor de las entidades, se enlaza Fiware con MongoDB, que es una BBDD que está en el mismo contenedor DOCKER. Dispositivo y Context Broker 28 3.2.1 Entidades Los datos recopilados por los sensores del invernadero se envían al Orion Context Broker de Fiware, donde se almacenan y organizan en entidades que representan cada componente del sistema. Cada entidad se identifica unívocamente por su id y type, y contiene atributos con los valores medidos o configurados, junto con metadatos que describen su origen. Para este proyecto, las entidades clave son: • La entidad del sensor, que contiene los valores de los sensores y está compuesta por: o Id SensorData1 y Type Sensor: o Atributos: humedad_ambiental, humedad_suelo, luz, nivel, temperatura_C, temperatura_F. ▪ Cada atributo tiene un campo de metadatos vacío. • La entidad del motor, que contiene el estado del motor y está compuesta por: o Id MotorData1 y Type Motor: o Atributo: estado, una variable de tipo boolean que indica el estado del motor. ▪ El atributo tiene un campo de metadatos que es una variable de tipo texto con un valor que indica el origen. • La entidad de los límites, que contiene los valores de los límites y está compuesta por: o Id Limites:1 y Type Limites: o Atributos: temp_min, temp_max, humedad_amb_min, humedad_amb_max, luz_max, luz_min, horas_riego, humedad_suelo_max, volumen_agua_min y consumo_agua_max. Todos estos atributos son de tipo Number, excepto horas_riego que es una StructruredValue. ▪ Cada atributo tiene un campo de metadatos que es una variable de tipo texto con un valor que indica el origen. • La entidad del aire acondicionado, que contiene el estado del aire acondicionado y está compuesta por: o Id AireAcondicionado y Type AireAcondicionado: o Atributo: estado, una variable de tipo boolean que indica el estado del aire acondicionado. ▪ El atributo tiene un campo de metadatos que es una variable de tipo texto con un valor que indica el origen. • La entidad de las luces, que contiene el estado de las luces y está compuesta por: o Id Luces y Type Luces: o Atributo: estado, una variable de tipo boolean que indica el estado de las luces. ▪ El atributo tiene un campo de metadatos que es una variable de tipo texto con un valor que indica el origen. Como se puede observar en la figura 3-7 aparte del id y el type, los atributos tienen su propia estructura compuesta por: • El campo type que indica el tipo de dato (Number, Boolean, StructuredValue). • El campo value que indica el valor actual. • El campo metadata que indica información adicional, en este caso el origen de los datos. El campo metadata a su vez, está compuesto por un campo type y un campo value. 29 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía Figura 3-7. Entidades Fiware De otra forma, si queremos consultar solo una entidad solo tenemos que hacer una petición GET añadiendo su id al final del endpoint, por ejemplo, /v2/entities/Limites:1 para consultar los límites donde Limites:1 es el id de la entidad. Además, se pueden obtener solo los atributos de la entidad, siguiendo con el ejemplo anterior quedaría /v2/entities/Limites:1/attrs/consumo_agua_max, y si añadimos value solo devolverá el valor del atributo. Figura 3-8. Atributo de una entidad Fiware Para eliminar una entidad se debe hacer una petición DELETE especificando el id de la entidad que queremos eliminar. Ahora se muestra un ejemplo usando el comando curl de Linux: curl -X DELETE \ 'http://192.168.1.113:1026/v2/entities/Limites:1/attrs/consumo_agua_ma x' 3.2.2 Suscripciones Las suscripciones son un mecanismo mediante el cual Fiware notifica a los dispositivos suscritos a una entidad cada vez que la entidad sea actualizada. En la notificación que envía Fiware se encuentra todo el JSON de la entidad actualizada, es decir, sería lo mismo que el resultado que devuelve Fiware cuando hacemos GET a esa entidad. Cada suscripción se almacena en una lista que se puede observar en el endpoint /v2/subscription, de forma que si se envía una petición GET a la URL devuelve todas las suscripciones. Dispositivo y Context Broker 30 Cada suscripción consta de una serie de campos, que voy a resumir (si se quiere más información visitar [5]): 1. id: Es el identificador generado automáticamente para la suscripción. 2. description: Texto creado por el usuario que indica el propósito de la suscripción (ej: notificar cambios al arduino). 3. expires: Es la fecha de caducidad de la suscripción (en formato ISO 8601). 4. status: Es el estado actual de la suscripción (active, expired, paused). 5. entities: Define qué entidades deben ser monitoreadas: a. idPattern: es el patrón regex para filtrar por ID (ej: "Limites:.*" cubre todos los IDs que empiezan con "Limites:"). b. type: es el tipo de entidad a suscribir (ej: "Limites"). c. condition: son condiciones adicionales: i. attrs: Son los atributos específicos a observar (si está vacío, se monitorizan todos). ii. notifyOnMetadataChange: Si este campo es true, se notifican cambios tanto en valores como en metadatos. 6. timesSent: Es el número total de notificaciones enviadas. 7. lastNotification: Es la fecha de la última notificación exitosa. 8. attrs: Son los atributos específicos a incluir en la notificación (vacío = todos). 9. onlyChangedAttrs: Si este campo es false, se envía el estado completo de la entidad; si es true, solo los atributos modificados. 10. attrsFormat: Es el formato de los datos (normalized = estándar FIWARE, keyValues = simplificado). 11. http + url: Es el endpoint del servidor que recibirá las notificaciones. 12. lastFailure + lastFailureReason: Es la Fecha y el motivo del último fallo. 13. lastSuccess + lastSuccessCode: Es la Fecha y el código HTTP de la última notificación exitosa. 14. covered: Si este campo es true, indica que la suscripción está siendo procesada por un servidor federado. 15. throttling: Es el tiempo mínimo (en segundos) entre notificaciones consecutivas. Ejemplo: 5 = no envía más de una notificación cada 5 segundos, incluso si hay múltiples cambios. Figura 3-9. Ejemplo de suscripción Fiware 31 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía Para generar una suscripción se debe mandar una petición POST a la URL de Fiware junto al endpoint que se ha nombrado al inicio de este subapartado y se siguen las recomendaciones de la guía de Fiware Orion [6]. Aquí se muestra un ejemplo de cómo hacer una suscripción mediante el comando curl: curl -iX POST http://192.168.1.113:1026/v2/subscriptions \ -H "Content-Type: application/json" \ -d '{ "description": "Notificación al backend cuando cambia el estado del motor", "subject": { "entities": [ { "id": "MotorData1", "type": "Motor" } ], "condition": { "attrs": ["estado"] } }, "notification": { "http": { "url": "http://192.168.1.152:9000/invernadero/motor/estado/cambiar", "qs": "motivo=fiware" }, "attrs": ["estado"], "attrsFormat": "keyValues" }, "throttling": 1 }' Para eliminar una suscripción se debe hacer un DELETE a la URL donde se hizo el POST más el id de la suscripción que queremos eliminar. Las notificaciones se envían como mensajes POST a la URL que se haya definido en el campo “url” de la suscripción. Dispositivo y Context Broker 32 33 4 SERVIDOR WEB Y BASE DE DATOS La mejor manera de predecir el futuro es inventarlo. - Alan Kayn este capítulo se va a explicar el funcionamiento del servidor web, ubicado en la máquina virtual con dirección IP 192.168.1.155 y en el puerto 9000; y el esquema de la base de datos que se usa en este proyecto. Para ello se detallarán los métodos más importantes y las clases que se han implementado. 4.1 Clases En esta sección se detallan las clases Java creadas para el servidor web, ubicadas en la denominada ruta principal (\invernadero\src\main\java\com\greenhouse). Las clases están divididas en las siguientes partes: 4.1.1 Principal Es la clase RegistroInvernaderoApplication, que contiene el método main del programa. Este es el primer método que se llama al ejecutar el programa. Anotada con @SpringBootApplication, combina tres configuraciones clave [7]: • @EnableAutoConfiguration: Configura automáticamente beans y dependencias. • @ComponentScan: Escanea componentes (controladores, servicios, repositorios) en el paquete com.greenhouse y subpaquetes. • @Configuration: Permite definir beans adicionales. Además, @EnableScheduling habilita la ejecución periódica de tareas [8]. El método main() inicia la aplicación usando SpringApplication.run(), levantando el servidor embebido (Tomcat) y cargando toda la configuración. 4.1.2 Configuración En el subdirectorio config de la ruta principal se encuentran las clases que configuran servicios. En este proyecto solo se encuentra la clase SwaggerConfig, que configura Swagger, un servicio para generar la documentación. En el fichero se han configurado el título, la versión que aparece en la interfaz de Swagger. 4.1.3 Modelos En el subdirectorio model de la ruta principal se encuentran las clases que representan la estructura de datos del proyecto, es decir, son clases POJO. Estas clases definen: • Las entidades que modelan elementos reales (ej: Motor, Sensor, Limites). • Las relaciones con la base de datos mediante anotaciones (@Entity, @Table, @Column) para mapear tablas en PostgreSQL. • Los atributos y las validaciones mediante anotaciones como @NotNull, @Size, o formatos específicos (@DateTimeFormat). E Servidor Web y Base de Datos 40 40 4.1.6 Controladores En el subdirectorio controller de la ruta principal se encuentran las clases que definen el comportamiento del servidor cuando se recibe una petición en la URL que definen. Su propósito principal es recibir peticiones HTTP, delega la lógica a los servicios y devuelven las respuestas estructuradas en el formato que se necesite, en este caso JSON. Cada clase de modelado tiene su propia clase java que sirve de controlador. 4.1.6.1 Controlador del Motor Está compuesto por los controladores de los eventos y del estado del motor. Estas clases son: • EventosMotorController que tiene como ruta base /invernadero/motor/eventos y gestiona los eventos de operación del motor. Solo tiene el método de respuesta a un GET a este endpoint / y obtiene todos los eventos del motor ordenados cronológicamente. • EstadoMotorController que tiene como ruta base invernadero/motor/estado y controla el estado actual del motor. Tiene configurado las respuestas a los siguientes métodos: Método HTTP Endpoint Descripción GET / Consulta el último estado registrado del motor. POST /cambiar Cambia el estado del motor mediante un JSON y registra el motivo, por defecto, “fiware”. Tabla 4-1. Peticiones respondidas por EstadoMotorController 4.1.6.2 Controlador de los límites Está compuesto por el controlador que corresponde a su clase modelo. Esta clase es LimitesController que tiene como ruta base /invernadero/limites y que gestiona la configuración de límites ambientales y de riego para el invernadero. Método HTTP Endpoint Descripción GET / Obtiene los límites actuales configurados en el sistema, mediante findCurrentLimits del servicio. GET /usuario/{usuarioId} Obtiene los límites específicos de un usuario por su ID, mediante el findCurrentLimitsByUsuarioId del servicio. POST /usuario/{usuarioId} Crea nuevos límites para un usuario, mediante el save del servicio. PUT /usuario/{usuarioId} Actualiza límites existentes de un usuario, mediante el updateLimits del servicio. POST /fiware-callback Recibe notificaciones de FIWARE para actualizar límites. POST /actualizar-horas-riego/{usuarioId} Actualiza horas de riego permitidas para un usuario, mediante el actualizarHorasRiego del servicio. Tabla 4-2. Peticiones respondidas por LimitesController 41 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía 4.1.6.3 Controlador de los sensores Está compuesto por la clase LecturasSensoresController que tiene como ruta base /invernadero/sensores y que gestiona las lecturas de sensores del invernadero. Método HTTP Endpoint Descripción POST /fiware-callback Recibe datos de sensores desde FIWARE y los almacena en la base de datos, mediante el método guardarDesdeNotificacion(payload) del servicio. GET /ultima Obtiene la última lectura registrada de los sensores, mediante el método obtenerUltimaLectura() del servicio. GET /historial Recupera el historial completo de lecturas de sensores, mediante el método obtenerHistorial() del servicio. GET /resumen-hoy Devuelve 12 lecturas del día actual mediante el método obtenerResumenHoy() del servicio. GET /resumenultimos-dias Obtiene promedios diarios del número de días con datos que se indica en el periodo, mediante el método obtenerResumenUltimosDias( String periodo) del servicio. Tabla 4-3. Peticiones respondidas por LecturasSensoresController 4.1.6.4 Controlador usuarios Está compuesto por la clase UsuariosController que tiene como ruta base /invernadero/usuarios y que gestiona el registro, la autenticación y la gestión de usuarios del sistema. Método HTTP Endpoint Descripción GET / Obtiene todos los usuarios registrados en el sistema, mediante el método findAll() del servicio. GET /{id} Obtiene un usuario específico por su ID (excluye datos sensibles como contraseña), mediante el método findById(id) del servicio. GET /login Autentica un usuario mediante nombre de usuario y contraseña, mediante el método login(nombreUsuario, contraseña) del servicio. POST /registro Registra un nuevo usuario (valida duplicados de nombre/email), mediante los métodos existeNombreUsuario(), existeEmail(), registrarUsuario(usuario) del servicio. GET /{nombreUsuario} /existe Verifica si un nombre de usuario ya está en uso, mediante el método existeNombreUsuario(nombreUsuario) del servicio. GET /email/{email}/exi ste Verifica si un email ya está registrado, mediante el método existeEmail(email) del servicio. PATCH /{id}/contrasena Actualiza la contraseña de un usuario existente, mediante el método actualizarContrasena(id, nuevaContrasena) del servicio. Tabla 4-4. Peticiones respondidas por UsuariosController Servidor Web y Base de Datos 42 42 Figura 4-4. Documentación de Swagger 43 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía 4.2 Ficheros de configuración En este apartado se detallan los ficheros de configuración del servidor web. Hay dos tipos de ficheros de configuración los que configuran las dependencias del proyecto (.xml) y los que configuran las propiedades de algunos elementos (.properties). Los ficheros de origen properties se encuentran dentro del subdirectorio resources que está en la ruta invernadero\src\main\resources. En este proyecto solo se ha usado un fichero de este tipo llamado application y contiene: • La configuración de la BBDD detallando el tipo de BBDD que en este caso es PostgreSQL, la URL para la conexión (jdbc:postgresql://localhost:5432/registro_invernadero), las credenciales y el controlador que se usa. • Las propiedades de Hibernate (JPA) que se configuran. Se activa el mostrar consultas SQL para mostrar las consultas en el servidor y formatoSQL para mejorar legibilidad. Se define la estrategia de actualización de la BBDD y el dialecto que se usa para hablar con la misma. • El puerto de la aplicación en este caso el 9000. • La configuración de la URL donde se va a ejecutar el swagger (http://localhost:9000/swagger-ui.html) Por otro lado, el fichero de las dependencias se encuentra al inicio de la ruta en el subdirectorio invernadero y se llama POM. Este fichero contiene las tecnologías usadas y las dependencias necesarias para el correcto funcionamiento del proyecto. 4.3 BBDD En este apartado se va a explicar la estructura de la BBDD, es decir, el nombre de esta, las tablas que contiene y la relación entre ellas. Se ha configurado una base de datos PostgreSQL que es un sistema de bases de datos relacional de código abierto. El nombre de la BBDD es registro_invernadero. Para ver cómo se ha configurado la BBDD consulte el Anexo C: Configuración de la base de datos. La BBDD está compuesta por las siguientes tablas: 4.3.1 Tabla usuarios Es la tabla que almacena la información de los usuarios del sistema. Además, tiene una relación 1:N con límites. Sus elementos son: Figura 4-5. Tabla usuarios 4.3.2 Tabla limites Es la tabla que contiene la configuración de los parámetros ambientales y de riego del invernadero. Tiene una relación 1:N con limites_horas_riego. Sus elementos son: Servidor Web y Base de Datos 44 44 Figura 4-6. Tabla limites 4.3.3 Tabla limites_horas_riego Es la tabla que contiene las horas permitidas para el riego automático y tiene una FK a limites. Sus elementos son: Figura 4-7. Tabla limites_horas_riego 4.3.4 Tabla lecturas_sensores Es la tabla que contiene los registros de los datos leídos por los sensores. Sus elementos son: Figura 4-8. Tabla lecturas_sensores 4.3.5 Tabla estado_motor Es la tabla que contiene el estado actual del motor y el consumo de agua. Sus elementos son: 45 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía Figura 4-9. Tabla estado_motor 4.3.6 Tabla eventos_motor Es la tabla que mantiene el registro de los cambios de estado del motor. Figura 4-10. Tabla eventos_motor A continuación, se muestra el diagrama ER de la base de datos: Figura 4-11. Diagrama ER Servidor Web y Base de Datos 46 46 47 5 INTERFAZ DE USUARIO Y FUNCIONALIDAD ¿Qué somos las personas sino máquinas muy evolucionadas? - Marvin Minsky - n este capítulo se va a explicar el funcionamiento de las dos interfaces de usuario diseñadas en este proyecto. Por un lado, tenemos la aplicación Android y por otro lado tenemos la aplicación OpenHAB, ambas permiten gestionar el invernadero, pero cada una tiene ventajas e inconvenientes. 5.1 Aplicación Android Gracias a la aplicación Android llamada ETSINatura, el usuario final podrá ver el estado actual del invernadero y controlar el motor de riego. Además, se podrá configurar los límites por los que se rigen las operaciones de control automático incluyendo la elección de las horas de riego según se haya creído conveniente después de ver el precio y el pronóstico del tiempo mediante las funcionalidades que se ofrecen. Por último, el usuario podrá obtener los registros del invernadero para analizar la evolución del mismo. Para comunicarse con el servicio REST, se usan los endpoints definidos en el punto 4. A continuación, se muestran los casos de uso que tiene la aplicación y una explicación de cómo funciona cada uno. Figura 5-1. Diagrama de casos de uso E Interfaz de usuario y funcionalidad 48 48 5.1.1 Inicio de sesión En este apartado se explica el funcionamiento y los elementos que conforman el caso de uso “Inicio de Sesion” de la aplicación Android. Este caso de uso consiste en una pantalla con dos campos a rellenar el usuario y la contraseña, además de dos botones “Acceder” y “Registrarse”. Para implementar esta función se han necesitado los siguientes ficheros: • MainActivity.java: Esta clase es la actividad principal de la aplicación y maneja el inicio de sesión de usuarios. Contiene los campos para ingresar usuario y contraseña, y realiza una petición HTTP GET a un servidor para validar las credenciales. Si el inicio de sesión es exitoso, muestra un texto Toast con “Inicio de sesión exitoso” y redirige a MainUsuarios enviando los datos del usuario. También incluye un botón para redirigir a la actividad de registro (RegistroActivity) y maneja errores de conexión con mensajes Toast. • activity_main.xml: Define la interfaz de usuario de la actividad principal, que incluye: o Campos de texto (EditText) para usuario y contraseña. o Botones para iniciar sesión (Acceder) y registrarse (Registrarse). o Un fondo personalizado (@drawable/fondo_inicio) y estilos para los elementos (texto en negrita, colores semitransparentes, etc.). Figura 5-2. Inicio de sesión Además de este caso de uso en este apartado también se va a incluir la explicación de los ficheros que permiten las actividades de los usuarios en el resto de los casos de uso que necesitan primero que se inicie sesión. • MainUsuarios.java: Esta clase representa la actividad principal del usuario después del inicio de sesión, implementando un menú de navegación lateral y una barra de herramientas. Gestiona la navegación entre diferentes fragmentos (inicio, perfil, precios de electricidad, límites, actuadores, gráficas y eventos del motor) utilizando el componente Navigation, estos fragmentos corresponden a un caso de uso cada uno. Recibe los datos del usuario en formato JSON desde la actividad de login y los pasa a los fragmentos correspondientes. También incluye un botón de cierre de sesión en el menú superior que redirige al usuario de vuelta a la pantalla de inicio de sesión. • activity_main_usuarios.xml: Define la estructura visual de la pantalla principal de la aplicación, utilizando un DrawerLayout como contenedor principal. Incluye: o Un CoordinatorLayout que contiene una AppBar con Toolbar personalizada y un contenedor de fragmentos que muestra el contenido dinámico según la navegación. 49 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía o Un NavigationView (menú lateral) que muestra las opciones de navegación definidas en el archivo de menú (@menu/menu_nav) y un encabezado personalizado (@layout/nav_header). o Configuración de navegación mediante el grafo definido en @navigation/usuario_navigation, permitiendo la transición fluida entre las diferentes secciones de la aplicación. • content_usuarios.xml: Este archivo actúa como contenedor secundario para los fragmentos dentro de la actividad principal. • app_bar_usuarios.xml: Define la estructura de la barra de aplicación y el contenedor principal para la navegación entre fragmentos en la actividad MainUsuarios. Figura 5-3. Barra de aplicación 5.1.2 Registro En este apartado se explica el funcionamiento y los elementos que conforman el caso de uso “Registro”. Este caso de uso muestra los campos a rellenar para registrar un usuario nuevo en la BBDD y dos botones: uno para cancelar el registro y otro para confirmarlo. Para su implementación se han necesitado los siguientes ficheros: • RegistroActivity.java: Esta clase gestiona el proceso de registro de nuevos usuarios en la aplicación. Contiene los campos a ingresar: nombre de usuario, contraseña y email. Se valida que todos estén completos antes de enviar una petición POST al servidor con los datos en formato JSON. Se muestra un diálogo de progreso durante la solicitud y maneja tanto la respuesta exitosa (mostrando un mensaje y cerrando la actividad) como los errores. También incluye un botón para cancelar el registro y volver a la pantalla anterior. • activity_registro.xml: Define la interfaz de usuario para el registro, manteniendo el diseño visual coherente con la pantalla de inicio de sesión (mismo fondo y estilo). Incluye: o Tres campos de texto (EditText) para usuario, contraseña (con enmascaramiento) y email, cada uno con su etiqueta (TextView) correspondiente. o Dos botones ("Confirmar Registro" y "Cancelar Registro") con estilos similares a los de inicio de sesión. o Diseño lineal vertical con márgenes y alineación centrada, optimizado para usabilidad en dispositivos móviles. Interfaz de usuario y funcionalidad 56 56 o textoHorasSeleccionadas: Lista las horas elegidas por el usuario. Figura 5-10. Consultar precio de la luz 5.1.9 Consultar pronóstico del tiempo En este apartado se explica el funcionamiento y los elementos que conforman el caso de uso “Consultar pronóstico del tiempo”. Este caso de uso muestra dos campos para rellenar con la ciudad y el país del que queremos el clima y un botón para enviar la petición. Para su implementación se han necesitado los siguientes ficheros: • OpenWeatherService.java: Interfaz Retrofit que define el endpoint ("data/2.5/forecast"), para obtener datos meteorológicos de OpenWeatherMap. Utiliza una petición GET con parámetros como ciudad, unidades (métricas), idioma (español) y la API key obtenida creando un usuario en OpenWeather. Retorna un JsonObject con la respuesta. • TiempoFragment.java: Fragmento que muestra previsiones meteorológicas de 3 días (hoy, mañana y pasado) como máximo usando la API de OpenWeatherMap. Permite buscar por ciudad/país, procesa la respuesta JSON para extraer temperatura, descripción e iconos del clima ( / / ), y organiza los datos por franjas horarias. Usa la URL ("https://api.openweathermap.org/") y el OpenWeatherService para hacer la petición a la OpenWeather. • WeatherResponse.java: Clase modelo que permite parsear la respuesta JSON de OpenWeatherMap. Contiene clases anidadas para mapear campos del JSON, esto facilita el acceso a datos como temperatura (temp), condición climática (main) y descripción (description). • fragment_tiempo.xml: Diseño del fragmento con ConstraintLayout y un LinearLayout vertical. Incluye: o Dos EditText para ciudad y país. o Un botón "Buscar clima" que activa la consulta. o Un TextView para mostrar resultados. 57 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía Figura 5-11. Consultar pronóstico del tiempo 5.1.10 Controlar actuadores En este apartado se explica el funcionamiento y los elementos que conforman el caso de uso “Controlar actuadores”. Este caso de uso muestra un texto que representa el estado del motor y un interruptor que permite cambiarlo. Para su implementación se han necesitado los siguientes ficheros: • ActuadoresService.java: Interfaz Retrofit que define los endpoints para interactuar con el sistema de actuadores del invernadero. Incluye dos métodos principales: o getEstadoMotor: Obtiene el estado actual del motor mediante una petición GET. o cambiarEstadoMotor: Envía un comando para modificar el estado del motor (encender/apagar) usando POST, aceptando un mapa de datos como payload y un parámetro de motivo. • ActuadoresFragment.java: Fragmento que controla el estado del motor del invernadero. Muestra el estado actual (Encendido/Apagado) en un TextView y permite modificarlo mediante un Switch. Utiliza Retrofit para comunicarse con el servicio REST, manejando las interacciones del usuario en la aplicación para evitar actualizaciones no deseadas, es decir, tener en cuenta cuando se inicia el interruptor para que no se cambie el estado al por defecto al iniciar el fragmento y se envíe al servicio REST. Además, incluye la lógica para sincronizar el estado del switch con el servidor y muestra notificaciones Toast para confirmar cambios. • EstadoMotorRequest.java: Clase modelo que representa una solicitud de cambio de estado del motor. Contiene dos campos: acción un booleano que indica si se debe encender (true) o apagar (false) el motor y motivo un String que describe la razón del cambio. • fragment_actuadores.xml: Diseño del fragmento, organizado en un LinearLayout vertical centrado. Contiene: o textoEstadoMotor: Muestra el estado actual del motor. o switch_motor: Interruptor para control manual del motor. Interfaz de usuario y funcionalidad 58 58 Figura 5-12. Controlar actuadores 5.1.11 Ficheros de configuración Para poder usar todos los elementos y que el proyecto funcione correctamente se deben configurar dos ficheros especiales, pues son los ficheros de configuración del proyecto: • AndroidManifest.xml: Archivo de configuración principal que define la estructura básica de la aplicación Android. Declara los permisos necesarios (INTERNET y ACCESS_NETWORK_STATE), las actividades principales (MainActivity como actividad de lanzamiento, MainUsuarios y RegistroActivity), y configura aspectos globales como el icono de la aplicación, tema y configuración de seguridad de red. También especifica que la aplicación es compatible con diseño RTL (Right-toLeft). • build.gradle: Archivo de configuración de Gradle que gestiona las dependencias y opciones de compilación del proyecto. Establece las versiones mínimas (24) y objetivo (35) del SDK, configura el entorno de Java (versión 11), y declara las dependencias clave como Volley para peticiones HTTP, Material Design Components, Navigation Components, Retrofit para APIs REST, y MPAndroidChart para gráficos. Incluye también dependencias para testing (JUnit y Espresso). Figura 5-13. Librerías del fichero build.gradle 5.2 Aplicación Openhab La aplicación OpenHAB es un software que mediante canales conecta los ítems definidos en él y mediante reglas definimos cómo se va a actuar cuando ocurra un evento. La función de esta aplicación es permitir que a futuro se puedan conectar dispositivos IOT, sin necesidad de modificar la aplicación Android, de manera rápida y sencilla agregándolos como un ítem extra. Lo primero que se ha definido ha sido el canal de donde va a escuchar los elementos que en este caso es la dirección y el puerto de FIWARE (http://localhost:1026/v2/entities/). Después de enlazar con FIWARE, se usa 59 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía este canal de enlace en las reglas que se han personalizado para los ítems del programa. Los ítems los podemos clasificar en 3 tipos, los valores de los sensores, los valores de los límites y los actuadores. • Sensores: son los ítems que representan a los sensores. Nombre Tipo Etiqueta Categoría OrionHumedadAmbiental Number Humedad Ambiente humidity OrionLuz Number Luz light OrionTemperaturaC Number Temperatura °C temperature OrionTemperaturaF Number Temperatura ºF temperature OrionHumedadSuelo Number Humedad Suelo humidity OrionNivel Number Nivel water Tabla 5-1. Ítems de los sensores • Límites: son los ítems que representan los límites todos son editables, excepto las horas de riego Nombre Tipo Detalles LimiteTempMin Number Límite de la temperatura mínima en ºC LimiteTempMax Number Límite de la temperatura máxima en ºC LimiteHumedadAmbMin Number Límite de la humedad ambiental mínima en % LimiteHumedadAmbMax Number Límite de la humedad ambiental máxima en % LimiteHumedadSueloMin Number Límite de la humedad del suelo mínima en % LimiteHumedadSueloMax Number Límite de la humedad del suelo máxima en % LimiteLuzMin Number Límite de la luz mínima en % LimiteLuzMax Number Límite de la luz máxima en % LimiteConsumoAguaMax Number Límite del consumo de agua por riego en litros LimiteVolumenAguaMin Number Volumen de agua mínimo necesario para poder encender el motor LimitesHorasRiego String Horas en las que se puede encender el motor (no editables). Tabla 5-2. Ítems de los límites Interfaz de usuario y funcionalidad 60 60 • Actuadores: son los ítems que representan un actuador Nombre Tipo Detalles MotorEstado Switch Es el actuador que controla el motor de riego LucesEstado Switch Es el actuador que controla la iluminación AireEstado Switch Es el actuador que controla la climatización Tabla 5-3. Ítems de los actuadores Para controlar el funcionamiento de estos ítems se han definido las siguientes reglas: • Lectura_Elementos es la regla que sirve para actualizar los estados cada 30 segundos consultando FIWARE (Motor, Sensores, Luces, Aire). o Detalle: Realiza peticiones HTTP GET al canal para obtener los datos de sensores (humedad, luz, temperatura, nivel), los estados de actuadores (ON/OFF) . • ActualizarLimites es la regla que se ejecuta al modificar cualquier límite (temp, humedad, luz, agua). Se hacen las siguientes comprobaciones: o Rangos coherentes (min < max), Valores porcentuales (0-100%) y Horas de riego no vacías. o Se ignoran actualizaciones con metadatos origen: "openhab". • AccionarLuces es la regla que controla las LucesEstado. o Acción: Envía estado (ON/OFF) a FIWARE via PUT al cambiar LucesEstado incluyendo los metadatos de origen para evitar bucles. o Endpoint: http://localhost:1026/v2/entities/Luces/attrs/estado. • AccionarAire es la regla que controla el AireEstado o Usa PUT para enviar el estado al canal + AireAcondicionado/attrs/estado. • Accionar Motor es la regla que controla MotorEstado. o Usa POST para enviar estado al canal + MotorData1/attrs. • Inicio es la regla que se encarga de cargar todos los datos al arrancar OpenHAB. o Consulta: Obtiene valores actuales de sensores y límites de FIWARE. Además de estas reglas tenemos un script de Python que cuando se recibe una notificación desde FIWARE cambia el formato al JSON que puede leer OpenHAB. Este fichero implementa un servidor Flask, en Docker, que actúa como intermediario para recibir notificaciones y actualizar ítems en OpenHAB. El servidor escucha en el puerto 5000 y define una ruta /notify que acepta solicitudes POST. Cuando recibe datos en formato JSON, extrae valores específicos (como límites de consumo de agua, humedad, temperatura, etc.) de un diccionario llamado MAPA_ITEMS, que mapea atributos recibidos a nombres de ítems en OpenHAB. Luego, envía estos valores a OpenHAB mediante solicitudes HTTP POST a su API REST. La dirección de OpenHAB está configurada para funcionar en un entorno Docker (host.docker.internal). 61 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía Figura 5-14. Ítems de OpenHAB Interfaz de usuario y funcionalidad 62 62 Figura 5-15. Reglas de OpenHAB 5.3 Resumen En este apartado se redacta un resumen y una comparación de las dos interfaces de usuario que tenemos. Por un lado, tenemos la aplicación móvil que permite el registro e inicio de sesión de los usuarios y permite observar los históricos de los elementos de la base de datos. Además, permite establecer las horas de riego permitidas y mirar el clima. Aunque solo permite controlar el motor. Por otro lado, tenemos la interfaz de OpenHAB que, aunque permite editar los límites del sistema, no permite modificar las horas de riego permitidas ni consultar los históricos. Sin embargo, ofrece ventajas frente a la aplicación móvil, como la capacidad de controlar dispositivos IoT reales (por ejemplo, luces y aire acondicionado). En este proyecto, estos elementos se simulan mediante LEDs, pero en un entorno real podrían gestionarse directamente a través de canales de OpenHAB, simplificando su configuración en comparación con una implementación personalizada en la aplicación móvil. 63 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía 6 CONCLUSIONES Y LÍNEAS FUTURAS El arte desafía a la tecnología y la tecnología inspira al arte. -John Lasseter – l desarrollo del proyecto aunque diverso, tiene varios aspectos que se pueden mejorar. En este apartado se sacarán las conclusiones y se nombrarán las futuras líneas de mejoras que se pueden implementar sobre el proyecto. El mundo actual está evolucionando a gran velocidad, y con ello las tecnologías y las formas en las que están presentes en nuestra vida. Cada vez los procesos son más automáticos y están controlados desde la distancia. Como se ha demostrado en este proyecto mediante la implementación de un sistema de riego y control de un invernadero, se puede controlar todo desde un móvil lo que permite una respuesta instantánea a los cambios. Este proyecto ha resultado ser de bajo coste pues solo ha necesitado de los sensores, los actuadores y la placa ESP32. Además, se ha demostrado que es posible conectar Fiware Orion Context Broker con OpenHAB, aunque OpenHAB no proporcione una integración nativa o directa. Esto se ha logrado mediante reglas, que permiten la automatización de los elementos del proyecto, y bindings configurados con las URLs de Fiware, que permiten obtener y actualizar los valores de los elementos. Por otro lado, la aplicación Android ha demostrado que podemos conectarnos a la REE, para obtener los precios de la electricidad a tiempo real, y con OpenWeather, que permite obtener el pronóstico del tiempo. Ambas conexiones junto con las condiciones ambientales del invernadero que nos ofrece la aplicación nos permiten decidir que límites queremos establecer para el invernadero. Por último, podemos obtener en forma de gráficas los registros temporales del invernadero para estudiar cómo mejorar la eficiencia de este. Como líneas de interés para futuras mejoras se encuentran los siguientes apartados: 1. Seguridad: a. Actualizar el paso de mensajes usando el protocolo HTTPS. b. Implementar mecanismos que garanticen la autentificación de los usuarios y el cifrado de las comunicaciones, para evitar que un usuario no autorizado pueda cambiar los datos de algún elemento. 2. Funcionalidad: a. Optimizar el uso de los metadatos en futuras versiones para evitar bucles de mensajes y mejorar la eficiencia de las entidades. b. Añadir en los elementos del sistema la opción de modificar la dirección del servidor de manera dinámica y añadir la opción para que el administrador pueda eliminar información de la base de datos desde la aplicación Android. E Anexo A: Instalación de Fiware Orion usando Docker 64 64 ANEXO A: INSTALACIÓN DE FIWARE ORION USANDO DOCKER En este anexo se explican los pasos a seguir para instalar y poner en funcionamiento Fiware Orion usando Docker y MongoDB como base de datos para Fiware. Para instalar Docker, se necesita: un procesador de 64 bit con SLAT, 4GB de RAM, tener activado la virtualización en la BIOS y Windows 11 64-bit: Home o Pro versión 22H2 o mayor [11]. Los pasos a seguir para instalar Docker son: 1. Nos dirigimos a la página principal de Docker (https://www.docker.com/) y elegimos el OS donde nos queremos instalar Docker. En este caso se ha elegido Windows-AMD64 Figura 0-1. Descargar Docker 2. El siguiente paso es ejecutar el fichero .exe que instalará Docker en esta ruta por defecto, C:\Program Files\Docker\Docker. A partir de este momento seguimos las instrucciones del instalador y de la guía de Docker [11]. Una vez que tenemos instalado Docker procedemos a desplegar el contenedor de Fiware, que contiene al Orion y a MongoDB. Para lograr esto, se necesita lo siguiente: 1. Creamos el fichero docker-compose.yaml que contiene los elementos de nuestro contenedor. A continuación, se muestra el fichero: version: "3.8" services: orion: image: fiware/orion hostname: orion container_name: fiware-orion depends_on: - mongo-db networks: - fiware-net expose: - "1026" ports: 65 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía - "1026:1026" command: -dbURI mongodb://mongo-db:27017/orion -logLevel DEBUG mongo-db: image: mongo:4.4 hostname: mongo-db container_name: db-mongo networks: - fiware-net expose: - "27017" ports: - "27017:27017" command: --nojournal volumes: - mongo-db:/data/db networks: fiware-net: driver: bridge volumes: mongo-db: driver: local 2. Una vez que tenemos el fichero, en la terminal de Docker ejecutamos el siguiente comando, indicando la ruta hasta el docker-compose: docker-compose up -d .\fiware\docker-compose.yaml 3. Una vez que tenemos el contenedor en la interfaz gráfica le damos al play para iniciar y a stop para detener Figura 0-2. Contenedor apagado Figura 0-3. Contenedor encendido Una vez que tenemos todo instalado y configurado si pulsamos en el nombre del elemento podremos observar los logs de este y ver lo que ocurre. Anexo D: Construcción del sistema 72 72 ANEXO D: CONSTRUCCIÓN DEL SISTEMA En este anexo se detallarán los pasos a seguir para conseguir la puesta en marcha del sistema. En primer lugar, debemos acceder a este repositorio GitHub https://github.com/jospozpri1/TFG y descargarnos las carpetas o los .zip como se prefiera, que contienen los códigos de los programas. Una vez tengamos los ficheros vamos a ir usándolos de uno en uno: • Docker contiene el fichero docker-compose y la carpeta fiware-openhab-bridge. Usando el Dockercompose y siguiendo los pasos del Anexo A se instalará en Docker el contenedor para el Context Broker. En la carpeta se encuentran los ficheros necesarios para el puente que conecta con OpenHab, para ello nos situamos en la carpeta y ejecutamos “docker build -t fiware-openhab-bridge”. • Codigo_TFG contiene el código necesario para el funcionamiento del esp32. Una vez que hemos seguido los pasos del Anexo B y tenemos configurado todos los elementos físicos, conectamos el esp32 y configuramos el id y la contraseña del wifi, así como la ip que se le asigna al esp32 de manera que concuerde con nuestra red wifi. Por último, configuramos la zona horaria en el código y lo cargamos a nuestro esp32. • Src es la carpeta que contiene todas las clases .java y los layouts necesarios para la ejecución de la aplicación Android. Para su uso, en Android Studio se crea un proyecto Empty Views Activity, con nombre Invernadero y quedando el package como com.dam.invernadero y se selecciona lenguaje JAVA y lenguaje de configuración Groovy DSL. A continuación, se muestra un ejemplo de creación de un proyecto: Figura 0-1. Nuevo proyecto Android Studio. Una vez creado el proyecto sustituimos los elementos de la carpeta src por los nuestros y añadimos en el build.gradle las librerías que aparecen en la Figura 5 13. Librerías del fichero build.gradle. Por último, modificamos las direcciones ip del servidor por la dirección ip de nuestro servidor. • TFG contiene los ficheros necesarios para la ejecución del servidor Rest y la base de datos. En primer lugar, seguimos los pasos del Anexo C y una vez tengamos configurado la base de datos, modificamos el fichero properties que se encuentra en la siguiente ruta TFG\invernadero\src\main\resources si queremos hacer algún cambio. Además, modificamos en los ficheros de implementación de los servicios la ip del Context Broker por nuestra ip. Por último, se inicia el servidor moviéndonos a la carpeta de invernadero desde la terminal e introduciendo el siguiente comando “mvn springboot:run”. 73 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía Figura 0-2. Inicio del Servidor Rest Para obtener la aplicación de OpenHAB debemos descargarnos de la página oficial de OpenHAB la versión disponible para Windows (Stable actualmente la 4.3.5). Figura 0-3. Instalar OpenHAB desde la página oficial Una vez nos hemos vez descargado el zip y extraído se pulsa en el start de Windows y se inicia Openhab como se indica en la Figura 0 4. Iniciar OpenHab. Una vez iniciado la aplicación, nos conectamos a la dirección ip (o al localhost) y a su puerto y creamos el usuario y la contraseña y en la ruta openhab\userdata metemos la carpeta jsondb disponible en git que contiene las reglas y los ítems usados. Anexo D: Construcción del sistema 74 74 Figura 0-4 Iniciar OpenHab 75 Control domótico de un sistema de riego, mediante OpenHAB y Fiware, para el ahorro del consumo de agua y energía REFERENCIAS [1] ibm, «¿Qué es el Internet de las cosas (IoT)? | IBM,» [En línea]. Available: https://www.ibm.com/mxes/topics/internet-of-things. [Último acceso: 2025 06 19]. [2] Oracle, «Oracle España,» [En línea]. Available: https://www.oracle.com/es/internet-of-things/. [Último acceso: 2025 06 19]. [3] marketsandmarkets, «Agriculture IoT Market Size & Share Industry Growth Analysis 2032,» [En línea]. Available: https://www.marketsandmarkets.com/Market-Reports/iot-in-agriculture-market199564903.html. [Último acceso: 06 05 2025]. [4] Docker, «What is a Container? | Docker,» [En línea]. Available: https://www.docker.com/resources/whatcontainer/. [Último acceso: 07 05 2025]. [5] Fiware-Orion, «FIWARE NGSIv2 Orion API Specification - Fiware-Orion,» [En línea]. Available: https://fiware-orion.readthedocs.io/en/master/orion-api.html#subscription. [Último acceso: 08 05 2025]. [6] Fiware-Orion, «API Walkthrough - Fiware-Orion,» [En línea]. Available: https://fiwareorion.readthedocs.io/en/master/user/walkthrough_apiv2.html#subscriptions. [Último acceso: 08 05 2025]. [7] Spring, «Using the @SpringBootApplication Annotation :: Spring Boot,» [En línea]. Available: https://docs.spring.io/spring-boot/reference/using/using-the-springbootapplication-annotation.html. [Último acceso: 08 05 2025]. [8] Spring, «Task Execution and Scheduling :: Spring Framework,» [En línea]. Available: https://docs.spring.io/spring-framework/reference/integration/scheduling.html#scheduling-enableannotation-support. [Último acceso: 08 05 2025]. [9] Oracle, « Java Persistence API,» [En línea]. Available: https://www.oracle.com/java/technologies/persistence-jsp.html. [Último acceso: 09 05 2025]. [10] Spring, «Spring Data,» [En línea]. Available: https://spring.io/projects/spring-data. [Último acceso: 09 05 2025]. [11] Docker, «Windows | Docker Docs,» [En línea]. Available: https://docs.docker.com/desktop/setup/install/windows-install/. [Último acceso: 18 05 2025]. Referencias 76 76