Trabajo Fin de Máster Máster en Ingeniería Industrial Autora: Luisa Piñero Alarcón Tutora: Amparo Núñez Reyes Diseño y desarrollo de una App para la supervisión de un campo solar de colectores Fresnel Departamento de Ingeniería de Sistemas y Automática Escuela Técnica Superior de Ingeniería Sevilla, 20 21
2
3 Trabajo Fin de Máster Máster en Ingeniería Industrial Diseño y desarrollo de una App para la supervisión de un campo solar de colectores Fresnel Autora: Luisa Piñero Alarcón Tutora: Amparo Núñez Reyes Profesora titular Departamento de Ingeniería de Sistemas y Automática Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2021
4
5 Gracias a mis padres y a mi hermano por animarme a seguir en la distancia desde hace ya 10 años. Gracias a Paco, mi novio, sin cuyo apoyo no habría sido posible finalizar este capítulo de mi vida.
7 Agradecimientos Doy las gracias a mi tutora Amparo Núñez Reyes por su paciencia, por haber sabido respetar mi ritmo y animarme en cada correo y en cada llamada, por encontrar un tema que me interesase y haber sabido orientarme para poner el broche final a mi paso por la ETSI que tantos momentos me ha dado (buenos y malos). Gracias a mi familia, que hace 10 años apostó por mí, y me apoyaron en mi idea de irme a estudiar fuera de casa (más de 400km fuera). Gracias a mi novio, que lleva aguantando a una novia ausente y estresada todo este tiempo, y siempre con una sonrisa y un hombro donde apoyarme. Pero sobre todo, gracias a Gema, la que ha estado conmigo hombro con hombro en los últimos cursos, tropezándonos con las mismas piedras que nos alejaban de terminar este máster, pero siempre juntas, gracias a ella y a su último empujón, que me motivaron a terminar este trabajo para salir las dos juntas de esta escuela en la misma convocatoria.
8
9 Resumen En este trabajo se lleva a cabo el desarrollo de una aplicación móvil para comunicarse con el campo de colectores de tipo Fresnel ubicado en la azotea del edificio de la Escuela Técnica Superior de Ingeniería de Sevilla. Con la aplicación se podrá monitorizar el sistema y actuar sobre el mismo dependiendo de la cualificación del personal registrado. Los estudiantes podrán acceder a la planta para obtener los datos que arroja en cada preciso momento la planta o para acceder a datos de días ya pasados. Los docentes podrán hacer lo mismo que los estudiantes y, además, podrán aceptar el registro de nuevos perfiles de acceso y añadir datos de incidencia al histórico de datos. También tendrán la posibilidad de apagar los motores de la planta con un único botón, en caso de detectar un peligro inminente. La aplicación tendrá distintas pantallas para acceder a los datos y a las acciones a realizar que se busquen en cada momento. Se adapta a las necesidades de cada perfil y será sencilla e intuitiva para que no sea necesario un conocimiento alto en tecnología para poder utilizarla. Esta aplicación conectará con bases de datos online (alojadas en una web) para acceder al registro de usuarios que pueden acceder a ella y para acceder a los datos de la planta que se deseen obtener o actualizar en cada momento. Esta aplicación podrá ser modificada para monitorizar cualquier otra planta de los laboratorios o para añadir otras plantas solares a la vez que esta, simplemente replicando lo que se ha desarrollado para la planta de la ETSI y seleccionando al inicio del acceso la planta a la que se desea acceder.
16 Ilustración 45 – Evidencia de acceso a la pantalla de histórico de datos de docente .................. 80 Ilustración 46 - Evidencia de cierre de sesión desde datos en directo ......................................... 80 Ilustración 47 - Evidencia de vuelta a pantalla de inicio desde datos en directo de estudiante... 81 Ilustración 48 - Evidencia de desplegable de histórico de datos ................................................. 81 Ilustración 49 - Evidencia de cierre de sesión desde histórico de datos ...................................... 82 Ilustración 50 - Evidencia de vuelta a pantalla de inicio de estudiante desde histórico .............. 82 Ilustración 51 - Evidencia de vuelta a pantalla de inicio de docente desde histórico .................. 83 Ilustración 52 - Evidencia de campo incidencia en perfil docente .............................................. 83 Ilustración 53 – Evidencia de error en incidencia si no existen datos ......................................... 84 Ilustración 54 - Evidencia de introducir incidencia en un día sin datos ...................................... 84 Ilustración 55 - Evidencia de intentar registrar un usuario ya registrado .................................... 85 Ilustración 56 - Evidencia de formato de correo no válido ......................................................... 86 Ilustración 57 - Evidencia de contraseña con tamaño incorrecto ................................................ 87 Ilustración 58 - Evidencia de contraseñas no coincidentes ......................................................... 88 Ilustración 59 - Evidencia de motivo sin informar ...................................................................... 89 Ilustración 60 - Evidencia de registro correcto de estudiante...................................................... 90 Ilustración 61Evidencia de inserción de nuevo usuario estudiante sin permisos ...................... 90 Ilustración 62 - Evidencia de correo de nuevo registro de usuario estudiante ............................ 90 Ilustración 63 - Evidencia de registro correcto de docente ......................................................... 91 Ilustración 64 - Evidencia de inserción de nuevo usuario docente sin permisos ........................ 91 Ilustración 65 - Evidencia de correo de nuevo registro de usuario docente ................................ 91 Ilustración 66 - Evidencia de usuarios pendientes de validación ................................................ 92 Ilustración 67 - Evidencia de permisos para acceder .................................................................. 92 Ilustración 68 - Evidencia de acceso de nuevo estudiante .......................................................... 93 Ilustración 69 - Evidencia de acceso de nuevo docente .............................................................. 93 Ilustración 70 - Evidencia de volver a la pantalla de acceso desde registro correcto .................. 94
17 ÍNDICE DE TABLAS Tabla 1 - Características del sistema de captación solar instalado en la ETSI ............................ 22 Tabla 2 - Características del acumulador de la PRS .................................................................. 23 Tabla 3 - Tabla de usuarios ......................................................................................................... 59 Tabla 4 - Tabla de datos en directo ............................................................................................. 61 Tabla 5 - Tabla de histórico de datos .......................................................................................... 63
18
19 1 INTRODUCCIÓN 1.1. Motivación y objetivos El objetivo de este trabajo consiste en la creación de una aplicación móvil capaz de monitorizar el campo solar instalado en el tejado de la Escuela Técnica Superior de Ingeniería de Sevilla (ETSI). Con la aplicación se podrá monitorizar la planta en todo momento, accediendo a los datos, pudiendo actuar sobre ciertas variables, recibiendo notificaciones de alarmas y obteniendo datos de históricos. Para acceder a la aplicación se deberá ser un usuario registrado, se podrá acceder desde dos perfiles diferenciados, perfil estudiante y perfil docente. El perfil estudiante accederá a los datos tanto actuales como históricos, mientras que el perfil docente, además, podrá introducir comentarios a los registros de histórico, podrá aceptar el acceso de nuevos usuarios y podrán parar los motores de la planta desde un botón en caso de ser necesario. La aplicación está diseñada para un único campo solar, pero es fácilmente adaptable para añadir cuantas plantas sean necesarias, ya que sería simplemente replicar la planta que ya está creada e implementar en la pantalla de inicio la selección del campo solar deseado. 1.2. Estructura del documento - Capítulo 1: Objetivo de este trabajo y motivaciones para llevarlo a cabo. - Capítulo 2: En este capítulo se detallan las características de la planta solar de la ETSI, su funcionamiento y las ventajas de este tipo de planta frente a otras. Se comenta también el estado del arte del sistema de monitorización y control de la planta, es decir, la existencia de otras aplicaciones con el uso que se le quiere dar a la que se desarrolla en este trabajo. - Capítulo 3: En este capítulo se explica con detenimiento el software utilizado en este trabajo, sus características y sus usos. - Capítulo 4: En el cuarto capítulo se comenta el diseño de la aplicación, tanto el estudio previo como los requisitos y la maqueta que sirve de partida para el desarrollo. - Capítulo 5: En este capítulo se especifica todo el proceso del desarrollo de la aplicación, el diseño completo en Unity de la aplicación, el acceso de usuarios a dicha aplicación y la conexión de ésta para acceder a los datos de la web. - Capítulo 6: En el capítulo sexto se realiza el seguimiento de las pruebas y resultados de la aplicación, así como su implementación. - Capítulo 7: En el último capítulo se abordan las conclusiones del trabajo.
20 2 PLANTA SOLAR En este capítulo se realizará una breve descripción del campo solar de tipo Fresnel perteneciente a la planta de refrigeración solar ubicada en la azotea de la Escuela Técnica Superior de Ingeniería. [1] [2] [3] Ilustración 1 - Planta solar tipo Fresnel 2.1. Descripción La planta solar se encuentra instalada en la azotea de la ETSI. La instalación se sitúa a 6° de longitud hacia el oeste y a 37,41° de latitud. La planta solar está situada a 12°3'1" al suroeste de la fachada sur y paralelamente a ésta Ilustración 2 - Localización de la planta solar
21 Esta planta de refrigeración solar (PRS) funciona a partir de un campo de captadores solares lineales de Fresnel que recoge la radiación del sol con objeto de calentar agua hasta unos 180◦C. El agua a esta temperatura se utiliza para accionar una máquina climatizadora que transforma la energía térmica en frío, el cual es apto para la climatización de las dependencias del edificio. Este tipo de funcionamiento ocurre cuando se necesita generar frio. Sin embargo, en invierno puede cambiar de funcionamiento para producir calor, lo cual lleva a cabo con un rendimiento del 95%. Como todos los equipos de este tipo, precisa de un sistema de disipación del calor generado en el absorbedor y en el condensador, para lo cual se utiliza un sistema de captación de agua que actúa como sistema de refrigeración. En concreto, se aprovecha el circuito de agua de captación del río Guadalquivir que se creó para todos los edificios de la Exposición Universal del año 1992 (Expo’92) de la Isla de la Cartuja (Sevilla). Adicionalmente, la máquina de absorción instalada incorpora un quemador de gas natural que entra en funcionamiento como fuente de energía auxiliar, de forma que se garantice la disponibilidad del servicio en momentos de carencia de potencia térmica desde el lado solar. Es decir, cuando la irradiación es insuficiente para accionar la máquina de absorción, la energía proporcionada por el gas natural sirve de apoyo para mantener el proceso en funcionamiento. El esquema general de la planta se encuentra en la siguiente ilustración, en él podemos ver que la salida del sistema de energía solar pasa por un tanque de almacenamiento y después llega a una máquina de absorción de doble efecto. El objetivo de la instalación es refrigerar el edificio a partir del frío producido en la máquina de absorción por medio del agua calentada por la energía solar (por eso se puede llamar planta de refrigeración solar). En caso de tener exceso de energía esta se almacena en el tanque de almacenamiento, mientras que si la energía producida no es suficiente se utilizará el quemador de Gas Natural instalado para generar la energía restante. Ilustración 3 - Esquema general de la instalación
22 Centrándonos en la planta solar, las características se encuentran en la siguiente tabla: Extensión de terreno ocupada 480 m² Superficie reflectora primaria total 352 m² Orientación de la planta Este-Oeste Número de líneas receptoras 1 Longitud de la línea receptora 64 Tipo de receptor De cavidad con reflector secundario y cubierta de vidrio Altura de la línea receptora 4 m sobre los receptores primarios Anchura del receptor 0,3 m Tipo de absorbedor Tubo de acero DIN 1,4541 (AISI 321) Acero inoxidable austenítico estabilizado Fluido de trabajo Agua Generación de vapor No Presión de diseño 13 bar Número de filas de reflectores primarios por línea receptora 22 filas Número total de reflectores 176 Longitud de cada módulo reflector 4 m Anchura de los reflectores 0,5 m Reflectividad 0,92 Relación de concentración 25 Potencia térmica nominal 120KW Tabla 1 - Características del sistema de captación solar instalado en la ETSI
23 Características Valores Acumulador Peso en vacío 4100 Kg Peso lleno de agua 8150 Kg Capacidad de almacenamiento 291 KW h Potencia máxima 149.9 KW Salto de temperatura máximo 30 ◦C Carcasa Hidroquinona Temperatura de diseño 200 ◦C Presión de diseño 1 bar Volumen 3300 L Tubos Agua presurizada Temperatura de diseño 200 ◦C Presión de diseño 15 bar Volumen Tabla 2 - Características del acumulador de la PRS A continuación, se detallan los componentes del colector solar: • La estructura de acero marca los límites del área donde están situados los espejos, está recubierta con pintura en polvo y sostiene tanto los espejos como el tubo de absorción y el reflector secundario. • Los espejos reflectores son de vidrio y están unidos a un eje que es movido por un motor impulsor que se encargar del seguimiento solar. Por seguridad son ligeramente curvados elásticamente, el radio de curvatura es de entre 8,6 y 10.6 metros. • Los motores colocados en cada fila mueven 8 espejos de cada fila, cuatro en cada lado. • El reflector secundario envuelve al tubo captador y refleja la radiación solar que se desvía del receptor para aumentar la eficiencia óptica del sistema. También protege al receptor. • El tubo receptor tiene una absortividad nominal de 0.94, tiene un diámetro de 70mm y una longitud de 64 m. La temperatura máxima soportada es de 200ºC y la presión máxima en su interior de 16 bares. • Además de los componentes anteriores, en el sistema se utilizan diversos sensores que se comunican a través de CANopen con el autómata encargado del control de la planta, estos son los siguientes: - Sensor solar: se utiliza para la calibración automática detectando la reflexión de los espejos primarios no centradas en el receptor.
24 - Potenciómetro: cada fila de espejos cuenta con un sensor de este tipo que envía la posición actual de cada fila. - Sensor de temperatura: a la entrada y salida del captador se encuentra un sensor PT100 instalado para monitorizar la temperatura del fluido. La mayoría de los componentes de la instalación se pueden ver en la siguiente ilustración, esta fotografía fue tomada en una de las visitas a la planta para la comprobación de su estado. Ilustración 4 - Campo solar de la ETSI 2.2. Campo solar El objetivo principal de la planta Fresnel es reflejar los rayos solares sobre un largo receptor cilíndrico donde se generará calor. El receptor cilíndrico está situado a lo largo de una línea recta, y es por eso que esta disposición es conocida como sistema de foco lineal. El objetivo de un sistema de este tipo es la generación de energía, en este caso en forma de calor dentro del tubo cilíndrico que hemos comentado, por donde circula un fluido que será el encargado de transportar ese calor a una máquina de absorción, donde se absorberá dicho calor para producir frío. La generación de este calor se produce por la reflexión de la radiación solar a través de una serie de superficies reflectoras orientadas hacia el tubo receptor. Para concentrar correctamente los rayos solares sobre la superficie receptora se utiliza un mecanismo de control como puede ser un autómata programable. El autómata será el encargado de conocer la trayectoria del sol y hacer funcionar una serie de motores para mantener el sistema de superficies reflectoras orientadas hacia el tubo receptor. Por tanto, el sistema se compone de los siguientes elementos: • Receptor: formado por uno o varios tubos situados en un plano superior y paralelo al de los dispositivos reflectores. Contiene el fluido que transporta el calor por la instalación. Se encuentra rodeado parcialmente por un reflector secundario.
25 • Concentradores solares: sistema generalmente formado por espejos ligeramente curvados encargado de concentrar la energía solar en el receptor. • Motores: moverán los concentradores solares a partir de las señales recibas del sistema de control para que apunten al receptor y no perder así energía solar. • Sistema de control: dispositivo que controlará cada concentrador de forma independiente para orientarlos hacia el receptor. • Estructura: sujetará los diferentes planos de instalación. Ilustración 5 - Elementos de una planta solar tipo Fresnel El funcionamiento completo de la planta se puede describir con el diagrama de la siguiente ilustración. Ilustración 6 - diagrama de funcionamiento de la planta solar
32 4 ESTUDIO Y DISEÑO DE LA APLICACIÓN 4.1. Requisitos Según los estudios realizados por Jakob Nielsen, una interfaz de usuario que sea usable debe ser una interfaz que cumpla con los siguientes factores [9]: - Facilidad de aprendizaje: El uso de una interfaz debe ser intuitivo, una persona de entre las que conforman su público meta debe ser capaz de entender su funcionamiento sin la necesidad de un manual. - Eficiencia: El flujo de acciones debe ser corto y veloz, no requiriendo muchas etapas o mucho tiempo por parte del usuario, pero entregando los resultados esperados. - Sin requisición de memoria: El usuario no debe necesitar de su capacidad de memorización. A pesar de haber dejado de utilizar la aplicación por un tiempo, es importante que logre llevar a cabo las tareas que requiere sin mayor problema o consulta adicional. - Índice de error: La aplicación debe estar preparada para recuperarse en caso de errores, generar la menor cantidad posible de los mismos y ofrecer alternativas de corrección para el usuario en caso de que se presenten. - Experiencia satisfactoria: El usuario debe sentirse victorioso tras haber llevado a cabo una tarea con la ayuda de la aplicación, es decir, debe sentir la satisfacción de haber logrado la meta que se proponía. - Además, es importante acompañar la aplicación de un apartado estético atractivo y actual, acompañado de transiciones amigables y que hagan la experiencia más fluida y natural. Google pensó en ello con Android y publicó unas reglas de diseño llamadas Material Design. Por tanto, teniendo en cuenta todo lo anterior, los requisitos para esta aplicación son los siguientes: - La aplicación debe ser descargable gratuitamente en play store. - La aplicación debe ser sencilla e intuitiva, para que cualquier persona sin altos conocimientos técnicos pueda utilizarla. - Desde las distintas pantallas, desde todas ellas, debe haber un botón de cierre de sesión que nos lleve a la pantalla inicial previo al registro. - Para acceder a los datos debemos tener usuario y contraseña que haya sido validado por el administrador (en este caso será la tutora de este trabajo, Amparo Núñez).
33 - La aplicación tendrá distintas pantallas por las que podremos ir moviéndonos para obtener los distintos datos: 1. Pantalla de acceso: en ella habrá un desplegable para elegir el campo solar que se quiera observar, un recuadro para poner el usuario, otro para la contraseña, un botón para acceder y un enlace para solicitar el registro si no se tiene aún permiso para acceder. Si el registro es incorrecto se mostrará un error por pantalla. 2. Pantalla de inicio: A ella se llegará tras un acceso de un usuario registrado. En ella se dará la bienvenida al campo solar solicitado, habrá un tablón de noticias reservado para poner en un futuro novedades que puedan ser interesantes, y tres botones que llevarán a 3 pestañas distintas, botón de datos en directo, botón de histórico de datos y botón de cerrar sesión. 3. Pantalla de registro: A esta pantalla se accederá desde el enlace de registro de la pantalla de acceso. En dicha pantalla habrá 5 recuadros que rellenar: campo o campos solares a los que se solicita el acceso (ya que puede ser que sólo se necesite acceso a uno o a varios, pero no a todos, se seleccionarán a través de check en sus recuadros), correo electrónico, contraseña, confirmación de la contraseña y nombre completo y motivo por el cual se solicita el acceso. Será obligatorio rellenar todos los campos, si no se rellena saldrá un aviso y no se permitirá continuar hasta rellenar todos los huecos necesarios. Se encontrará también un botón de enviar que enviará dichos datos al administrador para que los confirme y dé de alta al usuario introduciéndolo en la tabla de la base de datos que crearemos para el registro. 4. Pantalla de histórico: A esta pantalla se accederá desde el botón de histórico de datos de la pantalla de inicio. En esta pantalla habrá un botón de cierre de sesión para volver a la pantalla de registro y un botón de flecha para retroceder a la pantalla de inicio; 3 desplegables para elegir año, mes y día y un botón de recuperar datos que nos mostrará en un recuadro la información del día seleccionado (debes elegir una opción de los 3 desplegables de modo que solo se seleccione un día, si ese día no tiene datos no se mostrarán resultados). 5. Pantalla de datos en directo: A esta pantalla se accederá también desde la pantalla de inicio, al pulsar el botón de datos en directo. Al igual que en la pantalla anterior, se tendrá un botón de cierre de sesión que lleve a la pantalla inicial. Habrá en esta pantalla un recuadro con los datos actuales del campo solar. 6. Pantalla de registro correcto: A esta pantalla se accederá tras darle al botón de enviar de la pantalla de registro, en ella estará escrita la frase: “Su solicitud ha sido registrada con éxito. Se le comunicará por correo electrónico cuando sea aceptada ¡Gracias!”. Y un botón de cerrar que llevará de nuevo a la pantalla de acceso.
34 - Las conexiones serán hacia una base de datos que simulará el campo solar de la ETSI. La base de datos debe crearse específicamente para este trabajo. - Si se pulsa el botón “atrás” se irá a la pestaña abierta justamente anterior. - Los datos de solicitud de registro llegarán al administrador por correo y éste los añadirá al listado de usuarios registrados y avisará a dicho usuario de que ya puede acceder si así lo desea. - Se debe comprobar, al iniciar sesión en la pantalla de acceso, que el usuario y la contraseña coinciden con un usuario de la tabla que contiene todos los usuarios/contraseñas que han sido dados de alta. Dicha tabla es dinámica y puede ser modificada por parte del administrador tanto para añadir usuarios como para quitarlos. Se debe cuidar la apariencia de la aplicación para que sea funcional pero también agradable a la vista. La planificación de este trabajo se ha realizado con un tablero Kanban realizado en Trello. Kanban ha ido ganando popularidad durante las últimas décadas. Nació para aplicarse a los procesos de fabricación y con el tiempo se convirtió en un territorio reclamado por los desarrolladores de software. Últimamente, ha empezado a ser reconocido por las entidades empresariales de diferentes ámbitos. [10]. Ilustración 7 - Planificación con un tablero Kanban
35 Con esta herramienta se puede planificar las distintas tareas necesarias, así como pasarlas a “en curso” o terminadas cuando corresponde. También se pueden añadir etiquetas (en este caso diferenciamos entre documentación del trabajo y el desarrollo de la aplicación). También sirve para añadir comentarios a las tareas y no perder el hilo si pasa tiempo sin retomarla. Se ha querido dedicar un pequeño apartado para esto, para mostrar las distintas herramientas que se han usado en todo el trascurso de la realización de este trabajo, y no solo en la parte más técnica, sino también en la parte previa de organización, ya que somos conocedores de su gran importancia. Buscando información acerca de cómo afrontar el desarrollo de una aplicación móvil (y de cualquier proyecto en general), se comenta la importancia de una buena planificación inicial y las herramientas que pueden ser de gran utilidad para un correcto trascurso y meta. Se ha decidido usar Trello ya que es una herramienta que se utiliza en el trabajo para organizar el día a día y no olvidar las tareas que se tienen pendientes o en curso. Las tareas pueden ser compartidas entre varios miembros y así vemos lo que otros han hecho sobre ellas y no realizan lo mismo dos personas a la vez por no saber que otro compañero ha cogido esa tarea ya. En este caso no tiene esta funcionalidad pues es únicamente para uso de la persona que desarrolla la aplicación, pero es interesante de cara a planificar este proyecto y marcar unos puntos de control en las fechas que se consideran críticas. También se ha querido mostrar otra herramienta que no se aprende en la ETSI, para tener una alternativa al Microsoft Project que sí se estudia en algunos grados, para que todo estudiante que lea este TFM pueda conocer otras opciones, que es más interesante que realizar la planificación con una herramienta que ya se maneja. A lo largo de la realización de esta aplicación se han tenido que tomar diversas decisiones. En un principio se pensó hacer la aplicación con Android Studio, que es el entorno de desarrollo integrado oficial para la plataforma Android. Tenía varias ventajas como mucha información gratuita en la red y de fácil acceso, pero por otro lado se basa en java que no es un lenguaje que domine la estudiante que ha realizado este trabajo, por lo que sería necesario aprenderlo para poder empezar a crear aplicaciones de cierta complejidad. Como el tiempo empleado para aprender java desde cero es bastante alto y no sería cuantificable para el desarrollo de esta aplicación, objeto de Trabajo Fin de Máster, finalmente se ha decidido utilizar Unity por su versatilidad sin necesidad de grandes nociones de lenguajes informáticos para obtener una aplicación funcional en un período de tiempo asumible y poder dedicar tiempo a hacerla lo más completa posible sin perder el tiempo en la formación previa necesaria, que repetimos, sería difícil cuantificar. 4.2. Maqueta Siguiendo los requisitos iniciales, se realiza un mockup (boceto) de cómo quedarían las distintas pantallas de la aplicación en un primer diseño. Se ha usado para tal fin Drawio, que es una aplicación online gratuita con diversas opciones desde bocetos en blanco hasta prediseños para los usos más comunes. En este caso se decidió empezar desde 0 para asemejar a la pantalla del móvil y todos sus partes que no siguen ningún patrón típico, como puede ser un bocadillo de conversación, una nube de pensamiento o unas viñetas. La imagen queda así:
36 Ilustración 8 - Mockup de la aplicación Como se puede observar, desde la pantalla de acceso podemos ir a dos pantallas, la de “inicio” si nos registramos con éxito o la de “registro” si pulsamos el botón de registrarse. Desde registrarse, y tras rellenar todos los campos y darle a enviar, se llega a la pantalla de “registro correcto” y al cerrar volvemos a la primera pantalla de acceso. Si se accede a la pantalla de inicio podemos leer las noticias, pulsar cerrar sesión para volver a la pantalla de acceso o dar a los botones de datos en directo o histórico de datos. Si pulsamos al botón de “datos en directo” accedemos a la pantalla de datos en directo, desde ella podemos dar al botón de atrás para volver a la pantalla de inicio o al botón de cerrar sesión para volver a la pantalla de acceso. De igual modo si pulsamos el botón
37 de “histórico de datos” accedemos a la pantalla de histórico de datos, donde podremos elegir la fecha que queramos consultar con los 3 desplegables que hay, y al dar al botón “recuperar datos” aparecerán abajo los datos solicitados, de igual modo podemos pulsar el botón de la flecha que nos lleva hacia atrás a la pantalla de inicio o el botón de cerrar sesión para volver a la de acceso. A continuación, se muestran todas las pantallas anteriormente descritas: Ilustración 9 - Pantallas de acceso e inicio
38 Ilustración 10 - Pantallas de registro e histórico
39 Ilustración 11 - Pantallas de directo y registro correcto 4.3. Nombre y logotipo de la aplicación Se decide llamar a la aplicación “EnergyApp” por ser un nombre corto y fácil de recordar. También se diseña el logo siguiente: Ilustración 12 - Logo de la aplicación EnergyApp
40 5 DESARROLLO DE LA APLICACIÓN En este apartado se presenta la descripción con detalle del funcionamiento de cada una de las partes de la aplicación. 5.1. Esquema de la aplicación El esquema de la aplicación es el siguiente: Ilustración 13 - Diagramas y relaciones de la aplicación
41 En el esquema se representa la división de la aplicación. La parte rosa es Unity, donde está la parte visual, con lo que el usuario interactúa. Esta parte conecta con la verde (la parte de los datos de la planta, en este caso en una base de datos de MySQL alojada en la web) gracias a php (la azul), que funciona como nexo. Gracias al fichero dbConnection, se puede conectar con dicha base de datos y gracias al resto de ficheros php, extraer los datos necesarios que mandar a la aplicación para que estos se puedan visualizar. 5.2. Capas de la aplicación EnergyApp se ha diseñado para satisfacer el uso por parte del usuario, por lo que gran parte del contenido se centra en la interfaz gráfica y escenas de esta aplicación. Este diseño intuitivo se consigue separando las distintas capas que lo componen, como son la de modelado de datos o capa de datos y el servidor de peticiones o capa de negociación que conforman el “backend” y las escenas con la interfaz de Unity o capa de presentación que conforman la parte del “frontend”. - Capa de datos: La capa de datos está formada por el propio servidor de base de datos externo basado en MySQL, el cual contiene diferentes tablas a modo de simulación de los datos que se desean extraer a futuro del campo solar. Las tablas son las siguientes: - Tabla de usuarios: En esta tabla se recogen los usuarios que tienen acceso (o lo han solicitado) a la aplicación. Se compone de los siguientes campos: correo: Email de usuario para el acceso password: Contraseña para el acceso rol: campo enumerado con alternativas ‘profesor’ y ‘alumno’ acceso: campo enumerado con alternativas ‘si’ y ‘no’ - Tabla de datos en directo: En esta tabla se recogen los datos en directo de la planta, es decir, la foto del momento en el que se lanza la consulta. Los campos que la componen son los siguientes: TSC: Temperatura de salida del colector expresada en ºC TEC: Temperatura de entrada del colector expresada en ºC TST: Temperatura de salida del tubo expresada en ºC TAMB: Temperatura ambiente expresada en ºC motores: binario entre 0 y 1 que determina si el motor está apagado o encendido respectivamente. Se han registrado en esta tabla un total de 22 motores diferentes tanque: Carga del tanque de almacenamiento expresada en kW.h energia: Energía generada expresada en kW.h presión: Presión expresada en bares - Tabla de datos históricos: En esta tabla se recogen los datos de la planta de días pasados. Los campos son los siguientes: fecha: fecha del registro salidaSol: hora de salida del Sol para la fecha indicada puestaSol: hora de puesta de Sol para la fecha indicada alarmaTs: binario entre 0 y 1 que determina si durante la fecha de entrada se ha activado o no la alarma de temperatura
48 tempTec (Text): Texto que indica la temperatura actual de entrada del colector. Se expresa en ºC. tempTst (Text): Texto que indica la temperatura actual de salida del tubo. Se expresa en ºC. tempAmb (Text): Texto que indica la temperatura actual ambiente. Se expresa en ºC. presion (Text): Texto que indica la presión actual. Se expresa en ‘bar’. energiaGenerada (Text): Texto que indica la energía generada actual. Se expresa en kW.h. Actualizar Datos (Button): Botón cuya acción actualiza la salida de datos en pantalla. - DatosHistorico: Esta escena refleja los datos relativos a una fecha concreta almacenada en el histórico. Los elementos que la componen son: dia (DropDown): Elemento desplegable que lista los días a elegir para la extracción de los datos. mes (DropDown): Elemento desplegable que lista los meses a elegir para la extracción de los datos. año (DropDown): Elemento desplegable que lista los años a elegir para la extracción de los datos. aceptarFecha (Button): Botón cuya acción permite realizar la carga de datos para el combo de día-mes-año introducido en los campos anteriores. alarmaTs (Image): Imagen que representa el estado de la alarma de temperatura. Ésta salta (se vuelve de color rojo) si la temperatura de salida del colector saltó durante el día elegido, de lo contrario permanece en color verde. alarmaM (Image): Imagen que representa el estado de la alarma de motor. Ésta salta (se vuelve color rojo) si la alarma de algún motor apagado saltó durante el día elegido. Si todos los motores funcionaron durante todo el día elegido, el indicador lucirá de color verde. alarmaP (Image): Imagen que representa el estado de la alarma de presión. Ésta salta (se vuelve de color rojo) si la presión superó los 15 bares durante el día elegido. acumulacionMax (Text): Texto que indica la capacidad máxima que alcanzó el tanque durante el día elegido expresada en kW.h. tempTscMed (Text): Texto que indica la temperatura media de salida del colector durante el día elegido. Se expresa en ºC. tempTecMed (Text): Texto que indica la temperatura media de entrada del colector durante el día elegido. Se expresa en ºC. tempTstMed (Text): Texto que indica la temperatura media al de salida del tubo durante el día elegido. Se expresa en ºC. tempAmb (Text): Texto que indica la temperatura media ambiente durante el día elegido. Se expresa en ºC. presionMed (Text): Texto que indica la presión media obtenida durante el día elegido. Se expresa en ‘bar’. energiaGenerada (Text): Texto que indica la energía media generada durante el día elegido. Se expresa en kW.h. Actualizar Datos (Button): Botón cuya acción actualiza la salida de datos en pantalla. Incidencia (Text): Texto que refleja si se introdujo alguna incidencia para el día seleccionado. ComentarioIncidencia (InputField): Entrada de texto que recoge a modo de comentario la incidencia. Al pulsar sobre el botón Actualizar, se guarda la incidencia para el día seleccionado.
49 Actualizar (Button): Botón cuya acción habilita la inserción de la incidencia comentada en ComentarioIncidencia. 5.4.1. Creación de las escenas en Unity Para crear cada una de las pantallas de las que se compone nuestro programa, debemos hacer lo siguiente, arriba a la izquierda le damos a “file” y a “new scene”, ahí le podremos dar el nombre que queramos. Pantalla de acceso (0): Ilustración 15 - Pantalla de acceso Los elementos que se han añadido a esta escena son los siguientes:
50 Ilustración 16 - Elementos de la pantalla de acceso Para añadir todos estos elementos se debe hacer click con botón derecho (sobre el panel izquierdo en “hierarchy”) bajo el título, seleccionamos “UI” (interfaz de usuario) y elegimos en primer lugar “Canvas”, bajo este componente pondremos todos los demás colgando de él, del mismo modo, click derecho, UI y elegimos. En este caso tenemos imágenes, textos, un “dropdown” (desplegable), “inputField” (campos para introducir datos), un botón y script que llamamos cargar escena que nos sirve para acceder a otra pantalla desde ésta. Pantalla de inicio (1): En esta pantalla vamos a ver el primer cambio respecto al diseño original. Por un tema de seguridad y comodidad de cara al manejo de los registros de usuarios, se va a diferenciar entre perfil estudiante y perfil docente. La diferencia radica en que un perfil docente será el único perfil con permiso para poder aceptar nuevos usuarios. Por tanto, esta pantalla de inicio será distinta según el perfil que se sea. Si eres estudiante, verás la siguiente pantalla:
51 Ilustración 17 - Pantalla de inicio (estudiante) Sin embargo, si eres docente, verás la siguiente pantalla, en la que podrás ver las solicitudes de acceso pendientes y aceptarlas: Ilustración 18 - Pantalla de inicio (docente)
52 Al darle a “Ver campo solar” sí se accede a una pantalla igual a la que ve el estudiante. Es decir, esta pantalla sería una pantalla intermedia entre iniciar sesión y acceder al panel de bienvenida desde el que acceder a los datos de la planta, esta pantalla intermedia solo la tendrán los perfiles “docente” para poder admitir a nuevos usuarios. El método de añadir los elementos es el mismo que la pantalla 0 explicada arriba, por lo que no repetiremos los objetos que ya se han mencionado para no ser redundantes y sólo se comentará algún elemento nuevo si se da el caso, como en este caso en el que tenemos un “Scroll View” que es simplemente un objeto que podemos ver más de su contenido haciendo scroll con el ratón. Y se añade aquí una interacción hacia la base de datos de apagar todos motores (ponerlos a 0) dándole a un único botón, añadiendo así una acción de control de la aplicación. Ilustración 19 - Elementos de la pantalla de inicio de docente Pantalla de registro (2): En esta pantalla vamos a ver algunos cambios que se han introducido ya que, si existe un perfil estudiante y otro docente, esto se deberá especificar en la solicitud de registro. Esto lo haremos con un check que se seleccionará si se es docente y se dejará sin marcar en caso de ser estudiante. También se ha decidido centrarnos únicamente en el campo solar de la ETSI por lo que el registro se hará para este campo y la base de datos creada para los usuarios será sólo para este campo solar, en el caso futuro de querer ampliar para abarcar otras plantas solares será tan sencillo como replicar lo que se hace para esta planta, pero no creemos que aporte valor a este trabajo realizar lo mismo para otros campos solares inventados. La pantalla quedará así:
53 Ilustración 20 - Pantalla de registro Y la forman los siguientes elementos: Ilustración 21 - Elementos de la pantalla de registro
54 Pantalla de histórico (3): Estos datos se van a obtener de una base de datos donde se han simulado registros tanto para los datos en directo como para este histórico de datos, la idea cuando la planta esté en funcionamiento será pasar los datos de los distintos sensores a una base de datos online donde podamos conectar la aplicación del mismo modo que ha sido conectada para nuestra base de datos online. Ilustración 22 - Pantalla de histórico de datos de estudiante Elementos que lo forman: Ilustración 23 - Elementos de la pantalla de histórico de datos
55 Para esta pantalla se tiene una variante para el caso de docente, éste podrá añadir un comentario a la tabla en el campo de “incidencia”. Por ejemplo, si un día se ha parado alguno de los motores por alguna avería, el docente podrá dejar constancia desde la propia aplicación. La pantalla quedará por tanto del siguiente modo: Ilustración 24 - Pantalla de histórico de datos para perfil docente Y sus elementos: Ilustración 25 - Elementos de la pantalla de histórico de datos para docente
56 Pantalla de datos en directo (4): Ilustración 26 - Pantalla de datos en directo Elementos que lo forman: Ilustración 27 - Elementos de la pantalla de datos en directo
57 Pantalla de registro correcto (5): Ilustración 28 - Pantalla de registro correcto Y los elementos de esta pantalla son los siguientes: Ilustración 29 - Elementos de la pantalla de registro en directo
64 alarmaMot: Alarma que avisa si alguno de los 22 motores se ha parado en este día (ha tomado el valor de 0). Idem que la anterior. Booleana, 0 apagada, 1 encendida. acumulacionMax: Registra el % de carga mayor del día (entre 0 y 100) del acumulador de energía. tecMed: Temperatura media de entrada al captador (ºC). tscMed: Temperatura media de salida al captador (ºC). tstMed: Temperatura media de salida de los tubos (ºC). tambMed: Temperatura ambiente media (ºC). presiónMed: Presión media (bar) energíaGen: Energía generada por campo solar al final del día (KW·h). 5.7. Módulos de la aplicación La parte funcional de la aplicación puede dividirse en dos grandes módulos: el módulo de accesos y el de datos. A continuación, se comentan en detalle estos módulos que conforman la lógica funcional de EnergyApp. 5.7.1. Acceso El módulo de acceso es el encargado de gestionar los usuarios, tanto para el registro de estos como para el inicio de sesión una vez registrados. - Capa de datos: La capa de datos relativa a este módulo la compone la siguiente tabla: Usuarios - Capa de negociación: La capa de negociación relativa a este módulo la componen los PHP siguientes: dbConnection.php loginUsuario.php registroUsuario.php administraciónUsuarios.php - Capa de presentación: La capa de presentación está compuesta por las escenas y los scripts siguientes: Login (escena) Registro (escena) Administración (escena) SceneManager.cs (script) NetworkManager.cs (script)
65 La lógica del módulo a bajo nivel es la siguiente: - En la pantalla de Login, un usuario introduce un ‘correo’ y una ‘contraseña’. Tras esto pulsa en ‘Iniciar Sesión’. En este momento, se realiza una conexión con la base de datos a través del servicio ofrecido por dbConnection.php. También se realiza una consulta para validar que el usuario y la contraseña corresponden con un usuario dado de alta y que dispone de acceso. La consulta es la siguiente: SELECT password,rol FROM alumnos WHERE correo = '$correo' - Si los valores de correo y contraseña introducidos son correctos, se carga la escena BienvenidaUsuario (si el rol del usuario es “alumno”) o BienvenidaProfesor (si el rol del usuario es “profesor”). - Desde la pantalla de Login, también es posible pulsar sobre el botón ‘¿No tienes cuenta?’. Este botón llama al script ‘SceneManager.cs’ para cargar la escena de Registro. - En la pantalla de Registro, el usuario introduce un correo válido, una contraseña y la validación de esta contraseña (repetición). También tiene la opción de indicar si el usuario a dar de alta es o no docente mediante un check seleccionable. Como medida, es obligatorio indicar el motivo por el que se necesita acceso a la aplicación. Al pulsar sobre el botón ‘Enviar’ y si los datos son correctos, el script ‘NetworkManager.cs’ realiza una llamada al servicio ‘crearUsuario.php’ el cual consulta a la base de datos si no existe el usuario previamente para introducir la entrada del nuevo usuario con la siguiente query: INSERT INTO alumnos(correo, password,rol,acceso) VALUES(:field1,:field2,:field3,'no') - Como consecuencia del éxito en el registro, el script se comunica con el servidor SMTP correspondiente para enviar una notificación vía email a los docentes que tienen acceso. El listado de usuarios con rol “profesor” y acceso “si” se obtiene a través del servicio que ofrece ‘profesoresAcceso.php’ mediante otra consulta a la base de datos: SELECT correo FROM alumnos WHERE rol LIKE 'profesor' AND acceso LIKE 'si' - Como último paso, se carga la escena RegistroCorrecto, notificando al usuario del registro exitoso. 5.7.2. Datos El módulo de datos es el encargado de gestionar los datos relacionados con los campos solares, tanto en directo como por histórico. - Capa de datos: La capa de datos relativa a este módulo la componen las siguientes tablas: datosDirecto historicoDatos - Capa de negociación: La capa de negociación relativa a este módulo la componen los PHP siguientes: dbConnection.php obtenerDato.php
66 obtenerDirecto.php introducirDatos.php - Capa de presentación: La capa de presentación está compuesta por las escenas y los scripts siguientes: DatosDirecto (escena) DatosHistórico (escena) SceneManager.cs (script) DatosSolares.cs (script) Directo.cs (script) La lógica del módulo a bajo nivel es la siguiente: - En la pantalla de Bienvenida, el usuario puede seleccionar si desea ver los datos en directo o si prefiere consultar el histórico. Estas acciones se revelan a través de unos botones que llaman al script ‘SceneManager.cs’. - Desde la pantalla de datos en directo los datos se cargan instantáneamente gracias al servicio que ofrece ‘obtenerDirecto.php’ y su respectiva conexión a la tabla ‘datosDirecto’. La consulta que se realiza es la siguiente: SELECT * FROM datosDirecto - Esto muestra por pantalla los datos y permite volver a llamar al mismo servicio si pulsamos sobre el botón ‘Actualizar Datos’. - Desde la otra pantalla de datos que corresponde con el Histórico, el usuario debe seleccionar un día, un mes y una fecha y pulsar sobre el botçon de validar junta a esta. En este momento se realiza una consulta mediante el servicio ‘obtenerDatos.php’: SELECT * FROM historicoDatos WHERE fecha= '$fecha' - Si la fecha coincide con la de alguna entrada en la tabla ‘historicoDatos’ de la base de datos con la que conecta, se pinta la información en pantalla. Si no, devuelve un error. Estas acciones las realiza el script ‘DatosSolares.cs’. - Además, en esta pantalla también encontramos un campo de texto donde es posible introducir a modo de comentario una incidencia para el día seleccionado. Si el usuario introducie texto en ese campo y pulsa sobre el botón validar que se encuentra a su derecha, la aplicación insertará a través del servicio ‘introducirDatos.php’ la incidencia en la entrada para la fecha seleccionada. La query que realiza la actualización de incidencia es la siguiente: UPDATE historicoDatos SET incidencia='$incidencia' WHERE fecha = '$fecha'. 5.8. Intento de conectar con Matlab La idea inicial de esta aplicación no era otra que la de conectar esta aplicación directamente con la planta real. Esto no ha podido ser posible ya que la planta de la ETSI sigue parada tras la avería,
67 y no se sabe cuánto tiempo pasará hasta que se compren los repuestos necesarios para su puesta en marcha de nuevo. Por tanto, la segunda idea que se tuvo fue intentar conectarla a una simulación en Matlab de esta planta, que estaba desarrollando un compañero de otro máster. El problema en este punto estaba en que el ritmo de realización de los trabajos no era el mismo ni iban necesariamente en paralelo, y se necesitaban datos de esa simulación para ir avanzando con este trabajo, y esto era lo final del trabajo del compañero que no contaba con entregarlo este curso, por lo que esperar para poder intentar conectar esta aplicación a su simulación no era viable. Por tanto, y a modo avance de cara al compañero que realice la conexión de esta aplicación con la simulación o con la planta real, se decidió intentar conectar la aplicación con Matlab aunque solo fuera para recoger y mostrar algún valor que se le pasase a la aplicación. El problema principal que nos encontramos fue que la mayoría de información era bastante antigua y obsoleta para las conexiones entre Unity y Matlab. Hay que dejar claro que la mayoría de información se ha obtenido en foros en inglés entre distintos trabajadores de la comunidad informática, y prácticamente todos desembocaban en el mismo código. Tras buscar en distintos foros y vídeos de ejemplos [15] [16], todas las conexiones entre Unity y Matlab tienen el siguiente código base para el caso que necesitamos en el que Unity es el servidor (server) y Matlab el cliente (client): Unity: using UnityEngine; using System.Collections; using System.Net; using System.Net.Sockets; using System.Linq; using System; using System.IO; using System.Text; public class readSocket : MonoBehaviour { // Use this for initialization TcpListener listener; String msg; void Start () { listener=new TcpListener (55001); listener.Start (); print ("is listening"); } // Update is called once per frame void Update () { if (!listener.Pending ()) { } else { print ("socket comes"); TcpClient client = listener.AcceptTcpClient (); NetworkStream ns = client.GetStream (); StreamReader reader = new StreamReader (ns); msg = reader.ReadToEnd(); print (msg); } } }
68 Matlab: clc clear all tcpipClient = tcpip('127.0.0.1',55001,'NetworkRole','Client'); set(tcpipClient,'Timeout',15); fopen(tcpipClient); a='yah!! we could make it'; fwrite(tcpipClient,a); fclose(tcpipClient); El código de Matlab empezaba dando el aviso de que la parte de “clear all” no era necesaria y que solía dar problemas, por lo que decidimos eliminarlo del código al ver que obteníamos el mismo resultado con él que sin él. Tras esto, llegó el error de que el comando “tcpip” estaba obsoleto, parece que las últimas versiones de Matlab no aceptan este comando y en su lugar te piden usar el “tcpClient”, por lo que hicimos dicha corrección y nos encontramos con el problema de que el “fopen” parecía no poder abrir la variable “tcpipClient” ya que esta no era un fichero, por lo que probamos a realizar un paso intermedio definiendo una variable “data” que leyera dicha variable y se quedara con los primeros 30 caracteres (de sobra para leer la dirección ip). Con estas correcciones el código queda del siguiente modo: clc tcpipClient = tcpclient('127.0.0.1',55001,'Timeout',15); data=read(tcpipClient,30,"string"); fopen(data); a='yah!! we could make it'; fwrite(tcpipClient,a); fclose(tcpipClient); El problema, es que no se consigue una conexión correcta tras muchos intentos y distintas pruebas, algo ocurre en Unity pero en Matlab tras pasar los 15s del timeout falla diciendo que no ha sido capaz de conectar. Hay que tener en cuenta que en estas conexiones, primero debe ejecutarse la parte del servidor (en este caso el programa de Unity) y después la de cliente (en este caso Matlab), si no se hace así, nos aparecerá un error. El problema que nos hemos encontrado además, es que cada vez que ponemos a correr Matlab, la parte de Unity se queda pillada y el programa deja de reaccionar a nuestros intentos de pararlo o hacer cualquier modificación, de modo que hay que cerrar Unity desde el administrador de tareas del equipo y volver a abrirlo de nuevo (tarda un par de minutos en arrancar todo) de modo que todos los intentos de arreglar esto han desencadenado mucho tiempo perdido cerrando y abriendo el programa antes de revisar y volver a hacer otro intento. En la consola de Unity vemos como se pinta el “is listening” al ejecutar el programa y llega a pintar el “socket comes” cuando se ejecuta el programa de Matlab a continuación.
69 Ilustración 31 - Consola de Unity durante la ejecución con Matlab Sin embargo, pasados los 15 segundos, Matlab pinta el siguiente fallo: Ilustración 32 - Fallo en Matlab tras intentar leer de Unity 5.9. Google play Google Play es la tienda de aplicaciones de Android. Para subir cualquier aplicación es necesario darse de alta como desarrollador, con un coste de 30€ y cumplir con una serie de requisitos a la hora de creación del contenido de la ficha para Google Play y en el código de la aplicación. Para la subida de una aplicación a la tienda de aplicaciones primero es necesario que ésta sea compilada y firmada se debe generar un archivo “key”(.jks). Con la key y habiéndose podido corregir los warnings y errores que este exigente compilado detecta, obtendremos nuestra apk lista para la subida. Es importante realizar copias de seguridad de la key entregada pues no se puede volver a generar y si no se dispone en el futuro de ella, no se podrá volver a actualizar la aplicación en la tienda de aplicaciones, teniéndose que subir otra versión diferente duplicando así la aplicación en la Play Store y con el consecuente problema de actualización a los usuarios. Google Developer Console es un portal donde los desarrolladores suben sus aplicaciones a la tienda Play Store, crean las fichas de información de dicha aplicación y consultan todo tipo de estadísticas relevantes para el desarrollo su desarrollo y seguimiento. La aplicación se clasificaría en la categoría que más encaje y una vez subida se le aplica unas clasificaciones de consumo, que suelen ser las más sencillas para una aplicación de estas características. En el Developer Console hay un apartado de APK que nos dirá la compatibilidad de nuestra aplicación, dándonos el número de modelos de dispositivos diferentes compatibles con la aplicación, y también veremos ahí el número de actualizaciones de ésta.
70 También hay un apartado de bastante interés que es el apartado de reporte de errores de usuarios, donde aparecerá si se ha detectado algún error que haya sido reportado por los usuarios que han descargado la aplicación. [14] En el caso de esta aplicación se ha decidido no subirla por ahora a Google play ya que estamos ante una versión beta de la aplicación que carece aún de una conexión a la planta real, por lo que la funcionalidad actual sería más bien de prueba y no será hasta más adelante que será plenamente funcional, una vez que exista una web con datos reales cuando la planta esté de nuevo en funcionamiento. Por tanto, actualmente la subida a Google play solo conllevaría un gasto económico y, además, dicho perfil quedaría asociado a la autora de este trabajo, y entorpecería futuras actualizaciones realizadas por otros estudiantes que pudieran heredar este trabajo para continuarlo. Además, estaría el gran inconveniente de que cualquier persona podría descargarse la aplicación e intentar registrarse, llegándole avisos al correo a los docentes que estén registrados en la aplicación. Viendo que los contras actuales son mucho mayores que los pros, se decide informar de los pasos a seguir para la subida de una aplicación a Google play, pero sin llevarlo a cabo en este momento.
71 6 IMPLEMENTACIÓN, PRUEBAS Y RESULTADOS Una vez finalizado el desarrollo de la aplicación en Unity se revisan los datos de los sistemas operativos más usados el año pasado para poder hacernos una idea del mercado actual de cara a la distribución de esta aplicación. Las estadísticas son las siguientes [15]: Ilustración 33 - Sistemas Operativos móviles más usados El sistema operativo móvil más usado en el mundo en 2020 fue el Android, con un 71.42%, seguido de IOS con 27.95%, teniendo con éste prácticamente el 100% de los sistemas operativos utilizados, aunque con bastante diferenciados el primer y el segundo puesto. Android es un sistema operativo móvil basado en el núcleo Linux y otros softwares de código abierto. Fue diseñado para dispositivos móviles con pantalla táctil, como teléfonos inteligentes, tabletas, relojes inteligentes Wear OS, automóviles con otros sistemas a través de Android Auto, al igual los automóviles con el sistema Android Automotive y televisores Android TV. Inicialmente fue desarrollado por Android Inc., que fue adquirido por Google en 2005. Android fue presentado en 2007 junto con la fundación del Open Handset Alliance (un consorcio de compañías de hardware, software y telecomunicaciones) para avanzar en los estándares abiertos de los dispositivos móviles. El código fuente principal de Android se conoce como Android Open Source Project (AOSP), que se licencia principalmente bajo la Licencia Apache. Android es el sistema operativo móvil más utilizado del mundo muy por encima de IOS. Según los documentos secretos filtrados en 2013 y 2014, el sistema operativo es uno de los objetivos de las agencias de inteligencia internacionales. [16]
72 Además, cabe destacar, que España está muy por encima de ese porcentaje ya que el mercado de smartphones en España tiene particularidades que no tiene ningún otro. El 90,8% de todos los que se vendieron entre junio y agosto de 2013 funcionaban con sistema Android, según Kantar Worldpapnel. No hay otro país con ese porcentaje, pues el siguiente China tenía solo un 72,4%. [17]. 6.1. Implementación Con intención de ser lo más eficientes posible, se plantea pues el desarrollo de la aplicación móvil en este SO, Android, que nos ofrece la capacidad de abarcar un mercado y un público más extenso programando en su plataforma. Además, pese a no ser lo que se pensó en un principio, se decide compilar también para ordenador, de modo que la aplicación pueda ser usada también desde un ordenador si es más cómodo. Ambos casos se testean para poder comprobar su correcto funcionamiento y su visualización adaptada a cada uso. Cabe destacar que se podría compilar para IOS, pero en este caso no se puede asegurar su correcto funcionamiento y conexiones hacia las bases de datos generadas, ya que se han desarrollado buscando información para aplicaciones Android, además, no se dispone de terminales ios para poder hacer pruebas y asegurar su correcto funcionamiento en estos terminales, por lo que se decide centrarnos en asegurar un funcionamiento sin errores en Android y para pc en el caso de que algún usuario no tenga terminal Android, ya que se entiende que todos los que necesiten acceder a estos datos disponen en casa o en la universidad de ordenador. 6.2. Testing Una de las partes más importantes de todo desarrollo es el “testing” o comprobación de que todo el código funciona. Durante este paso aparecen pequeños fallos que se irán corrigiendo y depurando hasta conseguir una aplicación sin errores en su ejecución. En el caso de esta aplicación se han determinado las siguientes pruebas: 6.2.1. Pantalla de acceso: Se muestra error cuando se intenta acceder con un usuario que no está registrado. Por ejemplo,
[email protected].
73 Ilustración 34 - Evidencia de usuario no registrado Se muestra error cuando la contraseña introducida para un usuario registrado es incorrecta. Por ejemplo “noeslacontraseña” para
[email protected]. Ilustración 35 - Evidencia de contraseña incorrecta Se muestra error cuando el usuario aún está pendiente de validación por parte de algún docente.
80 Ilustración 48 – Evidencia de acceso a la pantalla de histórico de datos de docente 6.2.3. Pantalla de datos en directo: Se cierra sesión y se vuelve a la pantalla de acceso. Ilustración 49 - Evidencia de cierre de sesión desde datos en directo
81 Se le da a la flecha de retroceder y se vuelve a la pantalla de inicio. Ilustración 50 - Evidencia de vuelta a pantalla de inicio desde datos en directo de estudiante 6.2.4. Pantalla de histórico de datos: Se selecciona una flecha con los desplegables y se da al check para obtener los datos si los hay. Ilustración 51 - Evidencia de desplegable de histórico de datos
82 Se cierra sesión y se vuelve a la pantalla de acceso. Ilustración 52 - Evidencia de cierre de sesión desde histórico de datos Se le da a la flecha de retroceder y se vuelve a la pantalla de inicio. Caso estudiante: Ilustración 53 - Evidencia de vuelta a pantalla de inicio de estudiante desde histórico
83 Caso docente: Ilustración 54 - Evidencia de vuelta a pantalla de inicio de docente desde histórico En caso de haber entrado con perfil docente, posibilidad de introducir un texto como incidencia al día seleccionado. Ilustración 55 - Evidencia de campo incidencia en perfil docente
84 Error en incidencia si se selecciona alguna fecha que no tiene datos. Ilustración 56 – Evidencia de error en incidencia si no existen datos Error al intentar introducir una incidencia en un día que no tiene datos. Ilustración 57 - Evidencia de introducir incidencia en un día sin datos
85 6.2.5. Pantalla de registro: Se muestra error si se intenta registrar un usuario ya registrado. Ilustración 58 - Evidencia de intentar registrar un usuario ya registrado Se muestra error si el correo no tiene la extensión “@hotmail.com”, “@gmail.com”, “@alum.us.es” o “@us.es”.
86 Ilustración 59 - Evidencia de formato de correo no válido Se muestra error si la contraseña no tiene 8 caracteres o más.
87 Ilustración 60 - Evidencia de contraseña con tamaño incorrecto Se muestra error si las dos contraseñas introducidas NO coinciden.
88 Ilustración 61 - Evidencia de contraseñas no coincidentes Se muestra error si no se rellena el campo de motivo.
89 Ilustración 62 - Evidencia de motivo sin informar Se accede a la pantalla de registro correcto al darle a enviar si todos los campos cumplen los requisitos. Caso de registro de un estudiante.
96 REFERENCIAS [1] W. D. C. Salazar, Modelado neuro - borroso de un sistema captador solar lineal tipo Fresnel como gemelo digital, Sevilla, 2020. [2] L. G. Parrilla, Modelado y simulación de una planta solar, Sevilla, 2019. [3] J. J. L. Amores, Desarrollo de sistema de calibrado automático de espejos de captador solar tipo Fresnel, Sevilla, 2020. [4] [En línea]. Available: https://www.electiaplus.es/apps - moviles - instalaciones - fotovoltaicas/. [5] [En línea]. Available: https: //nexusintegra.io/es/sistemas - scada - industria/. [6] [En línea]. Available: https://sourceforge.net/software/scada/android/. [7] «Wikipedia,» [En línea]. Available: https://es.wikipedia.org/wiki/Unity_(motor_de_videojuego). [8] J. D. L. Castillo, Andr oid studio Aprende a desarrollar aplicaciones, Libros RC. [9] «Wikipedia,» [En línea]. Available: https://es.wikipedia.org/wiki/MATLAB. [10] «SG,» [En línea]. Available: https://sg.com.mx/revista/31/la - importancia - la - claridad - y - sencillez-una-interfaz-usuario. [11] «Kanbanize,» [En línea]. Available: https://kanbanize.com/es/recursos - de - kanban/primeros-pasos/que-es-kanban. [12] [En línea]. Available: https://docs.unity3 d.com/es/530/Manual/UICanvas.html. [13] [En línea]. Available: https://docs.unity3d.com/es/2018.4/ScriptReference/. [14] «Meteogram,» [En línea]. Available: https://meteogram.es/sol/espana/sevilla/. [15] [En línea]. Available: https://www.mathworks.com/matlabcentral/answers/196774 - connection-between-matlab-and-unity3d. [16] [En línea]. Available: https://www.youtube.com/watch?v=tz8WHs - rIf8. [17] M. H. Núñez, Diseño de APP Android para seguimiento de la web de Antiguos Alumnos de la ETSI, Sevilla, 2016.
97 [18] «itsoftware,» [En línea]. Available: https://itsoftware.com.co/content/sistemas - operativos-mas-usados/. [19] «Wikipedia,» [En línea]. Available: https://es.wikipedia.org/wiki/Sistema_operativo_m%C3%B3vil#Android. [20] «El Pais,» [En línea]. Available: https://elpais.com/tecnologia/2013/10/01/actualidad/1380620296_338056.html. [21] [En línea]. Available: https://www.seoptimer.com/es/blog/notificacion es - push - que - son-por-que-usarlas/. [22] [En línea]. Available: https://openautomationsoftware.com/?utm_source=sourceforge&utm_medium=webs ite&utm_campaign=Sourceforge. [23] [En línea]. Available: https://openautomationsoftware.com/?utm_source=sourceforge&utm_medium=webs ite&utm_campaign=Sourceforge. [24] [En línea]. Available: https://sourceforge.net/software/product/Fernhill - SCADA/.
98
99 ANEXO A: CÓDIGO SCENEMANAGER.CS (CAMBIAR ESCENA) Este script sirve para cargar otra pantalla (scene) del programa, se le asigna a un botón al pulsarlo (en onclick), pasándole como parámetro la escena que se quiera abrir al realizar la acción. using UnityEngine; public class SceneManager : MonoBehaviour { public string escena; // Carga una escena según el parámetro que se le pasa por Unity public void CargarEscena() { UnityEngine.SceneManagement.SceneManager.LoadScene(escena); } } ANEXO B: CÓDIGO LOGIN.CS using MySql.Data.MySqlClient; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; public class Login : MonoBehaviour { public InputField correoTxt; public InputField passwordTxt; public Text textoError; public Image fondoError; // Start is called before the first frame update public void Logear() { string _log = "SELECT * FROM"+" alumnos WHERE correo LIKE '"+correoTxt.text+"' AND password LIKE '"+passwordTxt.text+"'"; AdminMysql _adminMYSQL =
100 GameObject.Find("AdministradorBaseDatos").GetComponent<AdminMysql>(); MySqlDataReader resultado = _adminMYSQL.Select(_log); if (resultado.HasRows){ resultado.Close(); string _profesor = "SELECT *"+" FROM alumnos WHERE correo LIKE '"+correoTxt.text+"' AND rol LIKE 'profesor'"; MySqlDataReader profesor = _adminMYSQL.Select(_profesor); if(profesor.HasRows){ profesor.Close(); string _acceso = "SELECT *"+" FROM alumnos WHERE correo LIKE '"+correoTxt.text+"' AND acceso LIKE 'si'"; MySqlDataReader acceso = _adminMYSQL.Select(_acceso); if (acceso.HasRows) { Debug.Log("El profesor con correo "+correoTxt.text+" tiene acceso"); UnityEngine.SceneManagement.SceneManager.LoadScene("EscenaBienvenidaProfesor" ); } else { Debug.Log("El usuario profesor está pendiente de ser validado por un profesor"); textoError.text = "Este usuario profesor se encuentra pendiente de ser aceptado en la app"; fondoError.gameObject.SetActive(true); } acceso.Close(); } else { profesor.Close(); string _acceso = "SELECT *"+" FROM alumnos WHERE correo LIKE '"+correoTxt.text+"' AND acceso LIKE 'si'"; MySqlDataReader acceso = _adminMYSQL.Select(_acceso); if (acceso.HasRows) { Debug.Log("El usuario con correo "+correoTxt.text+" tiene acceso"); UnityEngine.SceneManagement.SceneManager.LoadScene("EscenaBienvenida"); } else { Debug.Log("El usuario está pendiente de ser validado por un profesor"); textoError.text = "Este usuario se encuentra pendiente de ser aceptado en la app"; fondoError.gameObject.SetActive(true); } acceso.Close(); }
101 } else { Debug.Log("Correo y/o contraseña incorrectos"); textoError.text = "Correo y/o contraseña incorrectos"; fondoError.gameObject.SetActive(true); } resultado.Close(); } void Start() { } // Update is called once per frame void Update() { } } ANEXO C: CÓDIGO REGISTRO.CS using System.Collections.Generic; using System.Data; using MySql.Data.MySqlClient; using UnityEngine; using System.Net.Mail; using UnityEditor; using UnityEngine.UI; public class Registro : MonoBehaviour { public InputField correoTxt; public InputField passwordTxt; public InputField passwordTxt2; public InputField mensaje; public Text textoError; public Image fondoError; public Toggle checkProfesor; public void EnviarMail(List<string> receptores) { MailMessage mail = new MailMessage(); SmtpClient SmtpServer = new SmtpClient("smtp.gmail.com");
102 mail.From = new MailAddress("
[email protected]"); foreach (string rec in receptores) { mail.To.Add(rec); } mail.Subject = "Nueva solicitud de acceso de usuario"; mail.Body = "El usuario " + correoTxt.text + " solicita acceder a EnergyApp.\n" + "Por favor, accede a la aplicación para gestionar los accesos. El motivo que expone es: \n\n" + mensaje.text + "\n\nMensaje automático. No responder a este mensaje."; //System.Net.Mail.Attachment attachment; //attachment = new System.Net.Mail.Attachment("c:/textfile.txt"); //mail.Attachments.Add(attachment); SmtpServer.Port = 587; SmtpServer.Credentials = new System.Net.NetworkCredential("
[email protected]", "iticona15"); SmtpServer.EnableSsl = true; SmtpServer.Send(mail); } private bool compruebaPass(string pass) { bool res = false; if (pass.Length >= 8) { Debug.Log("RESTRICCIÓN 1 CORRECTA: La contraseña insertada tiene 8 o más caracteres."); foreach (char c in pass) { if (char.IsDigit(c)) { Debug.Log("RESTRICCIÓN 2 CORRECTA: La contraseña insertada contiene al menos un dígito."); res = true; } else { Debug.Log("RESTRICCIÓN 2 ERRÓNEA: La contraseña insertada no contiene dígitos."); textoError.text = "La contraseña debe tener al menos un dígito"; fondoError.gameObject.SetActive(true); } } } else { Debug.Log("RESTRICCIÓN 1 ERRÓNEA: La contraseña insertada tiene menos de 8 caracteres."); textoError.text = "La contraseña debe tener al menos 8 caracteres"; fondoError.gameObject.SetActive(true);
103 } return res; } private bool compruebaMotivo(string msg) { return msg.Length != 0; } public void Registrar() { string _log = "SELECT * FROM" + " alumnos WHERE correo LIKE '" + correoTxt.text + "'"; string _logAlumno = "INSERT INTO" + " alumnos (correo, password, rol, acceso) values ('" + correoTxt.text + "','" + passwordTxt.text + "','alumno','no')"; string _logProfesor = "INSERT INTO" + " alumnos (correo, password, rol, acceso) values ('" + correoTxt.text + "','" + passwordTxt.text + "','profesor','no')"; AdminMysql _adminMYSQL = GameObject.Find("AdministradorBaseDatos").GetComponent<AdminMysql>(); MySqlDataReader resultado = _adminMYSQL.Select(_log); MySqlDataReader res; if (resultado.HasRows) { Debug.Log("El usuario con correo " + correoTxt.text + " ya existe"); textoError.text = "Existe un usuario con esta dirección de correo. Inténtelo con otro diferente."; fondoError.gameObject.SetActive(true); resultado.Close(); } else { if (correoTxt.text.EndsWith("@gmail.com") || correoTxt.text.EndsWith("@hotmail.com") || correoTxt.text.EndsWith("@us.es") || correoTxt.text.EndsWith("@alum.us.es")) { if (passwordTxt.text != passwordTxt2.text) { Debug.Log("Las contraseñás no coinciden"); textoError.text = "Las contraseñás no coinciden"; fondoError.gameObject.SetActive(true); resultado.Close(); } else { if (compruebaPass(passwordTxt.text)) { if (compruebaMotivo(mensaje.text)) { Debug.Log("Se cumplen todas las restricciones para el registro."); if (checkProfesor.isOn) {
104 resultado.Close(); Debug.Log("Insertando profesor " + correoTxt.text + " en la Base de Datos."); res = _adminMYSQL.Insert(_logProfesor); res.Close(); } else { resultado.Close(); Debug.Log("Insertando alumno " + correoTxt.text + " en la Base de Datos."); res = _adminMYSQL.Insert(_logAlumno); res.Close(); } string _correosProfesores = "SELECT * FROM" + " alumnos WHERE rol LIKE 'profesor' AND acceso LIKE 'si'"; MySqlDataReader profs = _adminMYSQL.Select(_correosProfesores); List<string> correosProf = new List<string>(); while (profs.Read()) { string email = (string) profs["correo"]; if (email.EndsWith("@gmail.com") || email.EndsWith("@hotmail.com") || email.EndsWith("@us.es") || email.EndsWith("@alum.us.es")) { correosProf.Add(email); Debug.Log("Correo destino: " + email); } } //string[] profesores = new string[]{}; EnviarMail(correosProf); Debug.Log("Correo informativo enviado a los profesores."); UnityEngine.SceneManagement.SceneManager.LoadScene("EscenaRegistroCorrecto"); Debug.Log("Cambio de escena a EscenaRegistroCorrecto."); } else { Debug.Log("No está relleno el campo de texto 'Motivo'."); textoError.text = "Es obligatorio indicar un motivo"; fondoError.gameObject.SetActive(true); resultado.Close(); } } else { resultado.Close(); } }
105 } else { Debug.Log("El dominio de correo no es '@alum.us.es', '@us.es', '@gmail.com' ni '@hotmail.com'."); textoError.text = "Solo se permiten los siguientes correos de dominio: '@alum.us.es', '@us.es', '@gmail.com', '@hotmail.com'."; fondoError.gameObject.SetActive(true); resultado.Close(); } } } } ANEXO D: CÓDIGO DIRECTO.CS using System; using System.Collections; using System.Collections.Generic; using System.Net.Mail; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; public class Directo : MonoBehaviour { //Variables para la comunicación PHP public string getURL = "http://energyapp.eu5.org/obtenerDirecto.php"; //Variables para la interpretación en pantalla public Image alarmaTs; public Image alarmaP; public Image alarmaM; public Text acumulacionMax; public Text tecMed; public Text tscMed; public Text tstMed; public Text tAmb; public Text presionMed; public Text energiaGen; public Sprite verde; public Sprite rojo; public Text motoresTxt; /* void Start() { StartCoroutine(cUpdate());
112 { alarmaP.sprite = rojo; } if (alarmaMTxt=="0") { alarmaM.sprite = verde; } else { alarmaM.sprite = rojo; } } private string calcularHorasEntre(string horaSalida, string horaPuesta) { Debug.Log("Entrando en calcularHorasEntre"); DateTime hSalida=DateTime.Parse(horaSalida); DateTime hPuesta=DateTime.Parse(horaPuesta); TimeSpan result = hPuesta.Subtract(hSalida); int horaEntera=result.Hours; int minutosEntero = result.Minutes % 60; Debug.Log("HORA: "+horaEntera+ " MINUTOS: "+minutosEntero); string horas= Convert.ToString(result.TotalHours); // string[] cadena = horas.Split(','); //Debug.Log("cadena1 (minutos) son: "+cadena[1].Substring(0,2)); //double minutos = Double.Parse(cadena[1].Substring(0,2))/100 * 60; //string min = minutos.ToString().Substring(0,2); return horaEntera.ToString() + "h y " + minutosEntero.ToString() + "min"; } } ANEXO F: CÓDIGO LISTARUSUARIOS.CS using System.Collections.Generic; using MySql.Data.MySqlClient; using UnityEngine; using UnityEngine.UI; using Button = UnityEngine.UIElements.Button; public class ListarUsuarios : MonoBehaviour { private string datosConexion; private MySqlConnection conexion;
113 // Función que lista los usuarios pendientes de acceso private List<string> Listar() { string _log = "SELECT * FROM"+" alumnos WHERE acceso LIKE 'no'"; Debug.Log("QUERY: "+_log); MySqlCommand cmd = conexion.CreateCommand(); cmd.CommandText = _log; MySqlDataReader listado = cmd.ExecuteReader(); List<string> listadoUsuariosPendientes = new List<string>(); while (listado.Read()) { string correo = (string) listado["correo"]; listadoUsuariosPendientes.Add(correo); Debug.Log("Se añade el correo "+correo+" a la lista de usuarios sin acceso."); } listado.Close(); return listadoUsuariosPendientes; } private void ConectarConServidorBaseDatos() { conexion = new MySqlConnection(datosConexion); try { conexion.Open(); Debug.Log("Conexión con BD correcta!"); } catch(MySqlException error) { Debug.LogError("Imposible conectar con la Base de Datos: "+error); } } void Start() { datosConexion = "Server=remotemysql.com" + ";Database=JeJBFPR3Uy" + ";Uid=JeJBFPR3Uy" + ";Pwd=9CJzhSsyeh" + ";"; ConectarConServidorBaseDatos(); Debug.Log("Estamos en el START"); GameObject buttonTemplate = transform.GetChild(0).gameObject; GameObject g; List<string> usuariosPendientes = Listar(); for (int i = 0; i < usuariosPendientes.Count; i++) { g = Instantiate(buttonTemplate, transform); g.transform.GetChild(0).GetComponent<Text>().text = usuariosPendientes[i];
114 } Destroy(buttonTemplate); } } ANEXO G: CÓDIGO NETWORKMANAGER.CS using System.Collections; using System.Collections.Generic; using System.Net.Mail; using UnityEngine; using UnityEngine.UI; public class NetworkManager : MonoBehaviour { //Variables para la comunicación PHP public string postURL = "http://energyapp.eu5.org/crearUsuario.php"; public string getURL = "http://energyapp.eu5.org/loginUsuario.php"; public string getCorreo = "http://energyapp.eu5.org/existeUsuario.php"; public string getProfesoresURL = "http://energyapp.eu5.org/profesoresAcceso.php"; private string _correo = ""; private string _password = ""; private string _rol = ""; //Variables para la interpretación en pantalla public InputField correo; public InputField contraseña; public InputField contraseñaRepetida; public InputField motivo; public Text textoError; public Toggle checkProfesor; //Los botones llaman a las Coroutines public void Enviar() { StartCoroutine("SaveUser"); } public void Recibir() { StartCoroutine("LoadUser"); }
115 //Coroutines para la comunicación con la web y mostrar datos recogidos de la BD private IEnumerator LoadUser() { Debug.Log("Entro en LoadUser"); Debug.Log("Cogiendo pass desde la URL "+getURL); textoError.text = "Procesando..."; _correo = correo.text; //mostrar datos de entorno aquí string urlString = getURL + "?" + "correo=" + WWW.EscapeURL(_correo); WWW getCorreo = new WWW(urlString); //Esperamos hasta que haya una respuesta (por eso usamos Coroutines) yield return getCorreo; Debug.Log("La pass es en BD: "+getCorreo.text); Debug.Log("La pass escrita en la app es: "+contraseña.text); string[] cadenaDB = new string[3]; string passDB = ""; string rolDB = ""; string accesoDB = ""; if (getCorreo.text.Split().Length==3) { cadenaDB = getCorreo.text.Split(' '); passDB = cadenaDB.GetValue(1).ToString(); rolDB = cadenaDB.GetValue(0).ToString(); accesoDB = cadenaDB.GetValue(2).ToString(); if (contraseña.text==passDB) { if (accesoDB == "no") { textoError.text = "Este usuario se encuentra pendiente de validación de acceso"; } else { Debug.Log("La pass en BD es: "+passDB); Debug.Log("El rol en BD es: "+rolDB); Debug.Log("Entro en el if"); Debug.Log("Las contraseñas son iguales"); if (contraseña.text=="") { Debug.Log("La contraseña está vacía"); textoError.text = "Debe introducir una contraseña"; } else { Debug.Log("La contraseña no está vacía"); Debug.Log("El valor de la variable _log es: "+ _rol); if (rolDB=="profesor") { Debug.Log("PROFESOR"); UnityEngine.SceneManagement.SceneManager.LoadScene("EscenaBienvenidaProfesor" ); } else
116 { Debug.Log("ALUMNO"); UnityEngine.SceneManagement.SceneManager.LoadScene("EscenaBienvenida"); } } } } else { Debug.Log("Las contraseñas son distintas o no encuentra correo"); textoError.text = "Correo y/o contraseña incorrectos"; } } else { textoError.text = "Correo y/o contraseña incorrectos"; } } public void EnviarMail(List<string> receptores) { MailMessage mail = new MailMessage(); SmtpClient SmtpServer = new SmtpClient("smtp.gmail.com"); mail.From = new MailAddress("
[email protected]"); foreach (string rec in receptores) { mail.To.Add(rec); } mail.Subject = "EnergyApp: Nueva solicitud de acceso de usuario"; mail.Body = "El usuario " + correo.text + " solicita acceder a EnergyApp.\n" + "Por favor, accede a la aplicación para gestionar los accesos. El motivo que expone es: \n\n" + motivo.text + "\n\nMensaje automático. No responder a este mensaje."; //System.Net.Mail.Attachment attachment; //attachment = new System.Net.Mail.Attachment("c:/textfile.txt"); //mail.Attachments.Add(attachment); SmtpServer.Port = 587; SmtpServer.Credentials = new System.Net.NetworkCredential("
[email protected]", "iticona15"); SmtpServer.EnableSsl = true; SmtpServer.Send(mail);
117 } private bool correoCorrecto(string correo) { bool res = false; if (correo.EndsWith("@gmail.com") || correo.EndsWith("@alum.us.es") || correo.EndsWith("@us.es") || correo.EndsWith("hotmail.com")) { if (!correo.StartsWith("@")) { res = true; } else { textoError.text = "Introduzca un correo válido"; } } else { textoError.text="Los dominios válidos son '@alum.us.es', '@us.es', 'gmail.com' y 'hotmail.com'"; } return res; } //Coroutine para comunicarse con la BD e introducir los datos que se envian desde Unity //Lo único que hace Unity desde aquí es enviar los datos a la página web private IEnumerator SaveUser() { //Debug.Log("Entro en SaveUser"); textoError.text = "Procesando..."; _correo = correo.text; Debug.Log("_correo es LO SIGUIENTE: " + _correo); string url=getCorreo + "?" + "correo=" + WWW.EscapeURL(_correo); Debug.Log("Enviando URL NUEVA: "+url); WWW usuarioExiste = new WWW(url); yield return usuarioExiste; Debug.Log("usuarioExiste.text devuelve: "+usuarioExiste.text); if (usuarioExiste.text != "") { textoError.text = "El usuario con el correo introducido ya existe"; } else { if (correoCorrecto(correo.text)) { if (contraseña.text.Length>=8 && !contraseña.text.Contains(" ")) { if (contraseña.text == contraseñaRepetida.text) { //Debug.Log("Las contraseñas coinciden"); _correo = correo.text; _password = contraseña.text; if (checkProfesor.isOn) {
118 _rol = "profesor"; } else { _rol = "alumno"; } string urlString = postURL + "?" + "correo=" + WWW.EscapeURL(_correo) + "&" + "password=" + WWW.EscapeURL(_password) + "&" + "rol=" + WWW.EscapeURL(_rol); //Debugpara verde donde viene la data Debug.Log("Enviando: "+urlString); // pasamos la data al servidor WWW postUser = new WWW(urlString); yield return postUser; //INICIO CODIGO ANTIGUO WWW getProfesoresActivos = new WWW(getProfesoresURL); yield return getProfesoresActivos; string[] arrayCorreos = getProfesoresActivos.text.Split(' '); List<string> correosProf = new List<string>(); foreach (string s in arrayCorreos) { if (s.EndsWith("@gmail.com") || s.EndsWith("@hotmail.com") || s.EndsWith("@us.es") || s.EndsWith("@alum.us.es")) { correosProf.Add(s); //Debug.Log("Correo destino: " + s); } } EnviarMail(correosProf); //Debug.Log("Correo informativo enviado a los profesores."); /* List<string> correosProf = new List<string>(); while (correosProfesores.Read()) { string email = (string) profs["correo"]; if (email.EndsWith("@gmail.com") || email.EndsWith("@hotmail.com") || email.EndsWith("@us.es") ||
119 email.EndsWith("@alum.us.es")) { correosProf.Add(email); Debug.Log("Correo destino: " + email); } } //string[] profesores = new string[]{}; EnviarMail(correosProf); Debug.Log("Correo informativo enviado a los profesores."); UnityEngine.SceneManagement.SceneManager.LoadScene("EscenaRegistroCorrecto"); Debug.Log("Cambio de escena a EscenaRegistroCorrecto.");*/ //FIN CODIGO ANTIGUO UnityEngine.SceneManagement.SceneManager.LoadScene("EscenaRegistroCorrecto"); } else { textoError.text = "Las contraseñas no coinciden"; } } else { textoError.text = "La contraseña debe contener al menos 8 carcateres. Los espacios no están permitidos"; } } } } } ANEXO H: CÓDIGO BOTON.CS using System; using System.Collections.Generic; using System.Net.Mail; using MySql.Data.MySqlClient; using UnityEngine; using UnityEngine.UI;
120 public class Boton : MonoBehaviour { public void EnviarMail(string correo) { Debug.Log("SE VA A ENVIAR UN CORREO A: "+correo); MailMessage mail = new MailMessage(); SmtpClient SmtpServer = new SmtpClient("smtp.gmail.com"); mail.From = new MailAddress("
[email protected]"); mail.To.Add(correo); mail.Subject = "EnergyApp: Solicitud de acceso aceptada"; mail.Body = "El usuario " + correo + " ha sido aceptado.\n" + "Por favor, comprueba el acceso en la aplicación." + "\n\nMensaje automático. No responder a este mensaje."; //System.Net.Mail.Attachment attachment; //attachment = new System.Net.Mail.Attachment("c:/textfile.txt"); //mail.Attachments.Add(attachment); SmtpServer.Port = 587; SmtpServer.Credentials = new System.Net.NetworkCredential("
[email protected]", "iticona15"); SmtpServer.EnableSsl = true; SmtpServer.Send(mail); } public void AceptarUsuario() { GameObject corr = transform.GetChild(0).gameObject; string correo = corr.GetComponent<Text>().text; Debug.Log("Has seleccionado aceptar a "+correo); string _logAceptar = "UPDATE alumnos" + " SET acceso='si' WHERE correo='" + correo+"'"; AdminMysql _adminMYSQL = GameObject.Find("AdministradorBaseDatos").GetComponent<AdminMysql>(); MySqlDataReader resultado = _adminMYSQL.Select(_logAceptar); EnviarMail(correo); resultado.Close(); UnityEngine.SceneManagement.SceneManager.LoadScene("EscenaAdministracion"); } } ANEXO I: CÓDIGO ADMINMYSQL.CS
121 using MySql.Data.MySqlClient; using UnityEngine; public class AdminMysql : MonoBehaviour { public string servidorBaseDatos; public string nombreBaseDatos; public string usuarioBaseDatos; public string contraseñaBaseDatos; private string datosConexion; private MySqlConnection conexion; // Start is called before the first frame update void Start() { datosConexion = "Server=" + servidorBaseDatos + ";Database="+nombreBaseDatos + ";Uid=" + usuarioBaseDatos + ";Pwd=" + contraseñaBaseDatos + ";"; ConectarConServidorBaseDatos(); } private void ConectarConServidorBaseDatos() { conexion = new MySqlConnection(datosConexion); try { conexion.Open(); Debug.Log("Conexión con BD correcta!"); } catch(MySqlException error) { Debug.LogError("Imposible conectar con la Base de Datos: "+error); } } public MySqlDataReader Select(string _select) { MySqlCommand cmd = conexion.CreateCommand(); Debug.Log("conexion.CreateCommand()..."); cmd.CommandText = _select; Debug.Log("cmd.CommandText = _select;..."); MySqlDataReader resultado = cmd.ExecuteReader(); Debug.Log("cmd.ExecuteReader()..."); return resultado; } public MySqlDataReader Insert(string _select) { MySqlCommand cmd = conexion.CreateCommand(); cmd.CommandText = _select; MySqlDataReader res = cmd.ExecuteReader(); return res;