UNIVERSIDAD NACIONAL DE EDUCACIÓN A DISTANCIA DEPARTAMENTO: Ingeniería Eléctrica, Electrónica y de Control TÍTULO: Rediseño del sistema de monitorización de energías renovables: acceso, estandarización y seguridad AUTOR: José María Estepa Martínez DIRECTOR: Dr. Manuel Alonso Castro Gil CODIRECTOR: PONENTE: ESCUELA TÉCNICA SUPERIOR DE INGENIEROS INDUSTRIALES TÍTULO DEL PROYECTO: Rediseño del sistema de monitorización de energías renovables: acceso, estandarización y seguridad. (A rellenar por el Tribunal Calificador) TRIBUNAL CALIFICADOR PRESIDENTE: _________________________________________________________________ _________________________________________________________________ VOCAL : _________________________________________________________________ _________________________________________________________________ SECRETARIO: _________________________________________________________________ _________________________________________________________________ FECHA DEFENSA _____ de _________________ de _______ CALIFICACIÓN _________________________________________________________ Vocal Presidente Secretario Fdo.:_________________ Fdo.:_________________ CÓDIGOS UNESCO: Fdo.:_________________ J.M.Estepa Índice LISTA DE SÍMBOLOS ..........................................................................................................iii LISTA DE FIGURAS .............................................................................................................. v CONTENIDOS DEL PROYECTO 1. Introducción ................................................................................................................ 1 2. Elementos de la instalación de energías renovables 2.1. Estación fotovoltaica y software de gestión 2.1.1. Descripción de la instalación ........................................................ 3 2.1.2. El inversor Sunny Boy 1100E....................................................... 4 2.1.3. El controlador Sunny Boy Control................................................ 8 2.1.4. El software Sunny Data Control ................................................. 10 2.2. Estación meteorológica y software de gestión 2.2.1. El sistema de adquisición de datos (SAD) .................................. 14 2.2.2. El software Teletrans W3K......................................................... 17 2.3. Equipamiento informático 2.3.1. El ordenador meteo.ieec.uned.es................................................. 18 2.3.2. Acceso remoto a meteo.ieec.uned.es .......................................... 19 3. Auditoría del sistema actual...................................................................................... 21 3.1. Estado actual 3.1.1. Estación meteorológica ............................................................... 21 3.1.2. Estación fotovoltaica................................................................... 21 3.2. Propuesta de implantación ......................................................................... 22 4. Nuevo sistema de monitorización............................................................................. 23 4.1. Hardware 4.1.1. Estación fotovoltaica................................................................... 25 4.1.2. Ordenador conectado a la estación fotovoltaica.......................... 25 4.1.3. Estación meteorológica ............................................................... 26 4.1.4. Servidor de servlets ..................................................................... 26 4.1.5. Equipos cliente ............................................................................ 26 4.2. Software 4.2.1. Task o programador de tareas ..................................................... 27 4.2.2. Instalador de servicios en Windows............................................ 28 4.2.3. Sunny Data Control (SDC) ......................................................... 30 4.2.4. Sunny Data Control Agent (SDCAgent)..................................... 31 4.2.5. Teletrans W3K ............................................................................ 32 4.2.6. Servidor de servlets Tomcat........................................................ 33 4.2.7. PFC_JMEstepa............................................................................ 34 4.2.8. Máquina Virtual de Java ............................................................. 35 4.3. Rutinas del nuevo sistema.......................................................................... 36 4.3.1. Menú principal ............................................................................ 38 4.3.2. Fotovoltaica-Gráfico en tiempo real ........................................... 40 4.3.3. Fotovoltaica-Valores en tiempo real ........................................... 41 4.3.4. Fotovoltaica-Datos históricos ..................................................... 42 -i- Proyecto Final de Carrera 4.3.5. Fotovoltaica-Fotos....................................................................... 46 4.3.6. Meteorológica-Datos históricos .................................................. 47 4.3.7. Meteorológica-Fotos ................................................................... 51 4.3.8. Documentos................................................................................. 52 BIBLIOGRAFÍA ............................................................................................................... 53 APÉNDICES I. Contenido del CD-ROM............................................................................................ 55 II. El estándar de representación de datos meteorológicos BUFR................................ 59 II.I. Estructuras de clave ................................................................................... 60 II.II. Tablas BUFR ............................................................................................ 61 II.III. Unidades .................................................................................................. 62 II.IV. Escala ...................................................................................................... 63 II.V. Valor de referencia ................................................................................... 64 II.VI. Anchura de datos..................................................................................... 65 II.VII. Descripción general de un mensaje BUFR ............................................ 66 III. Código fuente de las rutinas de la aplicación.......................................................... 71 III.I. index.htm .................................................................................................. 71 III.II. titulo.htm ................................................................................................. 72 III.III. menu\menu.htm...................................................................................... 73 III.IV. portada.jsp.............................................................................................. 79 III.V. DescargaBufr.class.................................................................................. 81 III.VI. fv\applet_texto.htm ................................................................................ 87 III.VII. fv\applet_grafico.jsp............................................................................. 88 III.VIII. fv\historico_coge.jsp ........................................................................... 90 III.IX. historico_actua.class .............................................................................. 92 III.X. fv\fotos\camarafotos.htm ...................................................................... 100 III.XI. meteo\fotos\camarafotos.class ............................................................. 101 III.XII. meteo\historico_coge.jsp .................................................................... 103 III.XIII. historico_meteo.class ........................................................................ 105 III.XIV. meteo\graficoXY.class...................................................................... 111 III.XV. meteo\fotos\camarafotos.htm ............................................................. 113 III.XVI. BaseDatos.class................................................................................. 114 III.XVII. Bufr.class ......................................................................................... 117 III.XVIII. EscritorExcel.class ......................................................................... 122 III.XIX. LectorExcel.class .............................................................................. 123 III.XX. LeeMeteoActual.class ........................................................................ 125 IV. Instalación de servicios en Windows.................................................................... 127 V. Proceso de instalación de la aplicación.................................................................. 129 CURRÍCULUM DEL AUTOR ........................................................................................... 131 -ii- J.M.Estepa LISTA DE SÍMBOLOS AWT API ASCII BIFF BUFR DC DNS ENS ETSII FTP FV HTML HTTP IGBT JAR JDK JRE JVM LED MPP PE SB SBC SDC TCP/IP UNED URL VDEW XML Abstract Windows Toolkit. Kit de Herramientas para Ventanas de Java. Interfaz de Programación de Aplicaciones. Código Estándar Americano para el Intercambio de Información. Formato de Archivo de Intercambio Binario. Binary Universal Form for the Representation of meteorological data. Formato de datos binario mantenido por la World Meteorological Organization. Corriente Continua. Sistema de Nombres de Dominios. Instalación Automática de Desconexión. Escuela Técnica Superior de Ingenieros Industriales. Protocolo de Transferencia de Archivos. Fotovoltaico(a). Lenguaje de Marcas de Hipertexto. Protocolo de Transferencia de Hipertexto. Transistor Bipolar de Puerta Aislada. Archivo comprimido y ejecutable Java. Java Developpement Kit. Kit de desarrollo de aplicaciones en Java. Entorno de Ejecución de Java. Máquina Virtual Java. Diodo Emisor de Luz. Punto de Máxima Potencia. Potencial de Tierra. Sunny Boy. Sunny Boy Control. Sunny Data Control. Protocolo de Control de Transmisión/Protocolo de Internet. Universidad Nacional de Educación a Distancia. Localizador de Recursos Uniforme. Asociación de Centrales Eléctricas Alemanas. Lenguaje de Marcas Extensible. -iii- Proyecto Final de Carrera -iv- J.M.Estepa LISTA DE FIGURAS Fig. 1. Módulos fotovoltaicos..................................................................................................... 3 Fig. 2. El inversor Sunny Boy 1100E......................................................................................... 4 Fig. 3. El controlador Sunny Boy Control.................................................................................. 8 Fig. 4. Software Sunny Data Control ....................................................................................... 10 Fig. 5. Geonica 3000 ............................................................................................................... 14 Fig. 6. Diversos sensores de la UNED .................................................................................... 16 Fig. 7. Software TeleTrans W3K ............................................................................................ 17 Fig. 8. Acceso remoto al ordenador meteo.ieec.uned.es ......................................................... 19 Fig. 9. Ejecución de aplicaciones en meteo para la instalación fotovoltaica ........................... 21 Fig. 10. Esquema del nuevo sistema de monitorización: hardware ........................................ 23 Fig. 11. Esquema del nuevo sistema de monitorización: flujo de información ...................... 24 Fig. 12. Estación fotovoltaica y ordenador conectado a ella ................................................... 25 Fig. 13. Estación meteorológica .............................................................................................. 26 Fig. 14. Servidor de “servlets” ................................................................................................. 26 Fig. 15. Configuración del programa instalador de servicios en Windows ............................. 28 Fig. 16. Estructura de archivos del proyecto ........................................................................... 37 Fig. 17. Pantalla del menú principal ........................................................................................ 38 Fig. 18. Pantalla informativa del formato BUFR .................................................................... 39 Fig. 19. Descarga en formato BUFR ....................................................................................... 39 Fig. 20. Pantalla de la opción Fotovoltaica-Gráfico en tiempo real ........................................ 40 Fig. 21. Pantalla de la opción Fotovoltaica-Valores en tiempo real ........................................ 41 Fig. 22. Pantalla de la opción Fotovoltaica-Datos históricos .................................................. 42 Fig. 23. Opción Visualización magnitud seleccionada ............................................................ 43 Fig. 24. Opción Visualización de gráfico resumen ................................................................. 43 Fig. 25. Opción Visualización de todos los datos .................................................................... 44 Fig. 26. Descarga en formato EXCEL ..................................................................................... 44 Fig. 27. Pantalla de la opción Fotovoltaica-Fotos ................................................................... 46 Fig. 28. Pantalla de la opción Meteorológica-Datos históricos ............................................... 47 Fig. 29. Opción “Ver todos los datos recogidos” .................................................................... 48 Fig. 30. Descarga en formato EXCEL ..................................................................................... 48 Fig. 31. Gráficos meteorológicos ............................................................................................ 49 Fig. 32. Opción Resumen diario .............................................................................................. 49 Fig. 33. Gráficos de valores meteorológicos ........................................................................... 50 Fig. 34. Opción Resumen del período ..................................................................................... 50 Fig. 35. Pantalla de la opción Meteorológica-Fotos ................................................................ 51 Fig. 36. Pantalla de la opción Documentos ............................................................................. 52 Fig. 37. Contenido del CD-ROM ............................................................................................. 55 Fig. 38. Carpetas del proyecto PFC_JMEstepa ........................................................................ 57 -v- Proyecto Final de Carrera -vi- J.M.Estepa CONTENIDOS DEL PROYECTO 1. Introducción La Escuela Técnica Superior de Ingeniería Industrial (ETSII) de la UNED, dispone de dos instalaciones relacionadas con las energías renovables: una estación fotovoltaica y una estación meteorológica instaladas en la azotea del edificio de la Escuela en la Ciudad Universitaria de Madrid. Ambas se encuentran conectadas a un ordenador del Departamento de Ingeniería Eléctrica, Electrónica y de Control, de forma que los datos recogidos en las mismas pueden ser monitorizados a través de programas de gestión suministrados por las empresas suministradoras de ambas estaciones. La necesidad de explotar la información recogida, hizo que en 2006, José Alberto Sánchez Sánchez, dirigido por el Dr. Manuel Alonso Castro Gil, realizara el Proyecto Final de Carrera titulado “Sistema Web de visualización y gestión de sistema fotovoltaico”, accesible desde la siguiente dirección de Internet: http://meteo.ieec.uned.es/www_Usumeteo4/TiempoReal.html Esta aplicación utiliza principalmente los applets de java suministrados con el programa de control de la estación fotovoltaica, de forma que se puede visualizar desde cualquier ordenador conectado a Internet los valores instantáneos de la planta y, además puede visualizar el contenido de los ficheros de datos anuales, mensuales y diarios generados. Una vez analizado el funcionamiento de esta aplicación, se detectaron varios problemas, que pueden resumirse en: • Necesidad de que el ordenador del departamento conectado a la estación fotovoltaica tuviera permanentemente abierta la sesión correspondiente al administrador del sistema para ejecutar varios programas necesarios para el funcionamiento de la aplicación, lo que lleva a dejar el equipo “cautivo” de la aplicación (no se puede cerrar la sesión del administrador, se debe tener la precaución de no cerrar los programas,…). • Pérdida de datos en el caso de que el ordenador, por cualquier circunstancia, quede apagado durante un periodo de tiempo superior a un día. • Uso de formato de datos propio a la aplicación, sin posibilidad de exportación de datos a formatos estándar. • Imposibilidad de migrar la aplicación a equipos servidores con distintos sistemas operativos. • No establecimiento de políticas de seguridad en el acceso. • No establecimiento de políticas de copias de respaldo. • No acceso a los datos de la planta meteorológica. -1- Proyecto Final de Carrera Por tanto, se decidió rediseñar el sistema de monitorización de energías renovables con los siguientes objetivos: • Acceso a los datos recogidos por las estaciones fotovoltaica y meteorológica de la ETSII de la UNED desde Internet a través de páginas Web. • Estandarización en la descarga de datos, entregándolos en formatos fácilmente manejables. • Seguridad en el acceso a los datos. • Posibilidad de migración de la aplicación a otras plataformas como servidores específicos de la UNED con otros sistemas operativos. • Descargar al ordenador del Departamento conectado con las estaciones de la responsabilidad de la gestión permanente de las mismas. • Organizar y diseñar las aplicaciones basando su ejecución en “servicios” independientes de los usuarios y las aplicaciones existentes y no en la ejecución de programas por un determinado usuario. -2- J.M.Estepa 2. Elementos de la instalación de energías renovables 2.1. La estación fotovoltaica y su software de gestión 2.1.1. Descripción de la instalación El equipo está formado por siete módulos fotovoltaicos (los generadores solares) en serie y un ondulador de secuencias o inversor, del tipo Sunny Boy 1100E, una marca registrada de SMA Regelsysteme GmbH. La corriente continua producida por los generadores solares es convertida por el inversor en corriente alterna que se introduce directamente en la red eléctrica. El Sunny Boy cumple con todas las normas de la Asociación de Centrales Eléctricas Alemanas (VDEW) para la “Marcha en Paralelo de Instalaciones de Producción Autónoma” con la red de baja tensión de las compañías eléctricas. También tiene el certificado CE (Comunidad Europea) por cumplir las normas europeas armonizadas referentes a la compatibilidad electromagnética y la normativa de redes de baja tensión. El control de la instalación se realiza con dos componentes adicionales, que se explicarán con detalle posteriormente: • Controlador Sunny Boy Control (SBC) • Un PC con el programa de Windows: Sunny Data Control (SDC). Estos elementos permiten la monitorización y el registro continuo de los datos de trabajo de los inversores conectados, la vigilancia de su estado de trabajo y aviso de fallos de operación, la representación gráfica de los datos registrados y la modificación de los parámetros de trabajo del inversor para optimizar la instalación completa. Fig. 1. Módulos fotovoltaicos -3- Proyecto Final de Carrera 2.1.2. El inversor Sunny Boy 1100E El inversor se caracteriza por una construcción sencilla y robusta con un alto grado de rendimiento. La tensión continua fotovoltaica se traslada por un montaje de puente IGBT (Insulated Gate Bipolar Transistor o Transistor Bipolar de Puerta Aislada) de alta frecuencia (16 kHz) a un circuito intermedio de corriente alterna. Desde allí se efectúa la alimentación directa a la red por un transformador toroidal de baja pérdida. El rango de tensión de entrada FV del Sunny Boy está dimensionado según configuración de la instalación hasta para 16 módulos fotovoltaicos estándar. La regulación de la corriente, alimentada por un ordenador de un chip, garantiza la forma sinusoidal de la curva con coeficiente mínimo de distorsión no lineal. El control de marcha garantiza la marcha completamente automática y la búsqueda y seguimiento del punto de trabajo de rendimiento máximo (MPP, Maximum Power Point o Punto de Máxima Potencia), evitándose pérdidas innecesarias en reserva y en marcha de alimentación. Fig. 2. El inversor Sunny Boy 1100E Las magnitudes de entrada del Sunny Boy son las siguientes: • Tensión máxima de entrada sin carga (VPV0): 400 V DC. No debe sobrepasar la tensión máxima DC especificada de entrada. La tensión sin carga del generador solar depende de la temperatura de sus células y de la irradiación solar. La mayor tensión sin carga del generador solar se da a la temperatura más baja de las células. Por eso, al planificar una instalación FV, se debe tener en cuenta la temperatura ambiente más baja posible. A partir de esta temperatura se puede indicar la tensión máxima sin carga del generador solar, si se conocen los módulos FV utilizados. • Tensión mínima rango MPP (VMPPmin): 139 V DC. Entre la VMPPmin con la que el inversor carga el generador solar y la tensión de red (UAC) existe una relación fija. En dependencia de la tensión momentánea de la red se determina la correspondiente tensión mínima DC. Gracias a esta ventana de tensión MPP, se aprovechan las propiedades específicas del equipo óptimamente y se aumenta el rendimiento de energía. Para una UAC = 230 voltios resulta según la gráfica una VMPPmin de 139 voltios. La tensión MPP de la secuencia conectada no debe pasar a +70 ºC por debajo del rango de tensión de entrada de cada caso (VMPP +70 ºC > rango mínimo de tensión de entrada). • Tensión de entrada rango MPP (VPV): 139 V – 400 V DC. -4- J.M.Estepa • Corriente máxima de entrada (IPV max): 10,0 A. • Potencia máxima de entrada (PPV): 1.210 W. • Potencia máxima recomendada del generador: 1.500 W. • Instalación de corte de todos los polos en el lado de entrada DC: Conectores de inserción MC (Multi-Contact). • Tensión de rizado (USS) < 10%. • Protección de personas mediante control de contacto a tierra (Riso > 1 MΩ). • Protección de sobretensión mediante varistores de control térmico. • Protección contra polarización inversa mediante diodos de cortocircuito. Y las de salida (conexión a la red): • Potencia nominal de salida (PACnom): 1.000 W. • Potencia punta de salida (PACmax): 1.100 W. • Resistencia al cortocircuito: de red por regulación de corriente. • Rango de trabajo de la tensión de red (UAC): 198 – 251 V AC. • Rango de trabajo de la frecuencia de red (fAC): 49,8 – 50,2 Hz. • Instalación de corte de todos los polos en el lado de la red: Instalación automática de desconexión (ENS), doble. • Ángulo de desfase (ϕ) referido a onda fundamental de la corriente: 0º. • Rendimiento máximo (ηmax): ≥ 93%. • Consumo de potencia en marcha < 4 W. En marcha nocturna < 0,1 W. • Rango de temperatura ambiente permitido: -25 ºC a +60 ºC. • Humedad relativa permitida: del 0% al 100% (clase 3K6). La transferencia de datos entre el Sunny Boy y el PC o el SBC se puede efectuar sencillamente por la línea existente de conexión de la red, o bien por una línea separada de datos RS232 o RS485. En el primer caso el trabajo de instalación se reduce al mínimo. En el inversor tiene que haber instalado un módem de línea de fuerza (Powerline-Modem) para la transferencia de datos. En caso de que se conecte a un PC, se necesita un módem de inserción (SWR-COM). En el SBC este módem está integrado. Tanto el PC como el SBC pueden colocarse en cualquier lugar de la red doméstica, porque sacan los datos del enchufe. La transferencia de datos por la línea de red es fiable y económica. La condición para la marcha sin problemas es que los Sunny Boys y el módem de inserción del PC o el SBC estén conectados a la misma fase de la red doméstica. En la instalación de la ETSII el enchufe de red de 230 voltios del SBC se mete en el enchufe de la red de distribución doméstica, y el PC está conectado al SBC por una conexión RS232. La interface entre estos equipos se explicará en detalle posteriormente. -5- Proyecto Final de Carrera En el diseño del Sunny Boy se ha puesto atención en mantener el consumo propio lo más bajo posible. El inversor necesita 4 W de potencia propia como máximo, que extrae del generador solar. El refrigerador del inversor sirve para dar salida a la potencia perdida que se produce siempre al conectar semiconductores de potencia. El Sunny Boy dispone de un control integrado de temperatura del refrigerador. Una temperatura del refrigerador demasiado alta (por ejemplo, como consecuencia de la alta temperatura ambiente) es reconocida por el control de marcha, y esto sólo reduce correspondientemente la potencia de alimentación de modo que el inversor permanezca en la marcha de alimentación. El control de marcha del inversor se encarga adicionalmente de las tareas de comunicación con los componentes del equipo de análisis de datos (SBC y SDC). Así, el inversor se puede utilizar no sólo como un aparato individual de funcionamiento independiente, como es el que caso que nos ocupa, sino como parte de una instalación FV grande, cuya marcha se monitoriza y evalúa de forma central. Por último señalar, en cuanto a las características estructurales, que el inversor tiene una carcasa de acero inoxidable hermética al polvo y protegida contra chorros de agua (tipo de protección IP65). Este tipo de protección permite el montaje en casi cualquier lugar con temperatura ambiente entre –25 ºC y +60 ºC. En principio, el inversor funciona de manera completamente automática y libre de mantenimiento. Así, por ejemplo, el aparato se apaga completamente cuando es imposible la alimentación solar a la red (por la noche). Al empezar la irradiación solar al día siguiente, el Sunny Boy se pone automáticamente en marcha e introduce, en caso de irradiación suficientemente alta, energía eléctrica en la red. En caso de irradiación insuficiente, el aparato pasa a estado de espera y está así dispuesto para la alimentación a la red en cualquier momento. En cada primer encendido diario, el inversor realiza una serie de autotests y tests de seguridad prescritos. Su estado de trabajo se indica por medio de tres LEDs integrados en la carcasa del aparato: • El LED verde (“Marcha”) informa sobre el estado actual de trabajo. • El LED rojo (“Contacto a tierra”) avisa si se produce un contacto a tierra del generador FV o una avería de la protección de sobretensión. • El LED amarillo (“Avería”) indica un fallo o avería interno (fallo de la instalación automática de desconexión o ENS) o externo (fallo de la red), que impide en ese momento continuar con la marcha de alimentación. El Sunny Boy solo debe utilizarse en funcionamiento paralelo a la red. Para la desconexión segura en caso de separación de la red y para evitar la marcha aislada, el inversor está equipado de fábrica con un punto de desconexión automático. Este punto de desconexión de funcionamiento automático está equipado por razones de máxima seguridad con dos Instalaciones de Vigilancia de la red con órgano de conmutación respectivamente adjudicado (ENS) en serie. Cada una de estas instalaciones (ENS) controla permanentemente la calidad de la red conectada por control de la tensión, frecuencia e impedancia. La construcción redundante y un autotest automático antes de cada conexión a la red aseguran la fiabilidad de funciones. Los criterios que conducen a la separación de la red del Sunny Boy son los siguientes: -6- J.M.Estepa o Impedancia de la red (ZAC). Si supera en el momento de conexión a la red un valor de 1,25 Ω no se inicia la marcha de alimentación. Si varía bruscamente en un valor determinado (∆ZAC ≥ 0,5 Ω) o supera un valor máximo (ZAC ≥ 1,75 Ω) durante la alimentación a la red, el inversor es desconectado en 5 segundos. o Tensión de la red (UAC). Puede variar en un rango de –15% a +10% de la tensión nominal de la red. Si se supera o se pasa por debajo de este rango permitido, el inversor es desconectado de la red en 0,2 segundos. o Frecuencia de la red (fAC). Puede variar en un rango de ± 0,2 Hz de la frecuencia nominal de la red a una tensión de la red de –30% a +15%. Si se supera o se pasa por debajo de este rango máximo permitido, el Sunny Boy es desconectado en 0,2 segundos. Si varía bruscamente en un valor determinado durante la alimentación a la red, también es desconectado en 0,2 segundos. El bloqueo permanente de la marcha por alguna de estas causas se identifica por el encendido de un LED en la tapa de la carcasa del inversor. Para conseguir la máxima seguridad contra una tensión de contacto peligrosa en la instalación FV, ni la línea positiva ni la negativa están conectadas con el potencial de tierra (PE), debido a la separación galvánica (transformador), es decir, en situación normal no se da ningún potencial eléctrico peligroso entre la línea positiva y el potencial de tierra o entre la línea negativa y el potencial de tierra. El valor de la resistencia eléctrica entre las conexiones positiva y negativa y el potencial de tierra son vigilados permanentemente por el Sunny Boy. Al pasar por debajo de un valor de resistencia de 1 MΩ se enciende el LED rojo como aviso. -7- Proyecto Final de Carrera 2.1.3. El controlador Sunny Boy Control (SBC) El SBC trabaja como unidad central de registro de datos de medición y diagnóstico hasta para 50 inversores, apoya la puesta en marcha de la instalación FV, y ofrece la posibilidad de telediagnóstico por fax y módem. Por el contrario, el número de modelos de inversor diferentes está restringido a cuatro. La capacidad de almacenamiento para los datos adquiridos depende del número de inversores y de su configuración. El volumen de almacenamiento es dimensionado para poder guardar los valores diarios de energía de cada inversor simple durante al menos un año. La memoria restante es usada para el almacenamiento de los canales de medición. Según el número de canales de medición seleccionados y el intervalo de medición definido, resulta una capacidad de almacenamiento diferente de los datos medidos (número de días hasta que los valores más antiguos son sobrescritos). Fig. 3. El controlador Sunny Boy Control Los canales de medición son los canales que se seleccionan para registrar sus datos en la memoria del sistema. Cualquier canal que un inversor Sunny Boy pueda medir se puede definir como un canal de medición. Para operar con la mayor profundidad de almacenamiento posible, el registro de datos se debe limitar a una selección de canales. Los canales de medición se almacenarán como el valor promedio de los valores en los intervalos de medición definidos. Por ejemplo, si se selecciona un canal y se define que el intervalo de medición sea 15 minutos, esto significa que todos los valores puntuales de ese canal se usarán para calcular el valor promedio de esos 15 minutos, y ese promedio y el tiempo correspondiente se registrarán en la memoria del sistema. Los canales de medición disponibles del Sunny Boy son los siguientes: 1. Vpv: Tensión de entrada FV. 2. Vpv-Setpoint: Tensión nominal FV del regulador Vpv interno. 3. Iac: Corriente de red. 4. Vac: Tensión de red. 5. Fac: Frecuencia de red. 6. Pac: Potencia suministrada a la red. 7. Zac: Impedancia de la red. 8. Riso: Resistencia de aislamiento. 9. Ipv: Corriente del generador FV. 10. E-Total: Suma total de la energía alimentada. H-Total: Suma total de las horas de trabajo en marcha de alimentación. 11. 12. Power On: Suma total de las conexiones a la red. 13. Serial Number: Número de serie del Sunny Boy. 14. Mode: Visualización del estado actual de trabajo. 15. Error: Visualización del tipo de fallo en estado de fallo. -8- J.M.Estepa Cada registro de datos está sujeto a más o menos errores. Los valores de medición registrados por el inversor son necesarios para la dirección de marcha y para la regulación de la corriente alimentada. La reproducibilidad de los valores de medición está adaptada a estas funciones. El error máximo del registro de datos a una temperatura ambiente de 25 ºC se encuentra en un rango entre el 0,1% y el 4%. A otras temperaturas ambiente se debe tener en cuenta un coeficiente de error por temperatura. Está implementada una función especial para el técnico de instalación, de modo que pueda adaptar los parámetros de sistema para optimizar la instalación FV. La transmisión de datos del SBC se realiza con una frecuencia de 132,45 kHz. Las instalaciones de electricidad en edificios suministran energía a los dispositivos eléctricos con 230 V / 50 Hz. Este sistema de distribución de electricidad no está optimizado para la transmisión de señales de alta frecuencia. Por ello, la comunicación libre de interferencias en este rango de frecuencias depende esencialmente de la selección de la línea de transmisión entre los inversores y el SBC. El enlace de transmisión debería usar sólo una fase y ser tan corto como sea posible. Hay que procurar conectar todos los dispositivos que transmiten y reciben datos a una fase o, preferiblemente, incluso a la misma línea. Por tanto, se debe elegir un enchufe que esté instalado en la misma línea o, al menos, en la misma fase que el inversor. Además el enchufe debe estar tan cerca como sea posible de su punto de alimentación. Por otra parte, si otros consumidores también usan esta frecuencia, la transmisión puede ser interrumpida cuando se supera cierto nivel. Señales de interferencia se pueden producir por dispositivos eléctricos en el mismo edificio o en edificios vecinos. Una transmisión aceptable en estos casos depende del aislamiento o eliminación de la fuente de interferencia. Otros sistemas de comunicación que también usan esta frecuencia (por ejemplo un interfono, vigilante de niños o similar) también pueden interrumpir la transmisión de datos. En este caso los sistemas de comunicación probablemente se interrumpirán el uno al otro. Igual que en el caso anterior la mejor solución es separar los caminos de transmisión. El SBC presenta los siguientes conectores e interfaces externas: • Un conector de comunicación con la línea de potencia, que es la opción estándar para la transmisión de datos con el inversor. • Un puerto COM 1, opción alternativa de conexión con el inversor mediante un cable RS485. • Un puerto COM 2, que se conecta con un PC con el SDC mediante un cable RS232. • Un conector RELAIS OUT. Se pueden adquirir y evaluar todos los datos de un SBC (datos de los canales de medición y valores de energía diarios) con un PC y el SDC. Además todas las configuraciones de un SBC pueden ser visualizadas y modificadas con el SDC. Esto es independiente del tipo de conexión del PC al SBC. Durante su funcionamiento el SBC cambia al modo de ahorro de energía por la noche (después de no conseguir conectar con ningún dispositivo FV durante 15 minutos). Cada 15 minutos se despierta y chequea si puede conectar con algún dispositivo. Si no puede, vuelve al modo de ahorro de energía, en caso contrario reanuda su funcionamiento normal. -9- Proyecto Final de Carrera 2.1.4. El software Sunny Data Control El programa SDC, que trabaja bajo Windows, permite un almacenamiento a largo plazo de los datos medidos de plantas fotovoltaicas. Un puerto COM1 del PC se conecta al SBC mediante un protocolo de transmisión RS232 a 19.200 baudios. El software SDC puede controlar varias plantas, cada una con su SBC. Fig. 4. Software Sunny Data Control El programa detecta en primer lugar todos los dispositivos conectados (SBCs e inversores). Después de la detección aparece una estructura tipo árbol con todos los tipos de dispositivos detectados y su número de serie. Para cada dispositivo se pueden visualizar los canales de medición definidos en el SBC, y seleccionar los que se quieren visualizar y/o registrar por el SDC. El SDC automáticamente lee los canales de medición seleccionados de la memoria del SBC y los salva en el PC. Además desde el SDC se pueden modificar los canales de medición que el SBC registra, bien añadir nuevos canales de medición o remover alguno de los existentes. El registro de los canales de medición puede realizarse de manera manual o automática. El SDC crea un directorio de plantas FV en el disco duro del PC. Este directorio contendrá un subdirectorio con el nombre de planta de la instalación. El SDC almacena los datos medidos en este subdirectorio de la siguiente forma: • Cada SBC tiene su propio subdirectorio. Este subdirectorio está formado por el texto SBC seguido por el número de serie del dispositivo. • El almacenamiento y visualización de los datos del SBC se hace en formato Excel. Los datos transmitidos se dividen en dos grupos: valores de energía producida diarios, y todos los restantes valores. Cada una de estos dos grupos se adquieren del SBC separadamente y se almacenan en archivos de datos separados: o Los valores de energía diarios se guardan en archivos anuales cuyo nombre tiene el formato SDT_AA.xls, donde AA son los dos últimos dígitos del año registrado. o El resto de valores medidos se guardan en archivos separados mensuales de nombre SDM_AAMM.xls, donde MM son los dos dígitos del mes registrado. En el caso de que el intervalo de medición definido en el SBC sea de 3 minutos o -10- J.M.Estepa inferior, los datos se guardan adicionalmente en archivos diarios SDM_AAMMDD.xls, cada uno de los cuales contiene todos los datos de un día simple, y donde DD son los dos dígitos del día registrado. La hoja de cálculo Excel se define de la siguiente manera para los archivos mensuales y diarios: • La primera columna contiene la fecha y la hora de medición de los canales medidos. • Cada una de las restantes columnas contiene uno de los canales de medición seleccionados de los dispositivos detectados. Se crea una hoja separada para cada dispositivo (SBCs e inversores), siendo el nombre y el número de serie del dispositivo el nombre de la hoja de cálculo. Y para los archivos anuales con los valores de energía diarios. • La primera columna contiene la fecha de la medición. • Cada una de las restantes columnas los valores de energía diarios de cada uno de los dispositivos detectados. Esta función no requiere selección de canales o dispositivos. Los datos medidos registrados pueden posteriormente ser evaluados gráficamente con Excel. SDC contiene una macro para la evaluación de datos en el archivo Excel97\SDCmac.xls. Cuando se abre alguno de los archivos almacenados con la macro aparece un menú adicional Sunny Boy en la barra de menú de Excel. Este nuevo menú tiene una función Diagrama, que permite seleccionar uno o varios canales registrados y un intervalo de tiempo, y con ello crea un gráfico de los valores del canal durante ese período de tiempo. La otra función fundamental del SDC es la posibilidad de crear una ventana de visualización online, que permite la monitorización en cualquier momento de las condiciones de operación de todos los dispositivos de la planta. Existe un menú para definir las características que debe tener esta ventana de supervisión: su nombre, el número de dispositivos a visualizar, su colocación en la red de la pantalla y si ésta es visible o no, si se va a desplegar una ventana de información rápida seleccionada de cada dispositivo, la paleta de colores del fondo y el texto, etc. Por último, de una lista de canales disponibles se seleccionan los canales de cada dispositivo que se van a visualizar. La ventana online arranca automáticamente cuando al menos un canal se ha seleccionado. La transmisión de datos se realiza dispositivo por dispositivo. El SDC, además, permite registrar todos los datos de la ventana de visualización online en archivos ASCII y XML. Estos dos archivos de texto se guardan en el subdirectorio online de la instalación actual del SDC. El nombre de los archivos está formado por el nombre de la ventana de supervisión más el sufijo .txt y .xml (para los archivos ASCII y XML respectivamente). Los archivos no son acumulativos, sino que se actualizan conforme lo hace la ventana de visualización online (cada cinco segundos). Los inversores Sunny Boy y el controlador SBC pueden ser configurados directamente con el Sunny Data Control. Tras seleccionar el dispositivo que se quiere configurar, se despliega -11- Proyecto Final de Carrera la lista de parámetros disponibles de ese dispositivo. Algunos parámetros pueden ser modificados (por ejemplo DA_Meas). Interval define el período de tiempo para calcular el promedio de valores medidos, que en esta instalación se ha establecido en 1 minuto. Otros, en cambio, vienen fijados de fábrica y no se pueden cambiar. El SDC tiene una función servidor de Internet. Esta función permite visualizar cualquiera de los valores medidos de la instalación FV en una página html (Hipertext Markup Language o Lenguaje de Marcas de Hipertexto) de Internet. La aplicación misma es un servidor de Internet en este caso. Los datos medidos se visualizan en una página html con Applets Java en un entorno cliente/servidor. La comunicación entre los Applets y el SDC se establece mediante una aplicación del SDC denominada SDC Agent, que se instala en el servidor Web. Por tanto, el SDC Agent es la interface entre los Applets y el SDC. La comunicación entre los Applets y el SDC Agent por un lado, y entre el SDC Agent y el SDC por otro, se realiza mediante una conexión TCP/IP. Un SDC Agent puede comunicarse con hasta tres diferentes plantas FV a la vez. Existen dos modos que se pueden usar para conectar la instalación FV al SDC y procesar los datos para los Applets: • Conexión directa: el SBC está conectado de forma permanente al SDC mediante un enlace RS232 o RS485. Se accede directamente a los valores medidos de la planta FV y se transmiten a Internet. Este modo es el recomendado, pues soporta todos los modos de visualización disponibles para los Applets. • Conexión offline: no hay una conexión permanente entre el SBC y el SDC. La conexión puede ser, por ejemplo, una línea de teléfono temporal. Este modo sólo usa los contenidos de los archivos de transmisión online, y sólo soporta un modo de visualización para los Applets. • Los requerimientos de sistema para usar las funciones de Internet del SDC son los siguientes: o Un servidor Web basado en el sistema operativo MS Windows o Un navegador compatible con Java 1.1 o posterior para los clientes de Internet. o El protocolo TCP/IP debe estar instalado en el ordenador donde se localiza el SDC. La activación de la función Servidor del SDC se realiza en una opción del menú, en la que también se completa una lista de canales de Internet, a la que se añaden todos los canales de medición que se van a transmitir y visualizar vía Internet. Además se definen el número de puerto de servidor de la aplicación SDC, que por defecto es el 18.503, y el tiempo de barrido de los canales (función Channel scan), que es el período de tiempo entre dos envíos de los canales y que se establece en 5 segundos. El SDC Agent por su parte no tiene una interface gráfica de usuario propia (sólo brevemente se activa una pequeña ventana que desaparece cuando el programa está corriendo), y se configura con un navegador Web introduciendo la URL http://62.204.201.181:18501, o bien -12- J.M.Estepa http://meteo.ieec.uned.es:18501. En el menú de configuración se definen los siguientes elementos: • El nombre-alias del servidor, pues los Applets identifican y se comunican con los servidores de acuerdo a estos nombres-alias. • La dirección IP o el nombre DNS (Domain Name System o Sistema de Nombres de Dominio) del computador donde el SDC está instalado (62.204.201.181 en nuestro caso). • El puerto TCP del SDC. Debe ser el mismo que el definido como número de puerto de la función servidor del SDC (en este caso el 18503). • El puerto TCP del SDC Agent. Por defecto es el 18500. • El máximo número de clientes de Internet. Este número define el máximo número de Applets que pueden comunicar con el SDC Agent a la vez. Debe definirse según la potencia disponible del procesador. Por defecto se establece en 50 clientes. La presentación gráfica de la planta FV en las páginas Web se hace con Applets Java. Se recomienda mantener el número de Applets tan bajo como sea posible debido al hecho de que cada Applet establece su propia conexión TCP con el servidor Web. Están disponibles varios modos diferentes de visualización de los datos de la instalación FV. Un Applet simple puede desplegar varios modos a la vez con el objetivo de mantener el número de conexiones tan bajo como sea posible. Los Applets se configuran mediante parámetros que se pasan al Applet en el código html de la página Web. Los Applets y sus características se describirán con detalle posteriormente. -13- Proyecto Final de Carrera 2.2. Estación meteorológica 2.2.1. El sistema de adquisición de datos (SAD) Este tipo de unidades suelen denominarse también Registradores Digitales, DataLoggers o DataTakers. Por su alto grado de funcionalidad, se prefiere la denominación de SAD, que engloba la idea de SISTEMA por realizar muchas más funciones que un simple registrador de datos, como son el proceso previo de los datos; la gestión de las comunicaciones (vía radio, GSM, Internet, etc.); la generación automática de alarmas; etc., e incluso, la transmisión de imágenes mediante la conexión de una o varias cámaras tipo webcam. El equipo disponible, de la serie 3000 de Geonica, tiene aplicación en muy diversos campos de la Meteorología, la Hidrología o la Vigilancia Medioambiental, siendo también equipos idóneos para la medida y el control de procesos industriales, en todos aquellos casos en los que se precise realizar un almacenamiento remoto de la información, para dejar constancia de los valores históricos de los parámetros medidos, alarmas generadas, o comandos de control activados por la unidad, durante el proceso industrial en cuestión. Fig. 3. Geonica 3000 Canal físico: Corresponde con cada una de las entradas físicas de las que dispone el equipo y que permiten la conexión de las señales procedentes de los sensores. Dichas señales pueden proceder de un sensor externo o de otro sistema de medida o dispositivo, y pueden ser de naturaleza analógica o digital. Canal analógico: Los canales analógicos, antes de procesarse, necesitan ser digitalizados. Para ello se utiliza un conversor analógico-digital que está incluido en el SAD. La conversión de la señal a digital será tanto más fiel cuanto mayor sea la resolución y la precisión de dicha conversión. Con una resolución de 19 bits más signo (20 bits), que es la que utiliza este modelo, se tiene la posibilidad de discriminar una parte entre 524.288 partes de la señal de entrada, tanto para señales positivas como negativas. Esta gran resolución evita tener que amplificar las señales de entrada, eliminando así los errores que se derivan del proceso de amplificación presentes en otros equipos de menor resolución. -14- J.M.Estepa Canal digital: A diferencia de los analógicos, los canales digitales no necesitan ser convertidos y por tanto, la información que aportan puede ser tratada directamente por el microprocesador del SAD. Estos canales digitales pueden ser de cuatro tipos distintos: • Frecuencia-periodo: El equipo recibe una señal pulsante cuya frecuencia es función del parámetro que se desea medir. Cuando se mide este tipo de canales, el equipo analiza con gran precisión el numero de pulsos que se han leído en un determinado período de tiempo y a partir de ahí, calcula la frecuencia o, su inversa, el período. Un ejemplo típico de este tipo de sensor es el (sensor de velocidad del viento) que entrega a su salida una señal pulsante que aumenta o disminuye de frecuencia a medida que el viento sube o baja de velocidad. • Acumuladores-contadores: El equipo recibe una serie de pulsos en función de la variación que experimenta el sensor. Estos pulsos son acumulados durante un período de tiempo para determinar la medida exacta del sensor. El pluviómetro es un claro ejemplo de este tipo de canal, en el que cada vez que las cazoletas internas se llenan de agua, se produce un volcado que, a su vez, provoca un pulso en la señal de entrada al SAD. Pasado un tiempo, la cantidad de agua total será función del acumulado de todos los pulsos recibidos en ese intervalo. • De estado: La señal procedente del sensor nos da información simplemente de un estado que puede ser “activado-desactivado”. Un ejemplo puede ser el detector de apertura de una puerta, que nos indica si ésta se encuentra abierta o cerrada, sin que exista la posibilidad de estados intermedios. • Canales inteligentes: En ocasiones, la información que recibe el equipo de adquisición no proviene directamente del elemento sensor, sino que ha sido adquirida, convertida y tratada por un equipo determinado o sensor que esta dotado de su propio procesador. En estos casos la vía física de entrada es un puerto de comunicación serie mediante el cual el equipo interroga al sensor inteligente, solicitando la información deseada. Para que este tipo de intercambio de información se pueda llevar a cabo, es necesario que ambos sistemas hablen el mismo “lenguaje” o protocolo de comunicación. Canal lógico: Corresponde con cada una de las variables o parámetros que se desea medir. En condiciones normales cada canal físico se corresponde con una variable a medir y por tanto con un canal lógico. Por ejemplo, en el canal físico 5 de tipo analógico, se conecta una sonda de temperatura y su valor se puede visualizar en el canal lógico 5, ó en cualquier otro disponible. Pero esta situación no siempre se da, ya que como hemos visto antes, pueden existir sensores del tipo inteligente que se conectan por una entrada física pudiendo aportar más de una variable, parámetro o canal lógico a medir. Otra situación que también se puede dar, es la de que un canal lógico (por ejemplo en el agua la obtención de la Conductividad Corregida), necesita información de dos canales físicos, uno por donde se mide la Conductividad Bruta y de otro para la Temperatura. Combinando la medida de los 2 parámetros, se obtiene el valor de la Conductividad Corregida del agua. Una definición más concreta correspondería con la de una ventana lógica de visualización, cálculo y almacenamiento, para una variable determinada, cuya información procede de uno o varios canales físicos. -15- Proyecto Final de Carrera Periodo de almacenamiento: Permite al usuario definir cada cuánto tiempo desea registrar en la memoria de almacenamiento del sistema, los cálculos y datos estadísticos obtenidos por el equipo, partiendo de los datos leídos en el muestreo. Salvo petición expresa, el SAD no guarda los datos instantáneos en la memoria de almacenamiento, ya que ocuparían gran cantidad de espacio y la autonomía de ésta, por mucha capacidad de almacenamiento de la que se dispusiese, se reduciría drásticamente. La forma de operar, por tanto, es la de obtener de forma dinámica una serie de valores estadísticos programados por el usuario. Estos valores estadísticos son los que finalmente se guardarán en la memoria de almacenamiento, y se obtienen partiendo de todas las lecturas instantáneas tomadas durante el período de almacenamiento. Los cálculos que puede programar el usuario son: valores medio, máximo y mínimo, desviación típica, acumulado, integrado, instantáneo o final de periodo. Incremento respecto al período anterior, estado de alarma y calidad del dato. La unidad agrupa los datos atendiendo al sensor del que proceden y guarda la fecha para cada uno de estos grupos de datos estadísticos, que se irán almacenando, grupo tras grupo, desde el inicio de la memoria de almacenamiento hasta el final. Cuando se agota la memoria destinada a almacenamiento, el equipo comienza un nuevo ciclo, desde el inicio de la memoria, borrando los datos más antiguos y almacenando los nuevos en su lugar. Obviamente, la programación del periodo de almacenamiento tiene una repercusión directa sobre la de la memoria, por lo que se hace necesario volcar los datos a PC antes de que sean sobrescritos. El período de almacenamiento puede ser programado por el usuario de forma independiente para cada canal lógico. El SAD de la ETSII de la UNED, dispone de sensores para registrar los siguientes parámetros: • Velocidad y dirección del viento. • Temperatura del aire. • Humedad relativa. • Presión atmosférica. • Radiación solar. • Lluvia. Fig. 6. Diversos sensores de la UNED -16- J.M.Estepa 2.2.2. El software Teletrans W3K Se trata de un conjunto de programas desarrollados por GEONICA, bajo plataforma Windows, que permiten el volcado de los datos desde el SAD al PC y su posterior tratamiento informático por parte del usuario. Funciones: • Comunicación con la estación por: RED TCP/IP, fibra punto a punto, bluetooth, radio punto a punto, RTC, GSM, Cable RS-232/422/485, módems punto a punto próximo y distante. • Programación para interrogación automática. • Configuración de todos los parámetros de funcionalidad de la estación. • Sincronización horaria. • Petición de datos almacenados en la memoria del SAD. • Calibración de todos los canales del SAD. • Conexión con bases de datos Access y SQL. En el caso de la estación meteorológica de la ETSII de la UNED, el SAD se ha conectado a través del puerto serie 232 con un Device Server que la conecta a la red Ethernet de la Escuela. Se ha configurado como servidor en el puerto 30000. De esta forma, la estación es visible a través de Internet y accesible por el programa Teletrans W3K en la dirección 62.204.201.170:30000. Fig. 7. Software Teletrans W3K -17- Proyecto Final de Carrera 2.3. Equipamiento informático 2.3.1. El ordenador meteo.ieec.uned.es Como equipamiento informático se dispone de un PC conectado a la red de la Escuela. Este ordenador tiene las siguientes características: • PC Dell. Microprocesador Pentium 4 1,6 GHz, 1 GB RAM, Disco duro de 38 GB, sistema operativo: Windows XP Profesional SP2. • Dirección IP pública: 62.204.201.181. • Identificación http: meteo.ieec.uned.es. El ordenador está conectado con las estaciones fotovoltaica y meteorológica y tiene instalado el software de comunicación con las estaciones: • Sunny Data Control para comunicación y control de la estación fotovoltaica. • Teletrans W3K para comunicación y control de la estación meteorológica. Además tiene instalado Internet Information Server (IIS) como servidor Web y otros programas, ya que se utiliza como servidor de recursos para el Departamento de Ingeniería Energética de la ETSII. -18- J.M.Estepa 2.3.2. Acceso remoto Para permitir el acceso remoto desde cualquier equipo, el ordenador meteo.ieec.uned.es tiene instalado el software de gestión remota RAdmin. Cualquier ordenador conectado a Internet, puede acceder ejecutando el software RAdmin Viewer, y creando un acceso a meteo.ieec.uned.es. Tecleando la contraseña (la indicada en el proceso de configuración del servidor de RAdmin) se abre en remoto la pantalla de meteo y se puede trabajar de manera idéntica a si se estuviera sentado delante de la pantalla de meteo.ieec.uned.es. Fig. 8. Acceso remoto al ordenador meteo.ieec.uned.es. -19- Proyecto Final de Carrera -20- J.M.Estepa 3. Auditoría del sistema actual 3.1. Estado actual 3.1.1. Estación meteorológica La estación meteorológica tiene una dirección IP pública asignada (62.204.201.170). A pesar de que esta circunstancia puede facilitar el acceso a los datos que almacena de forma periódica, en estos momentos no se explotan los mismos. No existe ningún sistema que permita el acceso a los mismos. Como principales problemas se detectan los siguientes: • No se explotan las utilidades de la estación meteorológica. Por tanto no se accede ni a los datos instantáneos ni a los datos almacenados de un periodo de tiempo. • La base de datos donde se almacenan los datos temporales crece de manera desproporcionada ya que se efectúan lecturas cada 10 minutos de 18 parámetros, lo que da una cifra de 2592 datos al día, es decir, unos 946000 registros anuales. • No existe ningún mecanismo automatizado de lectura y registro de información. Por tanto, la estación meteorológica guarda los datos conforme está configurada (registro cada 10 minutos de temperatura, viento, humedad, lluvia) y va perdiendo los datos más antiguos registrados. 3.1.2. Estación fotovoltaica El programa que explota los datos precisa de una conversión de los mismos basada en un programa que precisa una ejecución continua del mismo. Esto hace que el ordenador del Departamento (meteo.ieec.uned.es) esté “cautivo” de esa aplicación. Como principales problemas se han detectado los siguientes: • Cerrar las aplicaciones precisas para la aplicación actual supone poner en peligro el almacenamiento de los datos durante el periodo en el que el programa esté ejecutándose (Fig. 9). • El que el usuario del sistema deba ser siempre el mismo, y además el administrador del sistema, con los peligros de seguridad que esto conlleva. • El programa condiciona que el servidor Web deba estar instalado obligatoriamente en el ordenador del Departamento (meteo.ieec.uned.es), impidiendo establecer la seguridad de acceso a los datos necesaria. Fig. 9. Ejecución de aplicaciones en meteo para la instalación fotovoltaica. -21- Proyecto Final de Carrera 3.2. Propuesta de implantación Para la implantación del rediseño del sistema de monitorización a los datos de energías renovables (estaciones fotovoltaica y meteorológica) se propone el diseño de un sitio Web accesible públicamente (sin necesidad de identificación) con las siguientes premisas: • Basado en el uso de páginas Web activas. Para que el servidor no esté condicionado a ningún sistema operativo, se opta por servlets de java. • El servidor debe poder instalarse en cualquier ordenador y bajo cualquier sistema operativo. • La gestión de los datos no deberá condicionar que ningún ordenador deba ejecutar programas “visibles” (se ejecutarán, en caso necesario como servicios si el SO es Windows y como daemons si el SO es Linux) bajo ninguna cuenta de un usuario concreto. • Los datos deberán ser accesibles desde el servidor Web sin necesidad de conversión a través de la intranet del Departamento y/o Internet. • Dividir la base de datos de meteorología en anualidades, de forma que se haga menor el tamaño de la misma. Esto facilitará la política de copias de seguridad y acelerará las búsquedas. • Posibilidad de descarga flexible y “a la carta” de los datos registrados por parte de los usuarios, tanto de los datos de la estación fotovoltaica como de la estación meteorológica. En definitiva, y de acuerdo a lo especificado como objetivo del proyecto, éste deberá permitir: • Información en tiempo real de la información recogida por las estaciones fotovoltaica y meteorológica. • Acceso a los datos históricos registrados de la estación meteorológica y fotovoltaica. • Estandarización en la entrega de la información (descarga en formatos de datos fácilmente utilizables). • Previsión de seguridad en los datos, tanto en el acceso, como en la política de copias de respaldo y de seguridad. • Flexibilidad ante futuros cambios en la ubicación del servidor de información, tanto de máquina como de sistema operativo. -22- J.M.Estepa 4. Nuevo sistema de monitorización El nuevo sistema de monitorización se diseña de acuerdo al principio de diseño modular, pensado en la posibilidad de separación de cada uno de los elementos en equipos y/o servidores individuales. En una primera fase todos los programas, instalados como servicios, correrán en la misma máquina (meteo.ieec.uned.es) pero existe una fácil migración a equipos diferentes. El esquema del equipamiento hardware es el mostrado en la Fig. 10 Cliente Web Servidor de ficheros Servidor con PFC_JMEstepa Estación meteorológica meteo.ieec.uned.es Estación fotovoltaica Fig. 10. Esquema del nuevo sistema de monitorización: hardware. -23- Proyecto Final de Carrera El flujo de información entre los programas de la aplicación es el mostrado en la Figura 11: Navegador web Cliente web JVM Servidor ficheros TCP/IP TCP/IP Servidor de servlets W3K INTERNET Tomcat PFC JMEstepa mdb TCP/IP SDCAgent TCP/IP TCP/IP Estación meteorológica 62.204.201.170:30000 Pluviómetro Ordenador Departamento meteo.ieec.uned.es 62.204.201.181:18503 Sunny Data Control xls Termómetro Anemómetro … SWR … Sunny Boy Control SWR SMA-Net Fig. 11. Esquema del nuevo sistema de monitorización: flujo de información. -24- J.M.Estepa 4.1. Hardware El sistema completo de monitorización de datos consta de los elementos que se describen a continuación. 4.1.1. Estación fotovoltaica El equipo está formado por: • Siete módulos fotovoltaicos (los generadores solares) en serie. • Un ondulador de secuencias o inversor, del tipo Sunny Boy 1100E, una marca registrada de SMA Regelsysteme GMBH. • Un controlador Sunny Boy Control. Todo este equipamiento ha sido descrito en el Apartado 1.1. 4.1.2. Ordenador conectado al controlador de la estación fotovoltaica Un PC con sistema operativo Windows XP Profesional o superior. En una primera implantación será el ordenador meteo.ieec.uned.es instalado en el Laboratorio de Ingeniería Eléctrica, Electrónica y de Control de la ETSII de la UNED. Evidentemente, para poder compartir los datos recogidos de la estación fotovoltaica, precisa tener una conexión a Internet con una IP fija. SWR SWR SWR SBC meteo.ieec.uned.es Sunny Data Control *.XLS Internet TCP 18503 IP: 62.204.201.181 Fig. 12. Estación fotovoltaica y ordenador conectado a ella. -25- Proyecto Final de Carrera 4.1.3. Estación meteorológica De la marca Geonica 3000 y descrita en el apartado 2.2.1. Con IP fija y accesible desde Internet. Temperatura Geonica 3000 Estación meteorológica Vel. Viento Dir. Viento Humedad Rel Presión Atm. Lluvia Internet Radiación 30000 TCP IP: 62.204.201.170 Fig. 13. Estación meteorológica. 4.1.4. Servidor de servlets Equipo destinado a albergar la aplicación objeto de este proyecto. Al haber sido diseñado con Servlets (Web activa implementada con tecnología java), puede tener cualquier sistema operativo (linux, Windows XP, Windows Server 2003,…). Lo ideal sería destinar uno de los servidores de la ETSII para albergar el proyecto, pero en un principio, será el mismo ordenador del punto 2 de esta sección. Evidentemente, para poder ser accesible desde Internet, precisa tener una conexión a Internet con una IP fija. TeleTrans W3K SDA Agent S.Web config Acceso SDC Servidor Servlets Tomcat Servidor servlets con PFC_JMEstepa PFC_JMEstepa Hacia la est. meteorológica TCP IP: A.B.C.D Hacia el SDC Applets 18500 18501 Internet 8080 Fig. 14. Servidor de “servlets”. 4.1.5. Equipos cliente Cualquier ordenador conectado a Internet y con máquina virtual java (JVM) instalada para poder visualizar los applets de java. -26- J.M.Estepa 4.2. Software 4.2.1. Task o programador de tareas de Windows Instalar en: • Ordenador conectado a la estación fotovoltaica. • Servidor de servlets. Función: Este programa se utilizará para automatizar la carga en el arranque de los ordenadores de los programas necesarios para el funcionamiento de la aplicación, aunque es preferible la configuración de estos programas para que se ejecuten como servicios mediante el programa nº 2 (Instalación de servicios en Windows). Los programas que deben estar en ejecución serán: • Sunny Data Control, a ejecutar en el ordenador conectado físicamente a la estación fotovoltaica. • Sunny Data Control Agent, a ejecutar en el ordenador que albergue el servidor de servlets o servidor Web. Instalación: En los ordenadores con Sistema Operativo Windows XP viene ya instalado y se accede a él mediante la secuencia: Inicio – Todos los programas – Accesorios – Herramientas del Sistema – Tareas programadas – Agregar una tarea programada Se activa un asistente donde se deberá elegir, sucesivamente las siguientes opciones: • Elegir el ejecutable del programa correspondiente. • Realizar esa tarea: Al iniciar el equipo. • Usuario que lo ejecuta: elegir un usuario con perfil de administrador y teclear su contraseña. • Abrir propiedades avanzadas y en Configuración, desactivar todas las opciones. -27- Proyecto Final de Carrera 4.2.2. Instalador de servicios en Windows Instalar en: • Ordenador conectado a la estación fotovoltaica. • Servidor de servlets. Función: Permite ejecutar los programas TeleTrans-W3K.exe, SDC Agent y Sunny Data Control como servicios, de forma que no se requiera el login de ningún usuario y la tarea se ejecute en un segundo plano de forma permanente. Instalación: Con el programa NTServiceInstaller, siguiendo el siguiente procedimiento: • Instalar el programa mediante el ejecutable NTServiceInstaller.exe. • Inicio – Programas – ServiceInstaller – Servinst. Aparece la pantalla mostrada en la Figura 15. Fig. 15. Configuración del programa instalador de servicios en Windows. Service Name y DisplayName: es el nombre con el que se reconocerá el servicio. Startup: Automatic para que el servicio se ejecute de forma automática al encender el servidor. Executable: Ruta completa de cada uno de los programas que se desea convertir en servicios: TeleTrans, SDC Agent y SDC. Working Directory: Carpeta donde se localiza el *.exe y los ficheros asociados de cada uno de los 3 programas citados. -28- J.M.Estepa Pulsar sobre el botón Install y el programa se convierte en un servicio ejecutable en el arranque. Si hubiera algún problema en el funcionamiento del servicio de TeleTrans (por ejemplo, no se grabaran datos instantáneos), puede ser por no estar correctamente configurado el entorno. Al iniciar el programa por primera vez, crea el entorno y si es un servicio, no se ve nada en pantalla, por lo que, en realidad, el programa está esperando que el usuario configure las opciones. Para corregir este funcionamiento anómalo seguir la siguiente secuencia: • Herramientas del sistema – Servicios - parar el servicio w3k - pulsar con el botón derecho sobre el servicio – Propiedades - Iniciar sesión - Permitir a los servicios que interactúen con el escritorio. Esto hará que el servicio se ejecute con sus pantallas, en formato “no transparente”. • Se vuelve a arrancar el servicio, y se configura la aplicación de forma normal. • Se vuelve parar el servicio de la misma forma que se indica en el primer apartado. Se quita la opción de permitir interactuar con el escritorio y ya está perfectamente preparado para ejecutar como servicio TeleTrans iniciado por un usuario del sistema. En el caso de problemas en la ejecución de este programa (por ejemplo que haya antivirus que lo detecten como “potencialmente peligroso”) se puede realizar la ejecución de programas como servicios de acuerdo a las instrucciones que se indican en el Anexo III de este proyecto. -29- Proyecto Final de Carrera 4.2.3. Sunny Data Control (SDC) Instalar en: • Ordenador conectado a la estación fotovoltaica. Función: Automatizar la descarga de los datos de la estación fotovoltaica. Instalación: Con el CD de instalación que acompaña a la estación fotovoltaica. La configuración se hará de forma que automatice la descarga de datos en una hora que se prevea que el ordenador está poco utilizado: • Descargar automáticamente los datos al PC a las 3:00 AM. • Acceso a través del puerto 18503. -30- J.M.Estepa 4.2.4. Sunny Data Control Agent (SDCAgent) Instalar en: • Servidor de servlets. Función: Acceso a SDC a través de applets. Instalación: Con el CD de instalación que acompaña a la estación fotovoltaica. Es el interface de comunicaciones entre el applet de acceso a datos fotovoltaicos y el Sunny Data Control (instalado en meteo.ieec.uned.es). Se configuran los siguientes puertos: • Puerto 18501: Web Server del SDA Agent. – Para configuración. • Puerto 18500: sirve para comunicar el Applet con SDA Agent. • Puerto 18503: para comunicar el SDA Agent con el Sunny Data Control. Configurar el SDC Agent para que pueda acceder a los datos on-line proporcionados por el programa Sunny Data Control (instalado en el PC conectado al Sunny Boy Control). Para ello: • Ejecutar el programa SDCAgent.exe. • Acceder a la Web de configuración (http://localhost:18501) y proporcionar los datos de la máquina que ejecuta Sunny Data Control. En nuestro caso: o o o o Server1=meteo.ieec.uned.es. Port=18503. Marcar la casilla de servidor esté activo. Commit changes. A partir de este momento, SDCAgent se instalará como un servicio (apartado 4.2.2) en la máquina que funciona como servidor de páginas Web. -31- Proyecto Final de Carrera 4.2.5. TeleTrans-W3K Instalar en: • Servidor de servlets. Función: Permitir configurar los parámetros de la estación meteorológica y ejecutar acciones automatizadas como la lectura de valores instantáneos y la descarga de los datos recogidos por los sensores de la estación. Instalación: Automática con el programa Geonica Suite entregado con la estación meteorológica. Si presentara algún problema en la ejecución, se debe a que precisa del entorno .net framework, que se puede descargar e instalar desde las páginas de Microsoft (fichero dotnetfx.exe). Se necesita configurar la estación y las tareas de la siguiente forma: • Conexión automática con la base de datos correspondiente: o Herramientas – Opciones del Sistema – Activar login automático – Elegir los valores correspondientes al tipo de base de datos, nombre y camino de la base de datos, usuario avanzado y su contraseña. • Grabación de últimos valores meteorológicos: o Editar las propiedades de la Estación UNED – Pestaña Almacenamiento – Grabar Log de datos e indicar que el nombre del fichero que deberá ser: PATH_DE_LA_BASE_DE_DATOS\DATOSMETEO.LOG o Es importante que el fichero esté localizado en esa carpeta y sea ese su nombre, pues la aplicación buscará esos datos precisamente. • Creación de las tareas periódicas del sistema: o Petición de valores instantáneos con repetición cada 5 minutos (se puede variar y afecta a la exactitud de la portada de la aplicación). o Petición de valores almacenados con repetición cada día. -32- J.M.Estepa 4.2.6. Servidor de servlets Tomcat Instalar en: • Servidor de servlets. Función: Acceso vía Web de la aplicación PFC_JMEstepa. Instalación: Descargar y ejecutar el fichero correspondiente al sistema operativo del servidor correspondiente. La descarga se puede efectuar de tomcat.apache.org. Se configura fácilmente, haciéndolo un servicio de ejecución automática. Si se realiza la instalación sobre Windows XP y no llega a arrancar, se soluciona copiando el fichero msvcr71.dll de %java_home%/bin a la carpeta windows/system32. Dependiendo del sistema operativo y del cortafuegos configurado, será preciso abrir el puerto correspondiente (por defecto el 8080) y dar permiso de escritura en los directorios fotovoltaico y meteorológico al usuario sobre el que se ejecuta la aplicación. De no ser así, no se crearía el fichero .xls para la descarga de datos. Para el manejo del servidor, consultar manuales de configuración y utilización en Internet dependiendo del sistema operativo. -33- Proyecto Final de Carrera 4.2.7. PFC_JMEstepa (aplicación objeto de este proyecto) Instalar en: • Servidor de servlets. Función: Web de monitorización de las estaciones, objeto de este proyecto. Instalación: Al estar compilado el proyecto mediante NetBeans, se genera un archivo war. En computación, un archivo WAR (de Web Application Archive - Archivo de aplicación Web) es un archivo JAR utilizado para distribuir una colección de JavaServer Pages, servlets, clases Java, archivos XML, librerías de tags y páginas Web estáticas (HTML y archivos relacionados) que juntos constituyen una aplicación Web. Para su instalación basta con seguir el siguiente procedimiento: • Compilar con NetBeans el proyecto (Build-Clean and build the main Project). • Se genera el fichero PFC_JMEstepa.war en la carpeta dist del proyecto local. • Copiar PFC_JMEstepa.war al directorio webapps de Tomcat. • Borrar (si existiese) la carpeta PFC_JMEstepa de webapps para que se despliegue la nueva aplicación. También se puede desplegar la aplicación mediante el gestor de aplicaciones que Tomcat genera en el proceso de instalación. Para ello será necesario identificarse con permisos de administrador. • Asegurarse que existe el fichero \PFC_JMEstepa.conf (tiene los caminos a los ficheros) con, al menos, el siguiente contenido: o Directorio_Meteorologico=E:/Datos/uned/PFC/MiPFC/Proyecto/Datos/ o Directorio_Fotovoltaico=E:/Datos/uned/PFC/MiPFC/Proyecto/Datos/ o Evidentemente, los caminos a los datos meteorológicos (base de datos MeteoStation.MDB y ficheros DATOSMETEO.LOG) y fotovoltaicos (archivos *.XLS) habrá que adaptarlos al sitio real donde se encuentran esos ficheros. • Arrancar Tomcat. Desde ese momento la aplicación estará disponible en: o http://IP_SERVIDOR_SERVLETS:8080/PFC_JMEstepa/ o NOTA: El puerto 8080 es configurable y puede modificarse para adaptarse a la política de acceso del ordenador servidor -34- J.M.Estepa 4.2.8. Máquina Virtual de Java (v6.0) Instalar en: • Equipos clientes de la aplicación. Función: Visualización correcta de los applets de java. Instalación: Acceso a la Web de Sun (http://www.java.com/es/download/). Descargar la última versión estable (en este momento la 6.17) e instalar en los equipos. La máquina virtual de java estará disponible para todos los navegadores de Internet. -35- Proyecto Final de Carrera 4.3. Rutinas del nuevo sistema La aplicación está implementada bajo la estructura de servlets. Los servlets son objetos que corren dentro del contexto de un contenedor de servlets (como Tomcat o Glassfish) y extienden su funcionalidad. También podrían correr dentro de un servidor de aplicaciones (como OC4J Oracle). La palabra servlet deriva de otra anterior, applet, que se refería a pequeños programas que se ejecutan en el contexto de un navegador Web. Por contraposición, un servlet es un programa que se ejecuta en un servidor. El uso más común de los servlets es generar páginas Web de forma dinámica a partir de los parámetros de la petición que envíe el navegador Web. El ciclo de vida de un Servlet se divide en los siguientes puntos: 1. El cliente solicita una petición a un servidor vía URL. 2. El servidor recibe la petición. a. Si es la primera, se utiliza el motor de Servlets para cargarlo y se llama al método init(). b. Si ya está iniciado, cualquier petición se convierte en un nuevo hilo. Un Servlet puede manejar múltiples peticiones de clientes. 3. Se llama al método service() para procesar la petición devolviendo el resultado al cliente. 4. Cuando se apaga el motor de un Servlet se llama al método destroy(), que lo destruye y libera los recursos abiertos. -36- J.M.Estepa La aplicación se estructura en las unidades funcionales, páginas htm, páginas jsp, servlets y applets que se muestran en la Figura 16. Fig. 16. Estructura de archivos del proyecto. -37- Proyecto Final de Carrera 4.3.1. Menú principal Fig. 17. Pantalla del menú principal. Es la página que se presenta al acceder a la aplicación. Emplea los siguientes recursos: • Index.htm – página Web de inicio de la aplicación. Abre los frames o marcos que constituyen la página que se presenta al usuario. • Titulo.htm – corresponde al marco superior que identifica el título de la aplicación. • Menu.htm – corresponde al marco izquierdo que presenta un menú desplegable con las opciones del programa. • Portada.jsp – página combinada de código html y funciones java. Presenta la fecha y hora del servidor, el applet que muestra los datos instantáneos de la planta fotovoltaica (de.sma.SunnyViewer.SunnyApplet.class) y el servlet que presenta los datos más recientes leídos desde la estación meteorológica por el programa Teletrans W3K –ver apartado 4.2.5- (paquetes.LeeMeteoActual). o Debajo de los datos instantáneos aparece un hiperenlace con el texto ¿Quiere descargar los datos en formato BUFR y saber más del mismo? Que lleva a la página de información acerca del formato BUFR. -38- J.M.Estepa Fig. 18. Pantalla informativa del formato BUFR. Esta página permite conocer más acerca del estándar BUFR. En la opción del menú hay documentación sobre el mismo. Pulsando sobre el enlace inferior, se permite descargar en el ordenador del cliente un fichero de unos 74 bytes en formato BUFR con los últimos valores registrados de la estación meteorológica. Este fichero se crea en tiempo real y puede ser interpretado con aplicaciones destinadas a ello (Apéndice I: el estándar de datos BUFR) Fig. 19. Descarga en formato BUFR. 4.3.2. Fotovoltaica – Gráfico en tiempo real -39- Proyecto Final de Carrera Fig. 20. Pantalla de la opción Fotovoltaica-Gráfico en tiempo real. Con esta opción se puede visualizar un gráfico combinado con hasta 4 parámetros de la estación fotovoltaica en tiempo real. Precisa que en el servidor esté corriendo el programa SDCAgent para que aparezcan los gráficos con cadencia de 1 minuto. Para su funcionamiento, basta con elegir de 1 a 4 parámetros a representar y pulsar sobre el botón “Visualizar gráfico”. Emplea los siguientes recursos: • Applet_grafico.jsp – Formulario de adquisición de parámetros a representar que se llama a sí mismo para visualizar el gráfico correspondiente mediante el applet de.sma.SunnyViewer.SunnyApplet.class. -40- J.M.Estepa 4.3.3. Fotovoltaica – Valores en tiempo real Fig. 21. Pantalla de la opción Fotovoltaica-Valores en tiempo real. En esta página se visualizan en formato texto los valores instantáneos de la estación fotovoltaica. Tal como se indica en la cabecera de la misma, haciendo clic con el botón derecho o izquierdo del ratón se puede ampliar o disminuir el número de parámetros a visualizar. Emplea los siguientes recursos: • Applet_texto.htm – Página Web que llama al applet que muestra los parámetros en formato gráfico (de.sma.SunnyViewer.SunnyApplet.class). -41- Proyecto Final de Carrera 4.3.4. Fotovoltaica – Datos históricos Fig. 22. Pantalla de la opción Fotovoltaica-Datos históricos. Esta pantalla permite acceder a los datos diarios, mensuales y anuales registrados por la estación fotovoltaica. No es preciso que éstos residan en el ordenador que ejecuta el servidor Web, sino que los intentará localizar en el directorio indicado por el fichero PFC_JMEstepa.conf, por lo que podrían residir en una unidad de red o un directorio compartido, ya que, normalmente, estarán en el ordenador conectado directamente con la estación fotovoltaica. Tiene varias opciones configurables mediante la información del formulario: • Periodo de tiempo: Permite elegir si se pretende operar con ficheros de datos correspondientes a un día, a un mes o a una anualidad. • Fecha: Dependiendo de la opción anterior, se tendrá en cuenta 1, 2 ó 3 de los campos para elegir el día, el mes o el año sobre el que realizar la operación. • Magnitud: Dato registrado sobre el que se pretende operar. • Acción: Permite elegir qué tipo de visualización de datos se va a hacer: Visualizar la magnitud seleccionada: Ver la evolución de la misma. Visualizar gráfico: Realiza un gráfico de horas, días o meses, dependiendo del período de tiempo elegido. Visualizar todos los datos registrados en el período A continuación se muestran varias figuras que se presentan con las distintas opciones: -42- J.M.Estepa a) Visualización de los datos de la energía diaria generada durante el año. Fig. 23. Opción Visualización magnitud seleccionada. b) Visualización del gráfico de la energía diaria generada. Se observa que se hace una agrupación de datos por meses. Los colores cambian automáticamente dependiendo de la magnitud porcentual respecto del período con mayor valor. Fig. 24. Opción Visualización de gráfico resumen. -43- Proyecto Final de Carrera c) Visualización de todos los datos recogidos durante el mes de abril de 2009. Presenta todos los datos y la opción de descargarlos en el ordenador del usuario en un formato estándar para poder manejarlos. En la siguiente pantalla se observa el fichero obtenido una vez abierto con la hoja de cálculo de Excel. Fig. 25. Opción Visualización de todos los datos. Fig. 26. Descarga en formato EXCEL. La opción Fotovoltaica-Datos históricos emplea los siguientes recursos: • Historico_coge.jsp – Formulario de adquisición de parámetros a representar. Envía los datos recogidos al servlet historico_actua. • Historico_actua – Servlet de java que comprueba las opciones elegidas y, de acuerdo con las mismas, realiza la acción correspondiente. -44- J.M.Estepa • LectorExcel – Servlet que permite extraer la información de los ficheros XLS generados por la estación fotovoltaica. • EscritorExcel – Servlet que permite generar de forma automática el fichero XLS que el usuario puede descargarse. Tanto LectorExcel como EscritorExcel hacen uso de los métodos de la librería jxl (manejo de ficheros Excel) que se incluye compilada en el proyecto. Como complemento a estas pantallas, se puede acceder a la página del anterior proyecto de monitorización para visualizar los gráficos de la estación fotovoltaica. Esta página no pertenece a este proyecto, sino que es una modificación de una página web anterior. Se muestra un ejemplo del resultado que se puede obtener: Fig. 26b. Gráficos de la estación fotovoltaica -45- Proyecto Final de Carrera 4.3.5. Fotovoltaica – Fotos Fig. 27. Pantalla de la opción Fotovoltaica-Fotos. En esta página se pueden ver las fotos de la instalación fotovoltaica de la ETSII de la UNED en Ciudad Universitaria. Realiza un carrusel de fotografías mediante 2 botones que permiten avanzar y retroceder en la serie. Emplea los siguientes recursos: • camarafotos.htm – Página Web que llama al applet que muestra las fotografías y los botones de control. • camarafotos.class – Applet de java que realiza la secuenciación de las fotos. -46- J.M.Estepa 4.3.6. Meteorológica – Datos históricos Fig. 28. Pantalla de la opción Meteorológica-Datos históricos. Esta página recoge las distintas opciones que se pueden tomar para sacar datos de la base de datos de la estación meteorológica. Al igual que la aplicación de datos históricos de la estación fotovoltaica, la localización de las bases de datos se realiza mediante el fichero PFC_JMEstepa.conf, por lo que es flexible para poder disponer de ellos a través de unidades de red o unidades compartidas. Emplea los siguientes recursos: • historico_coje.jsp – Formulario para elegir las fechas inicial y final de las acciones a realizar. La obligación de que ambas fechas pertenezcan al mismo año tiene relación con la fragmentación por anualidades de las bases de datos con objeto de que su tamaño no sea excesivo (un millón de registros por año). • historico_meteo – Servlet que recoge los datos lanzados por historico_coge.jsp y realiza las acciones pertinentes. Emplea la clase de java específica para el manejo de bases de datos: BaseDatos.class con sus métodos correspondientes. • EscritorExcel – Servlet ya definido en la parte de fotovoltaica. • Bufr – Servlet que permite generar un fichero con formato BUFR y descargarlo en el ordenador del cliente. Los datos del fichero los toma del último instante muestreado por la estación meteorológica. Existe una rutina en java para comprobar la validez del fichero generado y mostrar sus datos. Dependiendo de la acción elegida para realizar, se pueden obtener los siguientes resultados: -47- Proyecto Final de Carrera a) Ver todos los datos recogidos. Se muestra una tabla con todas las magnitudes registradas durante el período elegido. La cantidad de datos mostrada es muy grande pues hay que recordar que se realiza un muestreo cada 10 minutos a lo largo de las 24 horas de cada día. Fig. 29. Opción “Ver todos los datos recogidos”. En esta opción se puede descargar un fichero en formato Excel con la tabla de datos para su análisis. Se puede observar en la Figura 30 el contenido del fichero descargado. Fig. 30. Descarga en formato EXCEL. -48- J.M.Estepa b) Gráficos de temperatura, velocidad del viento, humedad, presión y radiación Muestra múltiples gráficos correspondientes a temperatura, velocidad del viento, humedad relativa, presión atmosférica y radiación solar del periodo elegido. Para no sobrecargar el gráfico, esta opción sólo se activa cuando el período es igual o menor de 5 dias Fig. 31. Gráficos meteorológicos c) Resumen diario y gráficos. Presenta una tabla con los valores máximos, mínimos y promedio de los diferentes parámetros para cada uno de los días del período (Fig. 32). A continuación de la tabla-resumen se muestran diversos gráficos con la evolución de las temperaturas máxima y mínima, lluvia, ráfagas de viento, humedad y radición solar de cada uno de los días (Fig. 33). Fig. 32. Opción Resumen diario. -49- Proyecto Final de Carrera Fig. 33. Gráficos de valores meteorológicos. d) Resumen del período. Muestra los valores de lluvia recogida, temperaturas máxima y mínima, máxima radiación solar, máxima ráfaga de viento y presiones atmosféricas máxima y mínima en el período elegido. Sirve de información de consulta general para los usuarios que acceden a la Web para conocer qué parámetros hubo a lo largo de un periodo de tiempo (Fig. 34). Fig. 34. Opción Resumen del período. -50- J.M.Estepa 4.3.7. Meteorológica – Fotos Fig. 35. Pantalla de la opción Meteorológica-Fotos. Página de similares características a la de fotos de la estación meteorológica. De hecho, utiliza el mismo applet llamado por una página idéntica a las de 4.3.5. -51- Proyecto Final de Carrera 4.3.8. Documentos Fig. 36. Pantalla de la opción Documentos. Esta opción del menú utiliza referencias a páginas Web, documentos doc y pdf y es un conjunto de páginas estáticas html de elaboración sencilla. Su misión es documentar la aplicación y hacer referencia a toda la información del proyecto. -52- J.M.Estepa BIBLIOGRAFÍA Libros • • • • • • B.Eckel, “Thinking in Java”, Prentice Hall, 2002. M.L.Liu. “Computación distribuida. Fundamentos y Aplicaciones”, Addison Wesley, 2004. J.L.Hevia y A.Esteban, “Tecnologias de Servidor con J2EE”, Eidos, 2005. S.Allamaraju, C.Beust y otros, “Programación Java Server con J2EE”, Addison Wesley, 2001. S.Bodoff, E.Armstrong, Jennifer Ball, Debbie Carson, Ian Evans y Dale Green, “J2EE Tutorial”, Addison Wesley, 2004. I.Singh, S.Brydon, G.Murray, V.Ramachandran y T.Violleau, “Designing Web Services with the J2EE 1.4 Platform JAX-RPC, SOAP, and XML Technologies”, Sun Micro Systems, 2004. Revistas técnicas • PCWorld, múltiples artículos de los números correspondientes al año 2009 y 2010. Manuales • • • • • SMA Regelsysteme, “Sunny Boy. Descripción Técnica”. SMA Regelsysteme, “Sunny Boy Control and Control Plus. User Manual”. SMA Regelsysteme, “Sunny Data Control. Operating Instructions”. Geonica, “Manual Meteodata Rev.03”. Geonica, “Manual Teletrans W3K”. Recursos de Internet • • • • www.enterprisedt.com o Página oficial de Enterprise Distributed Technologies que distribuye libremente la librería edtFTPj. o Consultada y activa el 30 de septiembre de 2010. www.andykhan.com/jexcelapi/ o Página oficial de la librería Java Excel API, una API de código abierto de Java para manejo de ficheros con formato xls. o Consultada y activa el 30 de septiembre de 2010. www.oracle.com/technetwork/java/index.html o Página oficial del propietario de la Plataforma Java. Además de la descarga de la plataforma, existen múltiples tutoriales. o Consultada y activa el 30 de septiembre de 2010. www.wmo.int/pages/index_en.html o Página de inicio de la World Meteorological Organization. o Consultada y activa el 30 de septiembre de 2010. -53- Proyecto Final de Carrera • • www.wmo.int/pages/prog/www/WMOCodes/TDCFtables.html#TDCFtables o Tablas con códigos para la elaboración de ficheros con los estándares BUFR y CREX. o Consultada y activa el 30 de septiembre de 2010. www.w3c.org o Especificaciones relacionadas con servicios Web y accesibilidad. o Consultada y activa el 30 de septiembre de 2010. -54- J.M.Estepa APÉNDICES I. Contenido del CD-ROM El CD-ROM que acompaña a este proyecto tiene el siguiente contenido: Fig. 37. Contenido del CD-ROM. Contiene todo el software necesario para hacer que cualquier equipo con sistema operativo Windows se convierta en uno de los módulos indicados en el apartado 4 de este proyecto. La aplicación completamente lista para su instalación es el fichero \PFC_JMEstepa\dist\PFC_JMEstepa.war Un fichero WAR (Web Archive) no es más que un fichero comprimido (al igual que un JAR) que contiene todos los archivos necesarios para la aplicación web. Este fichero ha sido generado por el entorno de desarrollo NetBeans Lo único que hay que hacer es copiar este fichero WAR al directorio del servidor Tomcat (Apartado 4.2.6) TOMCAT_HOME\webapps. Luego será Tomcat el que se encargará de -55- Proyecto Final de Carrera descomprimir el archivo cuando se arranque el servidor. Normalmente esto solo se hace en el momento del despliegue final, cuando se desea instalar la aplicación y hacerla productiva. Además se ha incluido los siguientes archivos y carpetas con software: PFC_JMEstepa.pdf Proyecto en formato pdf. Portada.bmp Portada del proyecto. PFC_JMEstepa.ppt Presentación del proyecto con sus principales puntos de desarrollo. PFC_JMEstepa.conf Fichero ejemplo de opciones de configuración de la aplicación. Su misión y contenido se explica en el punto 4.2.7 del proyecto e indica en qué carpetas (unidades y directorios) se encuentran los datos de la estación meteorológica y fotovoltaica. Se debe colocar en el directorio raiz del ordenador que albergue la aplicación objeto de este proyecto JDK Carpeta con el programa de instalación del Java Developer Kit para el desarrollo y ejecución de programas escritos en lenguaje Java. JExcelAPI API de desarrollo con las librerias necesarias para la compilación de programas Java que hagan uso de ficheros Excel. NetBeans Carpeta con el progrma NetBeans, entorno de desarrollo para programas Java. RAdmin Carpeta con el programa de instalación de la herramienta RAdmin para el acceso y control remoto de ordenadores. SDCAgent Carpeta con los programas necesarios para instalar en un ordenador el cliente de la estación meteorológica. Tomcat Carpeta con el programa que instala el servidor de servlets para plataformas Windows donde alojar la aplicación objeto de este proyecto. W3k Carpeta con el programa que permite comunicar un ordenador con la estación meteorológica. -56- J.M.Estepa InstalaServicios Carpeta con los programas y las instrucciones que permiten instalar cualquier programa (*.exe o *.jar) como un servicio en un ordenador con sistema operativo Windows XP, 2003 Server o Vista. Jxl.jar y poi-3.1-beta2-20080526.jar Librerias de clases de java para el manejo de ficheros con formato xls. PFC_JMEstepa Carpeta con el código fuente de toda la aplicación objeto de este proyecto. Su contenido es la web completa de este proyecto, incluyendo programas con el código fuente, ejecutables, documentación y gestión de la aplicación. Responde al estándar de Sun Microsystem para aplicaciones basadas en servlets (Fig. 30): o DIST: carpeta con el fichero comprimido (PFC_JMEstepa.war) de distribución de la aplicación o SRC: carpeta con los programas fuente del proyecto o WEB: carpeta con los ficheros públicos de la aplicación, enumerados en el apartado 4.3 y en la Figura 16. Fig. 38. Carpetas del proyecto PFC_JMEstepa -57- Proyecto Final de Carrera -58- J.M.Estepa II Estándar de representación de datos meteorológicos BUFR BUFR es un estándar de representación de datos meteorológicos presentado por la Organización Mundial de Meteorología para el intercambio de ficheros con información meteorológica. A pesar de que está pensado para estaciones automatizadas, desde este proyecto se pensó en la posibilidad de la generación de este tipo de ficheros con objeto del estudio de sus posibilidades. Las claves determinadas por tablas BUFR (Forma binaria universal de representación de datos meteorológicos) y CREX (Clave de caracteres para la representación y el intercambio de datos) ofrecen, frente a las claves alfanuméricas tradicionales, dos grandes ventajas: son flexibles y ampliables. Estas características son posibles porque BUFR y CREX son autodescriptivas. El término “autodescriptivo” significa que la forma y el contenido de los datos incluidos en un mensaje BUFR o CREX están descritos en el propio mensaje. Además, BUFR ofrece la posibilidad de condensación, o empaquetado, en tanto que la clave alfanumérica CREX puede ser leída por una persona. BUFR fue aprobada por primera vez para usos prácticos en 1988. Desde entonces, ha sido utilizada para observaciones obtenidas por satélites, aeronaves y perfiladores de viento, y para observaciones de ciclones tropicales. BUFR y CREX son las únicas claves que necesita la OMM para la representación e intercambio de datos de observaciones, y están recomendadas para todas las aplicaciones presentes y futuras de la OMM. -59- Proyecto Final de Carrera II.I. Estructuras de clave La estructura de las claves BUFR es la siguiente: SECCIÓN 0 sección de indicador SECCIÓN 1 sección de identificación SECCIÓN 2 (sección facultativa) SECCIÓN 3 sección de descripción de datos SECCIÓN 4 sección de datos SECCIÓN 5 sección de fin de mensaje En BUFR, las secciones de indicador y de identificación son secciones cortas que identifican el mensaje. La lista de descriptores, que remiten a elementos contenidos en tablas predefinidas e internacionalmente acordadas que figuran en el Manual de Claves oficial de la OMM figura en la sección de descripción de datos. Esos descriptores describen el tipo de datos contenidos en la sección de datos, así como el orden en que aparecen los datos en esa sección. La sección facultativa puede utilizarse para transmitir información o parámetros de ámbito nacional. La sección de fin de mensaje contiene los cuatro caracteres alfanuméricos “7777” para denotar el final del mensaje BUFR -60- J.M.Estepa II.II. Tablas BUFR Las tablas definen la manera de cifrar los parámetros (o elementos) como elementos de información en los mensajes BUFR o CREX (datos tales como el tipo de unidad, el tamaño o la escala). Figuran en el Manual de Claves de la OMM, Volumen I.2 (Claves internacionales), Partes B (Claves binarias) y C (Elementos comunes a las claves binarias y alfanuméricas). El Manual de Claves contiene también el Volumen I.1 (Claves internacionales), Parte A (Claves alfanuméricas) y el Volumen II: Claves regionales y prácticas nacionales de cifrado. El conjunto de esos tres volúmenes es la Publicación Nº 306 de la OMM. Las tablas que definen los sistemas de cifrado BUFR y CREX son las Tablas A, B, C y D. En la Tabla A los datos se desglosan en varias categorías (por ejemplo, Datos de superficie – terrestres, Datos de superficie – marinos, Sondeos verticales (distintos de los satelitales), Sondeos verticales (de satélite), etc.). Aunque técnicamente no son esenciales para los sistemas de cifrado/descifrado de BUFR o CREX, las categorías de datos de la Tabla A son útiles para fines de telecomunicación y para el almacenamiento y recuperación de datos de una base de datos. La Tabla B describe la manera de cifrar y descifrar en BUFR y CREX diversos parámetros o elementos. Para cada elemento, la tabla indica el número de referencia (o el número de descriptor de elemento, que se utiliza en la sección descriptiva de la clave como “puntero”, como ya se ha explicado), el nombre del elemento y la información necesaria para cifrar o descifrar ese elemento. En BUFR, esa información consiste en las unidades que se utilizarán, la escala y los valores de referencia que se aplicarán al elemento, y el número de bits utilizados para describir el valor del elemento (la anchura de datos BUFR). La Tabla B es fundamental para el cifrado y descifrado tanto de BUFR como de CREX. -61- Proyecto Final de Carrera II.III. Unidades Las unidades de las entradas de la Tabla B hacen referencia al formato utilizado para representar los datos en la Sección 4 de BUFR. En BUFR, la mayoría de los parámetros meteorológicos u oceanográficos se representan en unidades del sistema internacional (SI), por ejemplo en metros, o en grados Kelvin. Sin embargo, los datos pueden ser también numéricos, como en el caso de un número OMM de bloque, o carácter, por ejemplo para un identificador de aeronave. Además, las unidades pueden hacer también referencia a una tabla de cifrado o de banderines descrita en el Manual de Claves de la OMM. -62- J.M.Estepa II.IV. Escala La escala hace referencia a la potencia de 10 por la que se ha multiplicado el elemento de la Sección 4 de BUFR o de la Sección 2 de CREX para conservar la precisión deseada en los datos transmitidos. Así, por ejemplo, en la Tabla B la unidad de latitud son grados enteros, que para la mayoría de los usos no es suficientemente precisa. Por ello, habrá que multiplicar los elementos por 100 (escala = 2) de manera que la precisión transmitida sea del orden de centésimas de grado, que resulta más útil. Por otra parte, en la Tabla B la unidad (SI) de presión es el pascal, que es bastante pequeña y proporcionaría un grado de precisión innecesariamente grande. Así, en la Tabla B hay que dividir la presión por 10 (escala = -1), con lo que la unidad transmitida serán décimas de hPa, es decir, décimas de milibares, que constituye un grado de precisión más razonable para usos meteorológicos. -63- Proyecto Final de Carrera II.V. Valor de referencia Por lo que respecta a BUFR, el valor de referencia es un número que habrá que restar de los datos después de multiplicar por el factor de escala (si lo hubiere), pero antes del cifrado en la Sección 4, para obtener un valor no negativo en todos los casos. Por ejemplo, la latitud sur es negativa antes de aplicar el valor de referencia. Si se desease cifrar una posición de 35’50 grados de latitud sur, 35’50 multiplicado por 100 (escala = 2) arrojaría -3550. Si se resta el valor de referencia de –9000 se obtendrá un valor de 5450, que es el que se codificaría en la Sección 4. Para obtener el valor original al descifrar la Sección 4, si sumamos el valor de referencia –9000 a 5450 obtendremos –3550, que dividido por el valor de escala (100) daría –35’50. -64- J.M.Estepa II.VI. Anchura de datos En BUFR, la anchura de datos de las entradas de la Tabla B representa el número de bits abarcado por el valor más grande posible de un elemento de información de la Sección 4, una vez multiplicado por el factor de escala y restado el valor de referencia. En los casos en que un descriptor de la Tabla B define un elemento de datos de la Sección 4 que falta para un subconjunto dado, todos los bits de ese elemento serán puestos a 1 en la Sección 4. -65- Proyecto Final de Carrera II.VII. Descripción general de un mensaje BUFR El término “mensaje” se refiere a la utilización de BUFR como formato de transmisión de datos; sin embargo, BUFR puede utilizarse y se utiliza en varios centros de procesamiento de datos como formato de almacenamiento en línea, y para archivar datos. Para la transmisión de datos, cada mensaje BUFR consiste en un flujo binario continuo estructurado en seis secciones. Secc Nombre Contenido 0 Sección de indicador "BUFR", longitud del mensaje, número de edición BUFR 1 Sección identificación Longitud de la sección, Identificación del mensaje 2 Sección facultativa Longitud de la sección, más todo elemento adicional para usos locales en los centros de procesamiento de datos 3 Sección de descripción de datos Longitud de la sección, número de subseries de datos, banderín de categoría de datos, banderín de compresión de datos, y descriptores de datos que definen la forma y el contenido de distintos elementos de datos 4 Sección de datos Longitud de la sección y datos binarios 5 Sección de fin de mensaje "7777" (cifrado en el Alfabeto Internacional Nº 5 del CCITT) En http://www.wmo.int/pages/prog/www/WMOCodes/TDCFtables.html#TDCFtables se puede consultar la descripción pormenorizada de cada una de las secciones. En la página Web del proyecto también se ha incluido el manual de las capas 1 y 2 en español y de la capa 3 en inglés, así como las tablas de codificación de cada una de las magnitudes meteorológicas observables. Sección 0: Sección de indicador Octeto Nº 1–4 Contenido "BUFR" (cifrado mediante el Alfabeto Internacional Nº 5 del CCITT) OCTETO Nº 1 2 3 4 BINARIO 01000010 01010101 01000110 01010010 5–7 8 HEXADECIMAL 4 2 5 5 4 6 5 2 CIFRADO U B F R Longitud total del mensaje BUFR, en octetos (incluida la Sección 0) Número de edición de BUFR (actualmente, 3) -66- J.M.Estepa Sección 1 – Sección de identificación Octeto Nº 1–3 4 5–6 Contenido Longitud de la Sección, en octetos Número de tabla maestra BUFR – Permite representar mediante BUFR datos de otras disciplinas, con sus propias versiones de tablas maestras y de tablas locales. Así, por ejemplo, este octeto vale 0 en las tablas ordinarias WMO FM 94 BUFR, pero 10 en las tablas ordinarias IOC FM 94 BUFR, dedicadas principalmente a datos oceanográficos. Centro de origen: tabla de cifrado 0 01 033 7 Número de secuencia de actualización (cero para los mensajes BUFR originales; incrementado en función de las actualizaciones) 8 Bit 1 = 0 No hay sección facultativa = 1 Sección facultativa incluida Bits 2 – 8 puestos a cero (reservado) 9 Tipo de categoría de datos (Tabla A de BUFR) 10 Subtipo de categoría de datos (definido por los centros locales de procesamiento automático de datos) 11 Número de versión de tabla maestra utilizado (actualmente, 9 en lo que respecta a las tablas WMO FM 94 BUFR) 12 Número de versión de tabla local utilizado para ampliar la tabla maestra que se utiliza 13 Año del siglo 14 Mes 15 Día 16 Hora 17 Minuto -67- Proyecto Final de Carrera Sección 2 – Sección facultativa Octeto Nº 1–3 Contenido Longitud de la sección, en octetos 4 Puesto a cero (reservado) 5- Reservado para uso de los centros de procesamiento automático de datos Sección 3 – Sección de descripción de datos Octeto Nº 1–3 4 5–6 7 Contenido Longitud de la sección, en octetos Puesto a cero (reservado) Número de subseries de datos Bit 1 = 1datos observados =0 otros datos Bit 2 = 1datos comprimidos =0 Bits 3 - 8 8- datos no comprimidos puestos a cero (reservados) Conjunto de descriptores que definen la forma y el contenido de diversos elementos de información que contienen una subserie de datos en la sección de datos Sección 4 – Sección de datos Octeto Nº 1–3 Contenido Longitud de la sección, en octetos 4 Puesto a cero (reservado) 5- Datos binarios como se definen en los descriptores que comienzan en el octeto 8 de la Sección 3. -68- J.M.Estepa Sección 5 – Sección de fin de mensaje Octeto Nº 1–4 Contenido "7777" (cifrado con arreglo al Alfabeto Internacional Nº 5 del CCITT) OCTETO Nº 1 2 3 4 BINARIO 00110111 00110111 00110111 00110111 HEXADECIMAL DESCIFRADO 3 7 3 7 3 7 3 7 7 7 7 7 Para realizar el proyecto, se escogieron los siguientes descriptores de las variables meteorológicas a incluir en el mensaje: Elemento Velocidad viento Dirección viento Temperatura Humedad Presión Radiación Precipitación Latitud Longitud F 0 0 0 0 0 0 0 0 0 X 11 11 12 13 07 14 13 05 06 Y 002 001 023 003 004 035 011 002 002 Unidad m/s º ºC % Pa W/m2 Kg/m2 º º -69- Escala 1 0 0 0 -1 1 1 2 2 Referencia 0 0 -99 0 0 0 -1 -9000 -18000 bits 12 9 8 7 14 14 14 15 16 Proyecto Final de Carrera -70- J.M.Estepa III. Código fuente de las rutinas de la aplicación III.I. index.htm Presenta la pantalla principal de la aplicación. Divide la pantalla en 3 frames o marcos: el superior identificando la aplicación, el izquierdo donde se presenta el menú y el central sonde se mostrarán los contenidos. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd"> <html> <head> <title>Proyecto Fin de Carrera J.M.Estepa</title> </head> <frameset rows="85,*" cols="*" frameborder="NO" border="0" framespacing="0"> <frame src="titulo.htm" name="titulo" scrolling="NO" noresize > <frameset rows="*" cols="134,*" framespacing="0" frameborder="NO" border="0"> <frame src="./menu/menu.htm" name="menu" scrolling="NO" noresize> <frame src="portada.jsp" name="cuerpo"> </frameset> </frameset> <noframes><body></body></noframes> </html> -71- Proyecto Final de Carrera III.II. titulo.htm Presenta permanentemente el título de la aplicación. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <link rel="STYLESHEET" type="text/css" href="./estilos/estilos.css"> </head> <body> <table border="0"> <tr> <td><img src="fondo.jpg"></td> <td align="center"><h2>Redise&ntilde;o del sistema de monitorizaci&oacute;n de energ&iacute;as renovables: acceso, estandarizaci&oacute;n y seguridad</h2></td> <td><img src="fondo2.jpg"></td> </tr> </table> </body> </html> -72- J.M.Estepa III.III. menu\menu.htm Presenta un menu desplegable en la parte izquierda de la pantalla. Este menu permanece visible de forma permanente, por lo que siempre se dispone la posibilidad de realizar cualquier acción sin necesidad de volver atrás. <html> <head> <link rel="STYLESHEET" type="text/css" href="./../estilos/estilos.css"> </head> <body><br><br> <script> var verspacetoplevel=5 var verspacesublevel=2 var horspace=3 var textdeco="none" var minusimg=new Image() minusimg.src="abajo.gif" var plusimg=new Image() plusimg.src="lastpost.gif" var plusminusimgsrc=plusimg.src var content="" var fnttop="Arial" var fnttopsize=10 var fnttopcolor="white" var fnttopweight="bold" var fntsub="Arial" var fntsubsize=9 var fntsubcolor="F3F781" var fntsubweight="normal" var i_level=new Array(0,0,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1) var i_url=new Array("../portada.jsp","#","../fv/applet_grafico.jsp","../fv/applet_texto.htm","../fv/historico_coge.jsp","../fv/fot os/camarafotos.htm","#","../meteo/historico_coge.jsp","../meteo/fotos/camarafotos.htm","#","../documento s/manual.htm","../documentos/arquitectura.htm","../documentos/PFC_JMEstepa.doc","#","../documentos/ BUFR/capas1_2.doc","../documentos/BUFR/layer3.doc","../documentos/BUFR/BUFRTableB_Jun2010.pd f","../documentos/GRIB.doc") var i_text=new Array("ESTACIONES","Fotovoltaica","Grafico t.real","Valores t.real","Datos historicos","Fotos","Meteorologica","Datos historicos","Fotos","Documentos","Manual","Arquitectura","Mi Proyecto","Estandares","BUFR 1y2","BUFR 3","Tablas","GRIB") var i_target=new Array("cuerpo","_blank","cuerpo","cuerpo","cuerpo","cuerpo","_blank","cuerpo","cuerpo","_blank","cuerpo" ,"cuerpo","cuerpo","_blank","cuerpo","cuerpo","cuerpo","cuerpo") var whichi_opened=-1 var i_opened=false var hassubmenus=false var istoppageitem=true var ie=document.all?1:0 -73- Proyecto Final de Carrera var ns6=document.getElementById&&!document.all?1:0 var ns4=document.layers?1:0 function closesublevels() { plusminusimgsrc=plusimg.src content="" content+="<table border=0 cellpadding=0 cellspacing="+verspacesublevel+">" for (i=0;i<=i_level.length;i++) { hassubmenus=false if (i_level[i]==0) { var iplus=i+1 if ((iplus<=i_level.length) && (i_level[iplus]==1)) { hassubmenus=true } if (hassubmenus) { if (!istoppageitem) { content+="<tr><td colspan=2><img src='emptypixel.gif' height="+verspacetoplevel+"></td></tr>" } istoppageitem=false; content+="<tr valign=middle>" content+="<td>" content+="<a href='javascript:opensublevels("+i+")'>" content+="<img src='"+plusminusimgsrc+"' border=0 hspace="+horspace+"></a>" content+="</td>" content+="<td>" content+="<a href='javascript:opensublevels("+i+")' style='text-decoration:"+textdeco+";fontfamily:"+fnttop+";font-size:"+fnttopsize+"pt;color:"+fnttopcolor+";font-weight:"+fnttopweight+"'>" content+=i_text[i] content+="</a></td></tr>" } else { if (!istoppageitem) { content+="<tr><td colspan=2><img src='emptypixel.gif' height="+verspacetoplevel+"></td></tr>" } istoppageitem=false; content+="<tr valign=middle><td></td>" if (i_url[i]!="#" && i_url[i]!="" && i_url[i]!="http://" && i_url[i].indexOf("@")<0) { content+="<td><a href='"+i_url[i]+"' target='"+i_target[i]+"' style='text-decoration:"+textdeco+";fontfamily:"+fnttop+";font-size:"+fnttopsize+"pt;color:"+fnttopcolor+";font-weight:"+fnttopweight+"'>" } else if (i_url[i].indexOf("@")>0) { content+="<td><a href='mailto:"+i_url[i]+"' style='text-decoration:"+textdeco+";fontfamily:"+fnttop+";font-size:"+fnttopsize+"pt;color:"+fnttopcolor+";font-weight:"+fnttopweight+"'>" } else { i_url[i]="#" content+="<td><a href='"+i_url[i]+"' style='text-decoration:"+textdeco+";font-family:"+fnttop+";fontsize:"+fnttopsize+"pt;color:"+fnttopcolor+";font-weight:"+fnttopweight+"'>" } content+=i_text[i] content+="</a></td></tr>" } } } content+="</table>" istoppageitem=true; whichi_opened=-1 if (ie) { -74- J.M.Estepa menu.innerHTML=content } if (ns6) { document.getElementById("menu").innerHTML=content } if (ns4) { document.menutop.document.menu.document.write(content) document.menutop.document.menu.document.close() } } function opensublevels(thisiopened) { if (whichi_opened==thisiopened) { openurl() closesublevels() } else { whichi_opened=thisiopened content="" content+="<table border=0 cellpadding=0 cellspacing="+verspacesublevel+">" for (i=0;i<=i_level.length;i++) { if (i_level[i]==0) { if (thisiopened==i) {i_opened=true} else {i_opened=false} var iplus=i+1 if ((iplus<=i_level.length) && (i_level[iplus]==1)) {hassubmenus=true} else {hassubmenus=false} if (i_opened) {plusminusimgsrc=minusimg.src} else {plusminusimgsrc=plusimg.src} if (!istoppageitem) { content+="<tr><td colspan=2><img src='emptypixel.gif' height="+verspacetoplevel+"></td></tr>" } istoppageitem=false; content+="<tr valign=middle><td>" if (hassubmenus) { content+="<a href='javascript:opensublevels("+i+")'>" content+="<img src='"+plusminusimgsrc+"' border=0 hspace="+horspace+"></a>" } content+="</td>" content+="<td><a href='javascript:opensublevels("+i+")' style='text-decoration:"+textdeco+";fontfamily:"+fnttop+";font-size:"+fnttopsize+"pt;color:"+fnttopcolor+";font-weight:"+fnttopweight+"'>" content+=i_text[i] content+="</a></td></tr>" } else if (i_level[i]==1 && i_opened){ content+="<tr valign=middle><td> </td>" if (i_url[i]!="#" && i_url[i]!="" && i_url[i]!="http://" && i_url[i].indexOf("@")<0) { content+="<td><a href='"+i_url[i]+"' target='"+i_target[i]+"' style='text-decoration:"+textdeco+";fontfamily:"+fntsub+";font-size:"+fntsubsize+"pt;color:"+fntsubcolor+";font-weight:"+fntsubweight+"'>" } else if (i_url[i].indexOf("@")>0) { content+="<td><a href='mailto:"+i_url[i]+"' style='text-decoration:"+textdeco+";fontfamily:"+fntsub+";font-size:"+fntsubsize+"pt;color:"+fntsubcolor+";font-weight:"+fntsubweight+"'>" } else { i_url[i]="#" content+="<td><a href='"+i_url[i]+"' style='text-decoration:"+textdeco+";font-family:"+fntsub+";fontsize:"+fntsubsize+"pt;color:"+fntsubcolor+";font-weight:"+fntsubweight+"'>" -75- Proyecto Final de Carrera } content+=i_text[i] content+="</a></td></tr>" } } content+="</table>" if (ie) { menu.innerHTML=content } if (ns6) { document.getElementById("menu").innerHTML=content } if (ns4) { document.menutop.document.menu.document.write(content) document.menutop.document.menu.document.close() } istoppageitem=true; openurl() } } function openurl() { var selectedtarget=i_target[whichi_opened] var selectedurl=i_url[whichi_opened] if (selectedurl!="#" && selectedurl!="" && selectedurl!="http://" && selectedurl.indexOf("@")<0) { document.flink.target=selectedtarget document.flink.action=selectedurl document.flink.submit() } else if (selectedurl.indexOf("@")>0) { selectedurl="mailto:"+selectedurl document.flink.target=selectedtarget document.flink.action=selectedurl document.flink.submit() } } init() function init() { istoppageitem=true; content="" content+="<table border=0 cellpadding=0 cellspacing="+verspacesublevel+">" for (i=0;i<=i_level.length;i++) { if (i_level[i]==0) { var iplus=i+1 if ((iplus<=i_level.length) && (i_level[iplus]==1)) {hassubmenus=true} else {hassubmenus=false} if (!istoppageitem) { content+="<tr><td colspan=2><img src='emptypixel.gif' height="+verspacetoplevel+"></td></tr>" } istoppageitem=false; content+="<tr valign=middle><td>" if (hassubmenus) { content+="<a href='javascript:opensublevels("+i+")'>" content+="<img src='"+plusminusimgsrc+"' border=0 hspace="+horspace+"></a>" } content+="</td>" content+="<td><a href='javascript:opensublevels("+i+")' style='text-decoration:"+textdeco+";fontfamily:"+fnttop+";font-size:"+fnttopsize+"pt;color:"+fnttopcolor+";font-weight:"+fnttopweight+"'>" content+=i_text[i] -76- J.M.Estepa content+="</a></td></tr>" } else if (i_level[i]==1){ content+="<tr valign=middle><td> </td>" content+="<td><a href='"+i_url[i]+"' target='"+i_target[i]+"' style='text-decoration:"+textdeco+";fontfamily:"+fntsub+";font-size:"+fntsubsize+"pt;color:"+fntsubcolor+";font-weight:"+fntsubweight+"'>" content+=i_text[i] content+="</a></td></tr>" } } content+="</table>" istoppageitem=true; if (ie || ns6) { document.write('<span id="menu" style="position:relative">'+content+'</span>') document.close() } else if (ns4) { document.write('<ilayer name="menutop">') document.write('<layer name="menu">'+content+'</layer>') document.write('</ilayer>') document.close() } else { oldbrowser() } } function oldbrowser() { istoppageitem=true; content="" content+="<table border=0 cellpadding=0 cellspacing="+verspacesublevel+">" for (i=0;i<=i_level.length;i++) { if (i_level[i]==0) { var iplus=i+1 if ((iplus<=i_level.length) && (i_level[iplus]==1)) {hassubmenus=true} else {hassubmenus=false} if (!istoppageitem) { content+="<tr><td colspan=2><img src='emptypixel.gif' height="+verspacetoplevel+"></td></tr>" } istoppageitem=false; content+="<tr valign=middle><td>" if (hassubmenus) { content+="<img src='"+plusminusimgsrc+"' border=0 hspace="+horspace+">" } content+="</td>" content+="<td><a href='"+i_url[i]+"' target='"+i_target[i]+"'><font size=3 face="+fnttop+" color="+fnttopcolor+">" content+=i_text[i] content+="</font></a></td></tr>" } else if (i_level[i]==1){ content+="<tr valign=middle><td> </td>" content+="<td><a href='"+i_url[i]+"' target='"+i_target[i]+"'><font size=2 face='"+fntsub+"' color="+fntsubcolor+">" content+=i_text[i] content+="</font></a></td></tr>" } } -77- Proyecto Final de Carrera content+="</table>" document.write(content) document.close() } function reloadpage() { location.reload(true) } if (ns4 || ns6 || ie) { window.onload=closesublevels } if (ns4 || ns6 || ie) { window.onresize=reloadpage } </script> </body> </html> -78- J.M.Estepa III.IV. portada.jsp Presenta los valores actuales de la estación fotovoltaica y meteorológica, además de identificar las coordenadas de la localización de las mismas. Hace uso de los applets de la estación fotovoltaica y de la aplicación java LeeMeteoActual.class <%@page contentType="text/html" pageEncoding="UTF-8"%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="STYLESHEET" type="text/css" href="./estilos/estilos.css"> <title>Pagina de portada</title> </head> <body> <h1>Monitorización de las estaciones de la ETSII de la UNED</h1> Aplicación para la explotación de los datos meteorológicos y fotovoltaicos de las estaciones de la Escuela Técnica Superior de Ingenieros Industriales (ETSII) de la UNED:<br> <ul><li>Situación: Ciudad Universitaria - Madrid (Spain)</li> <li>Coordenadas: 40º 27' 5.5" N - 3º 44' 13.5" W</li> <li>Altitud: 670 m </li> <li>Hora local: <% java.util.Date date=new java.util.Date(); out.println(date); %></li></ul> <table class=tabla1 align=center width=100% border=0> <tr><th>Planta fotovoltaica</th><th>Estación meteorológica</th></tr> <tr><td width=50% align=center background="./fv/nubes.jpg"> <applet code = "de.sma.SunnyViewer.SunnyApplet.class" codebase = "./fv" archive = "SunnyViewer.jar" width = 100% height = 200 > <param name=ServerAlias value="Server1"> <param name=ServerPort value=18500> <param name=Languaje value=en> <param name=Channel1 value="E-Total"> <param name=Channel1.Name value="Energia generada:"> <param name=Channel2 value="h-Total"> <param name=Channel2.Name value="Durante:"> <param name=Channel3 value="Mode"> <param name=Channel3.Name value="Funcionamiento:"> <param name=Channel3.SText value="Parado,1,2,3,4,5,6,Operando,8,9"> <param name=Channel4 value="Error"> <param name=Channel4.Name value="Error:"> <param name=Channel5 value="Vac"> <param name=Channel5.Name value="Tension:"> <param name=Channel6 value="Iac"> <param name=Channel6.Name value="Corriente:"> <param name=component3 value=de.sma.SunnyViewer.ViewerDigital> <param name=name3 value=digital> <param name=digital.TitleColor value=#000000> -79- Proyecto Final de Carrera <param name=digital.FontName value="Helvetica"> <param name=digital.FontSize value=12> <param name=digital.Channels value=E-Total,h-Total,Mode,Error,Vac,Iac> <param name=digital.ValueColor value=#000000> <param name=digital.ChanTextColor value=#0000FF> <param name=digital.Title value="Datos actuales"> <param name=digital.BGPicture value="./fv/nubes.jpg"> <param name=DisplayErrMsg value=1> </applet></td> <td background="./fv/nubes.jpg"><center><b> <%@page import="paquetes.LeeMeteoActual"%> <% LeeMeteoActual m = new LeeMeteoActual(); String c[] = m.cabecera(); String d[] = m.datos(); for (int i = 0; i < c.length; i++) { out.println("<font color=#08088A>" + c[i] + ": <font color=black>" + d[i] + "<br>"); } %> </b></center></td> </tr> </table> </body> </html> -80- J.M.Estepa III.V. DescargaBUFR.class Servlet que permite mostrar datos acerca de BUFR, generar un fichero con los últimos datos de la estación meteorológica y descargarlo en el ordenador del cliente package paquetes; import java.util.Vector; import java.io.*; import java.net.*; import javax.servlet.*; import javax.servlet.http.*; public class DescargaBUFR extends HttpServlet { protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title>Servlet DescargaBUFR</title>"); out.println("<link rel='STYLESHEET' type='text/css' href='./estilos/estilos.css'>"); out.println("</head>"); out.println("<body>"); out.println("<h1>El estándar BUFR</h1>"); out.println("<a href=http://en.wikipedia.org/wiki/BUFR>BUFR en wikipedia</a>"); out.println("<p>BUFR es un estandar de representación de datos meteorológicos presentado por la Organización Mundial de MeteorologÃa para el intercambio de ficheros con información meteorológica."); out.println("<p>A pesar de que está pensado para estaciones automatizadas, desde este proyecto se pensó en la posibilidad de la generación de este tipo de ficheros con objeto del estudio de sus posibilidades."); out.println("<p>Las claves determinadas por tablas BUFR (Forma binaria universal de representación de datos meteorológicos) y CREX (Clave de caracteres para la representación y el intercambio de datos) ofrecen, frente a las claves alfanuméricas tradicionales, dos grandes ventajas: son flexibles y ampliables."); out.println(" Estas caracterÃsticas son posibles porque BUFR y CREX son autodescriptivas. "); out.println("<p>El término “autodescriptivo†significa que la forma y el contenido de los datos incluidos en un mensaje BUFR o CREX están descritos en el propio mensaje. Además, BUFR ofrece la posibilidad de condensación, o empaquetado, en tanto que la clave alfanumérica CREX puede ser leÃda por una persona."); out.println("<p>BUFR fue aprobada por primera vez para usos prácticos en 1988. Desde entonces, ha sido utilizada para observaciones obtenidas por satélites, aeronaves y perfiladores de viento, y para observaciones de ciclones tropicales."); out.println("<p>BUFR y CREX son las únicas claves que necesita la OMM para la representación e intercambio de datos de observaciones, y están recomendadas para todas las aplicaciones presentes y futuras de la OMM."); out.println("<p>"); try { // Localizamos el Directorio Meteorológico // Leo del fichero de configuración dónde está el fichero String directorio = ""; try { -81- Proyecto Final de Carrera FileReader fr = new FileReader("C:/PFC_JMEstepa.conf"); BufferedReader br = new BufferedReader(fr); String linea = br.readLine(); while (linea != null) { if (linea.contains("Directorio_Meteorologico")) { String s[] = linea.split("="); directorio = s[1]; } linea = br.readLine(); } br.close(); fr.close(); } catch (Exception e) { System.out.println("Error 1 en Bufr"); } // Leemos los datos del fichero String primera_linea = ""; String ultima_linea = ""; try { FileReader fr = new FileReader(directorio + "DATOSMETEO_Inst.LOG"); BufferedReader br = new BufferedReader(fr); primera_linea = br.readLine(); String leido = ""; while (leido != null) { ultima_linea = leido; leido = br.readLine(); } br.close(); fr.close(); } catch (Exception e) { System.out.println("Error 2 en Bufr"); } // Troceo en campos String t[] = primera_linea.split(";"); String d[] = ultima_linea.split(";"); String datetime = d[0]; // Informacion de los 9 datos a grabar en el BURF // dato[0]=Latitud // dato[1]=Longitud // dato[2]=velocidad del viento // dato[3]=direccion del viento // dato[4]=temperatura // dato[5]=humedad relativa // dato[6]=presion // dato[7]=radiacion solar // dato[8]=lluvia String titulo[] = new String[9]; double dato[] = new double[9]; titulo[0] = "Latitud"; dato[0] = 40.4515F; titulo[1] = "Longitud"; dato[1] = -3.7371F; for (int i = 1; i < 8; i++) { titulo[i + 1] = t[i]; dato[i + 1] = Double.parseDouble(d[i]); } -82- J.M.Estepa int escala[] = {2, 2, 1, 0, 0, 0, -1, 1, 1}; int referencia[] = {-9000, -18000, 0, 0, -99, 0, 0, 0, -1}; int bits[] = {15, 16, 12, 9, 8, 7, 14, 14, 14}; int F[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; int X[] = {5, 6, 11, 11, 12, 13, 7, 14, 13}; int Y[] = {2, 2, 2, 1, 23, 3, 4, 35, 11}; // Empieza la creación a pedal Vector<Byte> s1 = new Vector<Byte>(); // Sección 0 = Indicator Section s1.add((byte) 'B'); s1.add((byte) 'U'); s1.add((byte) 'F'); s1.add((byte) 'R'); // BURF s1.add((byte) 0); s1.add((byte) 0); s1.add((byte) 0); // Longitud total del fichero s1.add((byte) 3); // Versión=3 // Sección 1 = Identification Section s1.add((byte) 0); s1.add((byte) 0); s1.add((byte) 18); // Longitud de la sección 1 (18 bytes) s1.add((byte) 0); // 0=Standar s1.add((byte) 0); s1.add((byte) 58); // 0-58=USNavy FNMOC s1.add((byte) 0); // Sin utilizar s1.add((byte) 0); // No hay Seccion 2 (lo habitual) s1.add((byte) 0); s1.add((byte) 0); // 0=Datos tomados en superficie s1.add((byte) 9); s1.add((byte) 1); // 9=versión master de tabla; 1=versión local de tablas // La hora y el minuto de la observación datetime = datetime.replace(' ', '/'); datetime = datetime.replace(':', '/'); String trozos[] = datetime.split("/"); // Rompo el DateTime en sus componentes int mes = Integer.parseInt(trozos[1]); int dia = Integer.parseInt(trozos[0]); int anno = Integer.parseInt(trozos[2]) - 2000; int hora = Integer.parseInt(trozos[3]); int minuto = Integer.parseInt(trozos[4]); s1.add((byte) anno); s1.add((byte) mes); s1.add((byte) dia); s1.add((byte) hora); s1.add((byte) minuto); s1.add((byte) 0); // Longitud de la sección 1 es siempre par (en este caso 18) // Seccion 2 = Optional Section // Seccion vacia // Seccion 3 = Data Description // Describe los datos que va a grabar s1.add((byte) 0); s1.add((byte) 0); -83- Proyecto Final de Carrera s1.add((byte) 26); // Longitud de la sección = 3+1+2+1+9*2+1=26 s1.add((byte) 0); // Este byte vale siempre 0 s1.add((byte) 0); s1.add((byte) 9); // Vamos a grabar 9 datos s1.add((byte) 128); // 128->Datos observados y no comprimidos // Estos son los 9 datos for (int i = 0; i < 9; i++) { s1.add((byte) X[i]); s1.add((byte) Y[i]); } s1.add((byte) 0); // Tiene que haber un número par de bytes, añado uno // Seccion 4 = Data // Contiene el valor de los datos transmitidos s1.add((byte) 0); s1.add((byte) 0); s1.add((byte) 18); // Longitud de la sección = 3+1+(15+16+12+9+8+7+14+14+14)/8=3+1+14=18 (sobran 3 bits) s1.add((byte) 0); // Este byte vale siempre 0 // Este Vector va a contener los 1 y 0 de los datos codificados Vector<Integer> chorizo = new Vector<Integer>(); // Codifico los datos pasándolos al Vector for (int i = 0; i < 9; i++) { chorizo = codifica(chorizo, dato[i], escala[i], referencia[i], bits[i]); } // Relleno para que el numero de bits sea un multiplo de 8 int resto = chorizo.size() % 8; if (resto > 0) { for (int i = 0; i < 8 - resto; i++) { chorizo.addElement(0); } } // Y ahora a escribir int bytes_datos = 0; int puntero = 0; for (int i = 0; i < chorizo.size() / 8; i++) { int valor = 0; for (int j = 0; j < 8; j++) { valor = valor + (int) chorizo.elementAt(puntero) * (int) Math.pow(2d, (double) (7 - j)); puntero++; } bytes_datos++; s1.add((byte) valor); } // Seccion 5 = Final // Contiene 4 '7' para indicar el final s1.add((byte) '7'); s1.add((byte) '7'); s1.add((byte) '7'); s1.add((byte) '7'); // Cuento los bytes y los pongo en la posicion 7 (la 6 del Vector) s1.setElementAt((byte) s1.size(), 6);//s1.size() // Creo la matriz de bytes para escribir en el fichero -84- J.M.Estepa byte[] trama = new byte[s1.size()]; for (int i = 0; i < s1.size(); i++) { trama[i] = s1.elementAt(i); } try { // Abro el fichero String camino = request.getRealPath("/"); RandomAccessFile fich = new RandomAccessFile(camino + "ETSII_UNED.BUFR", "rw"); // Me desplazo a la posición 0 fich.seek(0L); // Escribo fich.write(trama); // Cierro el fichero fich.close(); } catch (Exception e) { System.out.println("Error 3 en Bufr"); } out.println("<a href=ETSII_UNED.BUFR>Descargar un fichero con los últimos datos meteorologicos de la ETSII de la UNED en formato BUFR</a><br>"); out.println("</body></html>"); } finally { out.close(); } } Vector codifica(Vector v, double valor, int escala, int referencia, int bits) { // Para codificar, primero se multiplica por 10^escala ... valor = valor * Math.pow(10d, (double) escala); // ... luego se le resta la referencia ... valor = valor - referencia; // ... tomo la parte entera ... int valor_codificar = (int) valor; // ... lo paso a binario ... for (int i = bits - 1; i >= 0; i--) { if (valor_codificar >= (int) Math.pow(2d, (double) i)) { v.addElement(1); valor_codificar -= (int) Math.pow(2d, (double) i); } else { v.addElement(0); } } return v; } void ver(byte b) { byte c[] = new byte[8]; for (int i = 0; i < 8; i++) { int ci = b & (byte) (Math.pow(2d, (double) (7 - i))); if (ci != 0) { System.out.print("1"); } else { System.out.print("0"); } } System.out.println(""); -85- Proyecto Final de Carrera } byte[] pasaCadenaAHexadecimal(String s) { byte b[] = new byte[s.length()]; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); b[i] = pasaCharAHexadecimal(c); } return b; } byte pasaCharAHexadecimal(char c) { byte b = (byte) c; System.out.println(c + " - " + b); return b; } // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."> /** * Handles the HTTP <code>GET</code> method. * @param request servlet request * @param response servlet response */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP <code>POST</code> method. * @param request servlet request * @param response servlet response */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. */ public String getServletInfo() { return "Short description"; } // </editor-fold> } -86- J.M.Estepa III.VI. fv\applet_texto.htm Presenta los datos de la estación fotovoltaica en formato texto. Hace uso de los applets proporcionados por la estación fotovoltaica <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Instalacion fotovoltaica en tiempo real</title> <link rel="STYLESHEET" type="text/css" href="../estilos/estilos.css"> </head> <body> <center> <h1>Valores en tiempo real</h1> <h3>Click con el botón izquierdo del raton: amplÃa el número de datos<br>Click con el botón derecho: reduce el número de datos</h3> <applet CODE = "de.sma.SunnyViewer.SunnyApplet.class" CODEBASE = "." ARCHIVE = "SunnyViewer.jar" WIDTH = 600 HEIGHT = 400 > <param name=ServerAlias value=Server1> <param name=ServerPort value=18500> <param name=BGColor value=#ffffff> <param name="Language" value="en" /> <param name=component1 value=de.sma.SunnyViewer.ViewerGrid> <param name=name1 value=rejilla> <param name=rejilla.FontName value=Dialog> <param name=rejilla.FontSize value=11> <param name=rejilla.BGPicture value=nubes.jpg> <param name=rejilla.Draw3DFrame" value=1> <param name=rejilla.BGColor value=#c0c0c0> <param name=rejilla.Width value=600> <param name=rejilla.Height value=400> <param name=DisplayErrMsg value=0> </applet> </center> </body> </html> -87- Proyecto Final de Carrera III.VII. fv\applet_grafico.jsp Página activa que presenta un formulario para escoger de 1 a 4 parámetros a representar gráficamente. Hace uso de los applets proporcionados por la estación fotovoltaica. Es una página que se envía los datos a ella misma y entonces representalos las magnitudes seleccionadas <%@page contentType="text/html" pageEncoding="UTF-8"%> <html> <head> <title>Instalacion fotovoltaica en tiempo real</title> <link rel="STYLESHEET" type="text/css" href="../estilos/estilos.css"> </head> <body> <center> <h1>Gráficos en tiempo real</h1> <h3>Elija hasta 4 valores para representar en el gráfico</h3> <form action=applet_grafico.jsp method=post> <% // Permite elegir hasta 4 parámetros a representar gráficamente String Parametros[] = {"Vpv", "Vpv-Setpoint", "Ipv", "Riso", "Iac", "Vac", "Fac", "Pac", "Zac"}; for (int i = 0; i < 4; i++) { out.println("Parámetro " + (i + 1) + ":<select name=grafico" + i + ">"); if (i > 0) { out.println("<option value=-> - </option>"); } for (int j = 0; j <= 8; j++) { out.println("<option value=" + Parametros[j] + ">" + Parametros[j] + "</option>"); } out.println("</select>"); } %> <br><input type=submit value="Visualizar gráfico"> </form> <applet CODE = "de.sma.SunnyViewer.SunnyApplet.class" CODEBASE = "." ARCHIVE = "SunnyViewer.jar" WIDTH = 800 HEIGHT = 400 > <% String canal1 = request.getParameter("grafico0"); String canal2 = request.getParameter("grafico1"); String canal3 = request.getParameter("grafico2"); String canal4 = request.getParameter("grafico3"); String canales = canal1; %> <param name=Channel1 value=<%=canal1%>> <% if (canal2 != null && !canal2.equals("-")) { out.println("<param name=Channel2 value=" + canal2 + ">"); canales = canales + "," + canal2; } if (canal3 != null && !canal3.equals("-")) { -88- J.M.Estepa out.println("<param name=Channel3 value=" + canal3 + ">"); canales = canales + "," + canal3; } if (canal4 != null && !canal4.equals("-")) { out.println("<param name=Channel4 value=" + canal4 + ">"); canales = canales + "," + canal4; } %> <param name=ServerAlias value=Server1> <param name=ServerPort value=18500> <param name=BGColor value=#ffffff> <param name=component1 value=de.sma.SunnyViewer.ViewerDiagram> <param name=name1 value=grafico> <param name=grafico.FontName value=Arial> <param name=grafico.FontSize value=12> <param name=grafico.Channels value=<%=canales%>> <param name=grafico.BGColor value=#393939> <param name=grafico.AxisLabelColor value=#0000ff> <param name=grafico.AxisColor value=#0000ff> <param name=grafico.ChartColor1 value=#ff0000> <param name=grafico.ChartColor2 value=#0000ff> <param name=grafico.ChartColor3 value=#00ff00> <param name=grafico.LegendTextColor value=#ff0000> <param name=grafico.ChartColor4 value=#ff00ff> <param name=grafico.ImageHighlight value=0> <param name=grafico.HighlightRate value=20> <param name=grafico.LegendVis" value=1> <param name=grafico.ChartStyle" value=Line> <param name=grafico.LegendBGTextColor value=#000000> <param name=grafico.Width value=800> <param name=grafico.Height value=400> <param name=grafico.BGPicture value="nubes.jpg"> <param name=DisplayErrMsg value=0> </applet> </center> </body> </html> -89- Proyecto Final de Carrera III.VIII. fv\historico_coge.jsp Página activa que presenta un formulario con el que realizar todas las operaciones con los ficheros generados por la estación fotovoltaica. Los datos recogidos por el formulario son enviados al servlet historico_actua <%@page contentType="text/html" pageEncoding="UTF-8"%> <html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <head> <title>Formulario historico central fotovoltaica</title> <link rel="STYLESHEET" type="text/css" href="../estilos/estilos.css"> </head> <body> <center> <h1>Datos históricos</h1> <h3>Elija opciones para realizar la operación</h3> <form name=fomulario action="../historico_actua" method=post> <table> <tr> <td>Periodo de tiempo:</td> <td> <input type=radio name="periodo" value="Diario">Diario<br> <input type=radio name="periodo" value="Mensual">Mensual<br> <input type=radio name="periodo" value="Anual" CHECKED>Anual </td></tr><tr><td>Fecha:</td><td> <select name=dia> <% for (int i = 1; i < 32; i++) { String dia = "0" + i; out.println("<option value=" + dia.substring(dia.length() - 2, dia.length()) + ">" + i + "</option>"); } %> </select> <select name=mes> <option value=01>Enero</option> <option value=02>Febrero</option> <option value=03>Marzo</option> <option value=04>Abril</option> <option value=05>Mayo</option> <option value=06>Junio</option> <option value=07>Julio</option> <option value=08>Agosto</option> <option value=09>Septiembre</option> <option value=10>Octubre</option> <option value=11>Noviembre</option> <option value=12>Diciembre</option> </select> <select name=anno> <% java.util.Calendar ahora = java.util.Calendar.getInstance(); int annoActual = ahora.get(java.util.Calendar.YEAR); for (int i = 2006; i <= annoActual; i++) { -90- J.M.Estepa out.println("<option value=" + i + ">" + i + "</option>"); } %> </select> (Depende del perÃodo elegido) </td></tr><tr><td>Magnitud:</td><td> <select name=tipo> <option value=Vpv>Vpv</option> <option value=Iac>Iac</option> <option value=Pac>Pac</option> <option value=Ipv>Ipv</option> <option value=Energia>Energia</option> </select> </td></tr><tr><td>Accion:</td><td> <input type=radio name="accion" value="Ver" CHECKED>Visualizar los datos registrados de la magnitud seleccionada<br> <input type=radio name="accion" value="Grafico">Visualizar el gráfico de la magnitud seleccionada<br> <input type=radio name="accion" value="Descargar">Visualizar TODOS los valores registrados del periodo seleccionado </td></tr><tr><td colspan=2 align=center><input type=submit value="Realizar accion"></td></tr> </table> </form> </center> <hr><h4>Se disponen datos desde el 21 de Agosto de 2006, aunque faltan los datos <b>diarios</b> de los siguientes periodos: <ul><li>Año 2007: del 04 al 22-Ene, del 26-Mar al 03-Abr, 08-Oct, del 12 al 31-Dic</li> <li>Año 2008: del 01 al 05-Ene, del 13 al 16-Feb, del 10 al 30-Abr</li> <li>Año 2009: del 29 al 31-Dic</li> <li>Año 2010: del 01 al 02-Ene</li></ul></h4> </body> </html> -91- Proyecto Final de Carrera III.IX. historico_actua.class Servlet que recibe los datos de historico_coge.jsp y realiza las acciones necesarias para consultar los ficheros de la estación fotovoltaica package paquetes; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class historico_actua extends HttpServlet { protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Encuentro el camino donde esta el entorno de ejecución // Es para el tema de salvar en formato xls // Lo siguiente no esta deprecated, pero no funciona //ServletContext context = this.getServletContext(); //String camino = context.getRealPath(request.getContextPath()); String camino = request.getRealPath("/"); response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { out.println("<html>"); out.println("<head>"); out.println("<title>Servlet historico_actua</title>"); out.println("<link rel='STYLESHEET' type='text/css' href='./estilos/estilos.css'>"); out.println("</head>"); out.println("<body>"); out.println("<H2 align=left>Registro de valores historicos de la central fotovoltaica</H2>"); out.println("<center>"); // Recogemos los datos procedentes del formulario historico_coge.jsp String periodo = request.getParameter("periodo"); String dia = request.getParameter("dia"); String mes = request.getParameter("mes"); String anno = request.getParameter("anno"); String accion = request.getParameter("accion"); String tipo = request.getParameter("tipo"); // Configuramos el camino del fichero correspondiente (no lo leo con FTP, sino a pedal) String ficheroXLS = ""; if (periodo.equals("Diario")) { ficheroXLS = "SDM_" + anno.substring(2, 4) + mes + dia + ".xls"; } if (periodo.equals("Mensual")) { ficheroXLS = "SDM_" + anno.substring(2, 4) + mes + ".xls"; } if (periodo.equals("Anual")) { ficheroXLS = "SDT_" + anno.substring(2, 4) + ".xls"; } LectorExcel lectorExcel = new LectorExcel(); String[][] respuesta = lectorExcel.lee(ficheroXLS); -92- J.M.Estepa // Dependiendo de la opción recogida, mandamos al método correspondiente if (accion.equals("Ver")) { ver(periodo, dia, mes, anno, respuesta, tipo, out, camino); } if (accion.equals("Descargar")) { // Le creamos un enlace al sitio ftp para que descargue ver_todo(periodo, dia, mes, anno, respuesta, out, camino); } if (accion.equals("Grafico")) { graficar(periodo, dia, mes, anno, respuesta, tipo, out); } // Cerramos la página out.println("</center>"); out.println("</body>"); out.println("</html>"); } catch (Exception e) { out.println("No hay datos (historico_actua) "); } } protected void ver_todo(String periodo, String dia, String mes, String anno, String[][] respuesta, PrintWriter out, String camino) { // Si el periodo es anual, este método es simplemente ver() if (periodo.equals("Anual")) { ver(periodo, dia, mes, anno, respuesta, "", out, camino); } else { // Para el resto de periodos, se visualizan todos los parámetros // Genero el fichero excel y creo un enlace por si lo quiere descargar String cabecera[] = {"Dia", "Vpv", "Vpv-Setpoint", "Iac", "Vac", "Fac", "Pac", "Zac", "Riso", "Ipv", "ETotal", "h-Total", "Power On"}; EscritorExcel ficheroExcel = new EscritorExcel(cabecera, respuesta, "Datos de la Estación fotovoltaica de la ETSII de la UNED", out, camino); out.println("<table class=tabla1><tr><th>Dia</th><th>Vpv</th><th>VpvSetpoint</th><th>Iac</th><th>Vac</th><th>Fac</th><th>Pac</th><th>Zac</th><th>Riso</th><th>Ipv</t h><th>E-Total</th><th>h-Total</th><th>Power On</th></tr>"); int par = 0; for (int i = 0; i < respuesta.length; i++) { if (par == 0) { out.println("<tr class=filaImpar>"); par = 1; } else { out.println("<tr class=filaPar>"); par = 0; } out.println("<td>" + respuesta[i][0] + "</td>"); // Imprimiendo el resto de los parámetros for (int j = 1; j < respuesta[0].length; j++) { out.println("<td align=center>" + respuesta[i][j] + "</td>"); } out.println("</tr>"); } out.println("</table>"); } } -93- Proyecto Final de Carrera protected void ver(String periodo, String dia, String mes, String anno, String[][] respuesta, String tipo, PrintWriter out, String camino) { // Si el periodo es anual, sólo puedo ver la EnergÃa diaria generada if (periodo.equals("Anual")) { out.println("<h3>Energia diaria generada en el año " + anno + "</h3><hr>"); out.println("<table class=tabla1>"); out.println("<tr><th>Dia</th><th>KWh</th></tr>"); int par = 0; for (int i = 0; i < respuesta.length; i++) { /* // Convirtiendo el numero de la columna 0 en una fecha long milisegundos = (long) (Double.parseDouble(respuesta[i][0]) * 24 * 60 * 60 * 1000); long milisegundos19700101 = 25569L * 24 * 60 * 60 * 1000; java.sql.Timestamp fecha = new java.sql.Timestamp(milisegundos - milisegundos19700101); String fechaFormateada = fecha.toLocaleString().substring(0, 11); String fechaFormateada=respuesta[i][0].substring(0,11); */ // Poniendo bonito el valor medido Float valor = Float.parseFloat(respuesta[i][1]); java.text.DecimalFormat formateador = new java.text.DecimalFormat("##0.000"); if (par == 0) { out.println("<tr class=filaImpar>"); par = 1; } else { out.println("<tr class=filaPar>"); par = 0; } out.println("<td>" + respuesta[i][0].substring(0, 11) + "</td><td>" + formateador.format(valor) + "</td></tr>"); } out.println("</table>"); } else { // Seleccionamos la columna a visualizar int columna = 0; String unidades = ""; if (tipo.equals("Vpv")) { columna = 1; unidades = "V"; } if (tipo.equals("Iac")) { columna = 3; unidades = "mA"; } if (tipo.equals("Pac")) { columna = 6; unidades = "W"; } if (tipo.equals("Ipv")) { columna = 9; unidades = "mA"; } if (tipo.equals("Energia")) { columna = 10; unidades = "KWh"; } out.println("<h3>Magnitud: " + tipo + " (" + unidades + ") Periodo: " + periodo + "<br>"); if (periodo.equals("Mensual")) { out.println("Mes: " + mes + "/" + anno + "</h3><hr>"); -94- J.M.Estepa } else { out.println("Dia: " + dia + "/" + mes + "/" + anno + "</h3><hr>"); } // Imprimimos los datos out.println("<table class=tabla1>"); out.println("<tr><th>Instante muestreado</th><th>" + unidades + "</th></tr>"); int par = 0; for (int i = 0; i < respuesta.length; i++) { // Poniendo bonito el valor medido Float valor = Float.parseFloat(respuesta[i][columna]); java.text.DecimalFormat formateador = new java.text.DecimalFormat("####0.000"); if (par == 0) { out.println("<tr class=filaImpar>"); par = 1; } else { out.println("<tr class=filaPar>"); par = 0; } out.println("<td>" + respuesta[i][0] + "</td><td>" + formateador.format(valor) + "</td></tr>"); } out.println("</table>"); } } protected void graficar(String periodo, String dia, String mes, String anno, String[][] respuesta, String tipo, PrintWriter out) { // El grafico anual consiste una fila por dia que agrupo por meses if (periodo.equals("Anual")) { String titulo = "Energia generada durante el año " + anno; String[] meses = {"Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"}; Float[] valores = {0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F}; String unidades = "kWh"; // Recorro la respuesta para coger el mes de cada fecha float total = 0F; for (int i = 0; i < respuesta.length; i++) { int mes_fecha = Integer.parseInt(respuesta[i][0].substring(3, 5)) - 1; // Actualizando los contadores de cada mes y el total valores[mes_fecha] += Float.parseFloat(respuesta[i][1]); total += Float.parseFloat(respuesta[i][1]); } // Y a mostrarlos representa(out, titulo, meses, valores, unidades, total); } else { // Si es grafico mensual o diario, selecciono la columna a visualizar int columna = 0; String unidades = ""; if (tipo.equals("Vpv")) { columna = 1; unidades = "V"; } if (tipo.equals("Iac")) { columna = 3; unidades = "mA"; } if (tipo.equals("Pac")) { columna = 6; unidades = "W"; -95- Proyecto Final de Carrera } if (tipo.equals("Ipv")) { columna = 9; unidades = "mA"; } if (tipo.equals("Energia")) { columna = 10; unidades = "KWh"; } if (periodo.equals("Mensual")) { // El periodo tiene una medición cada 3' de cada dia del mes String titulo = tipo + "(" + unidades + ") en el mes " + mes + "/" + anno; String dias[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31"}; Float valores[] = {0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F}; int contadores[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Recorro la respuesta para coger el dia de cada fecha float total = 0F; int contadorTotal = 0; for (int i = 0; i < respuesta.length; i++) { int dia_fecha = Integer.parseInt(respuesta[i][0].substring(0, 2)) - 1; // Actualizando los contadores de cada mes y el total if (tipo.equals("Energia")) { valores[dia_fecha] = Float.parseFloat(respuesta[i][columna]); } else { valores[dia_fecha] += Float.parseFloat(respuesta[i][columna]); contadores[dia_fecha]++; total += Float.parseFloat(respuesta[i][columna]); contadorTotal++; } } // Y a mostrarlos // Si es Energia, mostramos la diferencia entre dias if (tipo.equals("Energia")) { titulo += " (E-total)"; Float valor_inicial = Float.parseFloat(respuesta[0][columna]); int cuantos_dias=31; if (mes.equals("02")) cuantos_dias=28; if (mes.equals("04")||mes.equals("06")||mes.equals("09")||mes.equals("11")) cuantos_dias=30; for (int i = 0; i < cuantos_dias; i++) { Float auxiliar = valores[i]; valores[i] = valores[i] - valor_inicial; valor_inicial = auxiliar; } total = valor_inicial - Float.parseFloat(respuesta[0][columna]); representa(out, titulo, dias, valores, unidades, total); } // Para el resto de tipos, mostramos el promedio else { titulo += " (valores promedio)"; for (int i = 0; i < 31; i++) { if (contadores[i] > 0) { valores[i] = valores[i] / contadores[i]; } } total = total / contadorTotal; representa(out, titulo, dias, valores, unidades, total); -96- J.M.Estepa } } if (periodo.equals("Diario")) { // El periodo tiene una medición cada 1'del dia String titulo = tipo + "(" + unidades + ") en el dia " + dia + "/" + mes + "/" + anno; String horas[] = {"00:00-01:00", "01:00-02:00", "02:00-03:00", "03:00-04:00", "04:00-05:00", "05:00-06:00", "06:00-07:00", "07:00-08:00", "08:00-09:00", "09:00-10:00", "10:00-11:00", "11:00-12:00", "12:00-13:00", "13:00-14:00", "14:00-15:00", "15:00-16:00", "16:00-17:00", "17:00-18:00", "18:00-19:00", "19:00-20:00", "20:00-21:00", "21:00-22:00", "22:00-23:00", "23:00-24:00" }; Float valores[] = {0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F, 0F}; int contadores[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Recorro la respuesta para coger la hora de cada fecha float total = 0F; int contadorTotal = 0; for (int i = 0; i < respuesta.length; i++) { // Cogiendo de cada fecha la hora String hora = respuesta[i][0].substring(11, respuesta[i][0].length() - 6); int hora_fecha = Integer.parseInt(hora); if (contadores[12] > 0 && hora_fecha != 12) { hora_fecha += 12; } // Actualizando los contadores de cada mes y el total if (tipo.equals("Energia")) { valores[hora_fecha] = Float.parseFloat(respuesta[i][columna]); contadores[hora_fecha]++; } else { valores[hora_fecha] += Float.parseFloat(respuesta[i][columna]); contadores[hora_fecha]++; total += Float.parseFloat(respuesta[i][columna]); contadorTotal++; } } // Y a mostrarlos // Si es Energia, mostramos la diferencia entre horas (cuidado con las horas que tienen 0) if (tipo.equals("Energia")) { titulo += " (E-total)"; // Ponemos valor a las horas sin insolación (valores a 0) Float valor_anterior = Float.parseFloat(respuesta[0][columna]); for (int i = 0; i < 24; i++) { if (valores[i] == 0F) { valores[i] = valor_anterior; } valor_anterior = valores[i]; } // Y hacemos que los valores sean la diferencia entre horas Float valor_inicial = Float.parseFloat(respuesta[0][columna]); for (int i = 0; i < 24; i++) { Float auxiliar = valores[i]; valores[i] = valores[i] - valor_inicial; valor_inicial = auxiliar; } total = valor_inicial - Float.parseFloat(respuesta[0][columna]); representa(out, titulo, horas, valores, unidades, total); } // Para el resto de tipos, mostramos el promedio -97- Proyecto Final de Carrera else { titulo += " (valores promedio)"; for (int i = 0; i < 24; i++) { if (contadores[i] > 0) { valores[i] = valores[i] / contadores[i]; } } total = total / contadorTotal; representa(out, titulo, horas, valores, unidades, total); } } } } protected void representa(PrintWriter out, String titulo, String[] nombres, Float[] valores, String unidades, Float total) { // Calculo el valor máximo y el total para la representación Float valorMaximo = 0F; for (int i = 0; i < nombres.length; i++) { if (valorMaximo < valores[i]) { valorMaximo = valores[i]; } } // Imprimo los datos out.println("<h3>" + titulo + "</h3><hr>"); out.println("<table width=100% class=tabla1>"); out.println("<tr><th colspan=2>Medida</th><th>" + unidades + "</th></tr>"); java.text.DecimalFormat formateador = new java.text.DecimalFormat("####0.00"); for (int i = 0; i < nombres.length; i++) { int ancho = (int) ((valores[i] * 100) / valorMaximo); out.println("<tr><td width='10%' height=20 align=center>" + nombres[i] + "</td>"); out.println("<td width='80%' height=20><img src="); if (ancho < 50) { out.println("rojo.gif"); } if (ancho >= 50 && ancho < 75) { out.println("azul.gif"); } if (ancho >= 75) { out.println("verde.gif"); } out.println(" width='" + ancho + "%' height=20></td>"); out.println("<td width='10%' align=center><font size=1>" + formateador.format(valores[i]) + "</td></tr>"); } out.println("<tr><th colspan=2 align=center><b></b></th><th align=center><b>" + formateador.format(total) + "</b></th></tr>"); out.println("<tr><th colspan=3>Respecto del mayor: <img src=rojo.gif height=10>Menos del 50% <img src=azul.gif height=10>Entre 50% y 75% <img src=verde.gif height=10>Más del 75%</th></tr>"); out.println("</table>"); } // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."> /** * Handles the HTTP <code>GET</code> method. * @param request servlet request * @param response servlet response -98- J.M.Estepa */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP <code>POST</code> method. * @param request servlet request * @param response servlet response */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. */ public String getServletInfo() { return "Short description"; } // </editor-fold> } -99- Proyecto Final de Carrera III.X. fv\fotos|camarafotos.htm Página web que presenta un applet de java que permite visualizar las fotos de la estación fotovoltaica <html> <head> <title>Camara de fotos</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="STYLESHEET" type="text/css" href="../../estilos/estilos.css"> </head> <body> <h1>Fotos estación fotovoltaica</h1> <center> Pulse sobre los botones para ver un carrusel de fotografÃas de la estación fotovoltaica<br> <applet height="530" width="480" codebase="../../meteo/fotos" code="camarafotos.class"> <param name=num_fotos value=34> </applet><br> <h5>Fotografias por cortesia de Manuel Castro Gil</h5> </center> </body> </html> -100- J.M.Estepa III.XI. meteo\fotos\camarafotos.class Applet que permite visualizar de forma flexible un número determinado de fotos en forma de carrusel import java.awt.*; import javax.swing.*; import java.awt.event.*; import java.applet.*; // Para AudioClip() import java.net.*; public class camarafotos extends JApplet implements ActionListener{ JButton b1,b2; Pizarra pizarra; Image img; int n=1; URL cb; int numero_fotos; public void init(){ numero_fotos=Integer.parseInt(getParameter("num_fotos")); setLayout(new BorderLayout()); Color fondo=new Color(97,11,94); JPanel panel1=new JPanel(); JPanel panel2=new JPanel(); JPanel panel3=new JPanel(); panel3.setBackground(fondo); panel2.setBackground(fondo); panel1.setBackground(fondo); b2=new JButton("Foto anterior"); panel1.add(b2); b2.addActionListener(this); b1=new JButton("Siguiente foto"); panel1.add(b1); b1.addActionListener(this); pizarra=new Pizarra(); panel2.add(pizarra); pizarra.setSize(480,480); cb=getDocumentBase(); img=getImage(cb,"./"+n+".JPG"); panel3.add(panel1,BorderLayout.NORTH); panel3.add(panel2,BorderLayout.CENTER); add(panel3); } public void actionPerformed(ActionEvent e){ if(e.getSource()==b1){ n++; if(n==numero_fotos+1) n=1; }else{ n--; if(n==0) n=numero_fotos; } img=getImage(cb,"./"+n+".JPG"); pizarra.repaint(); } -101- Proyecto Final de Carrera class Pizarra extends Canvas{ } } public void paint(Graphics g){ g.clearRect(0,0,480,480); int x=0; if(img.getWidth(this)==360) x=(480-360)/2; g.drawImage(img, x, 0,img.getWidth(this),img.getHeight(this), this); } -102- J.M.Estepa III.XII. meteo\historico_coge.jsp Página jsp que permite recoger mediante un formulario la información necesaria para elaborar páginas con los datos de la base de datos de la estación meteotológica. Las opciones recogidas se envían al servlet historico_meteo <%@page contentType="text/html" pageEncoding="UTF-8"%> <html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <head> <title>Histórico central meteorológica</title> <link rel="STYLESHEET" type="text/css" href="../estilos/estilos.css"> </head> <body> <center> <h1>Datos históricos</h1> <h3>Elija las fechas del periodo a mostrar</h3> <form name=fomulario action="../historico_meteo" method=post> <table> <tr><td>Año:</td><td> <select name=anno> <% java.util.Calendar ahora = java.util.Calendar.getInstance(); int annoActual = ahora.get(java.util.Calendar.YEAR); for (int i = 2007; i <= annoActual; i++) { out.println("<option value=" + i + ">" + i + "</option>"); } %> </select> </td></tr> <tr> <td>Primer dia:</td> <td> <select name=dia_inicial> <% for (int i = 1; i < 32; i++) { String dia = "0" + i; out.println("<option value=" + dia.substring(dia.length() - 2, dia.length()) + ">" + i + "</option>"); } %> </select> <select name=mes_inicial> <option value=01>Enero</option> <option value=02>Febrero</option> <option value=03>Marzo</option> <option value=04>Abril</option> <option value=05>Mayo</option> <option value=06>Junio</option> <option value=07>Julio</option> <option value=08>Agosto</option> <option value=09>Septiembre</option> <option value=10>Octubre</option> -103- Proyecto Final de Carrera <option value=11>Noviembre</option> <option value=12>Diciembre</option> </select> </td> </tr> <tr> <td>Último dÃa:</td> <td> <select name=dia_final> <% for (int i = 1; i < 32; i++) { String dia = "0" + i; out.println("<option value=" + dia.substring(dia.length() - 2, dia.length()) + ">" + i + "</option>"); } %> </select> <select name=mes_final> <option value=01>Enero</option> <option value=02>Febrero</option> <option value=03>Marzo</option> <option value=04>Abril</option> <option value=05>Mayo</option> <option value=06>Junio</option> <option value=07>Julio</option> <option value=08>Agosto</option> <option value=09>Septiembre</option> <option value=10>Octubre</option> <option value=11>Noviembre</option> <option value=12>Diciembre</option> </select> </td></tr> <tr> <td> Accion: </td> <td> <input type=radio name="accion" value="Todo" CHECKED>Ver todos los datos recogidos<br> <input type=radio name="accion" value="Resumen">Resumen dia a dia<br> <input type=radio name="accion" value="Tipico">Resumen del periodo<br> </td> </tr> <tr> <td colspan=2 align=center> <input type=submit value="Ver"> </td> </tr> </table> </form> </center> <hr>Se disponen datos meteorológicos desde el 14-Noviembre-2007, excepto el perÃodo comprendido entre el 19-Enero y el 13-Julio de 2009 </body> </html> -104- J.M.Estepa III.XIII. historico_meteo.class Servlet que recibe los datos del formulario meteo\historico_coge.jsp y realiza la acción requerida por el usuario package paquetes; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class historico_meteo extends HttpServlet { protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { // Empezamos a imprimir la página html out.println("<html>"); out.println("<head>"); out.println("<title>Servlet historico_actua</title>"); out.println("<link rel='STYLESHEET' type='text/css' href='./estilos/estilos.css'>"); out.println("</head>"); out.println("<body>"); out.println("<H1>Valores meteorológicos registrados</H1>"); // Recogemos los datos procedentes del formulario historico_meteo.jsp String anno = request.getParameter("anno"); String dia_inicial = request.getParameter("dia_inicial"); String mes_inicial = request.getParameter("mes_inicial"); String dia_final = request.getParameter("dia_final"); String mes_final = request.getParameter("mes_final"); String accion = request.getParameter("accion"); if (Integer.parseInt(anno + mes_final + dia_final) < Integer.parseInt(anno + mes_inicial + dia_inicial)) { out.println("La fecha final debe ser posterior a la fecha inicial"); } else { // Accion: Resumen de los datos del periodo if (accion.equals("Resumen")) { BaseDatos bd = new BaseDatos(); String orden = "SELECT Int([Datos.Fecha]) AS Dia, Parametros.Nombre, Funciones.Nombre, Max(Datos.Valor) AS MáxDeValor, Min(Datos.Valor) AS MÃnDeValor, Sum(Datos.Valor) AS SumaDeValor, Avg(Datos.Valor) AS PromedioDeValor " + "FROM (Datos INNER JOIN Parametros ON Datos.NumParametro = Parametros.NumParametro) INNER JOIN Funciones ON Datos.NumFuncion = Funciones.NumFuncion " + "GROUP BY Datos.NumEstacion, Int([Datos.Fecha]), Parametros.Nombre, Funciones.Nombre " + "HAVING (((Datos.NumEstacion)=627) AND ((Int([Datos.Fecha]))>=Int(#" + mes_inicial + "/" + dia_inicial + "/" + anno + "#) And (Int([Datos.Fecha]))<Int(#" + mes_final + "/" + dia_final + "/" + anno + "#)+1)) " + "ORDER BY Int([Datos.Fecha]), Parametros.Nombre, Funciones.Nombre"; String datos[][] = bd.consulta(orden,anno); // Imprimimos la cabecera out.println("<table class=tabla1 align=center>"); out.println("<tr><th rowspan=2>Dia</th><th colspan=3>Temperatura(ºC)</th><th colspan=2>Lluvia(mm)</th><th>Viento(m/s)</th><th colspan=2>Humedad(%)</th><th colspan=2>Radiacion(W/m2)</th></tr>"); -105- Proyecto Final de Carrera out.println("<tr><th>Max</th><th>Med</th><th>Min</th><th>Acu</th><th>Max</th><th>Max</th><th>M ax</th><th>Med</th><th>Max</th><th>Med</th></tr>"); // Imprimimos los datos java.text.DecimalFormat formateador = new java.text.DecimalFormat("##0.00"); int par = 0; for (int fila = 0; fila < datos.length; fila = fila + 18) { if (par == 0) { par = 1; out.println("<tr class=filaImpar>"); } else { par = 0; out.println("<tr class=filaPar>"); } out.println("<td>" + datos[fila + 0][0].substring(0, 11) + "</td>"); out.println("<td>" + formateador.format(Float.parseFloat(datos[fila + 12][3])) + "</td>"); out.println("<td>" + formateador.format(Float.parseFloat(datos[fila + 13][6])) + "</td>"); out.println("<td>" + formateador.format(Float.parseFloat(datos[fila + 14][4])) + "</td>"); out.println("<td>" + formateador.format(Float.parseFloat(datos[fila + 4][5])) + "</td>"); out.println("<td>" + formateador.format(Float.parseFloat(datos[fila + 4][3])) + "</td>"); out.println("<td>" + formateador.format(Float.parseFloat(datos[fila + 15][3])) + "</td>"); out.println("<td>" + formateador.format(Float.parseFloat(datos[fila + 3][3])) + "</td>"); out.println("<td>" + formateador.format(Float.parseFloat(datos[fila + 3][6])) + "</td>"); out.println("<td>" + formateador.format(Float.parseFloat(datos[fila + 10][3])) + "</td>"); out.println("<td>" + formateador.format(Float.parseFloat(datos[fila + 11][6])) + "</td>"); out.println("</tr>"); } out.println("</table>"); // Hago el gráfico de algo mediante el applet (por ejemplo la Tª máxima) out.println("<H1>Gráficos</H1>"); out.println("<center>"); out.println("<applet codebase='meteo' code='graficoXY.class' width=600 height=200>"); out.println("<param name='Titulo' value='Temperatura máxima diaria'>"); // Si hay muchos datos, no muestro rotulos if ((datos.length / 18) < 20) { out.println("<param name='MostrarX' value='SI'>"); out.println("<param name='MostrarY' value='SI'>"); } else { out.println("<param name='MostrarX' value='NO'>"); out.println("<param name='MostrarY' value='NO'>"); } String x = ""; String y = ""; for (int fila = 0; fila < datos.length; fila = fila + 18) { x += datos[fila + 0][0].substring(8, 10) + "#"; y += formateador.format(Float.parseFloat(datos[fila + 12][3])) + "#"; } // Cambio las comas por puntos para el Float y = y.replace(',', '.'); // Quito la última # x = x.substring(0, x.length() - 1); y = y.substring(0, y.length() - 1); out.println("<param name='ValoresX' value='" + x + "'>"); out.println("<param name='ValoresY' value='" + y + "'>"); out.println("</applet>"); // Temperatura minima -106- J.M.Estepa out.println("<applet codebase='meteo' code='graficoXY.class' width=600 height=200>"); out.println("<param name='Titulo' value='Temperatura mÃnima diaria'>"); if ((datos.length / 18) < 20) { out.println("<param name='MostrarX' value='SI'>"); out.println("<param name='MostrarY' value='SI'>"); } else { out.println("<param name='MostrarX' value='NO'>"); out.println("<param name='MostrarY' value='NO'>"); } x = ""; y = ""; for (int fila = 0; fila < datos.length; fila = fila + 18) { x += datos[fila + 0][0].substring(8, 10) + "#"; y += formateador.format(Float.parseFloat(datos[fila + 14][4])) + "#"; } y = y.replace(',', '.'); x = x.substring(0, x.length() - 1); y = y.substring(0, y.length() - 1); out.println("<param name='ValoresX' value='" + x + "'>"); out.println("<param name='ValoresY' value='" + y + "'>"); out.println("</applet>"); out.println("</center>"); } // Accion: Ver todos los datos del periodo if (accion.equals("Todo")) { BaseDatos bd = new BaseDatos(); String cab = "SELECT DISTINCT (Datos.NumParametro & '-' & Datos.NumFuncion) AS Codigo, Parametros.Abreviatura, Funciones.Nombre, Parametros.Unidad " + "FROM Funciones INNER JOIN (Datos INNER JOIN Parametros ON Datos.NumParametro = Parametros.NumParametro) ON Funciones.NumFuncion = Datos.NumFuncion " + "GROUP BY Parametros.Abreviatura, Funciones.Nombre, Parametros.Unidad, Datos.NumEstacion, Datos.Fecha, Datos.NumParametro, Datos.NumFuncion " + "HAVING (((Datos.NumEstacion)=627) AND ((Datos.Fecha)>=#" + mes_inicial + "/" + dia_inicial + "/" + anno + "# And (Datos.Fecha)<=#" + mes_final + "/" + dia_final + "/" + anno + "#+1) AND ((Datos.NumParametro)>1)) " + "ORDER BY (Datos.NumParametro & '-' & Datos.NumFuncion);"; String dat = "TRANSFORM First(Datos.Valor) AS PrimeroDeValor " + "SELECT Datos.Fecha " + "FROM Datos " + "WHERE (((Datos.Fecha)>=#" + mes_inicial + "/" + dia_inicial + "/" + anno + "# And (Datos.Fecha)<#" + mes_final + "/" + dia_final + "/" + anno + "#+1) AND ((Datos.NumEstacion)=627) AND ((Datos.NumParametro)>1)) " + "GROUP BY Datos.Fecha " + "ORDER BY Datos.Fecha, '' & [Datos].[NumParametro] & '-' & [datos].[NumFuncion] " + "PIVOT '' & [Datos].[NumParametro] & '-' & [datos].[NumFuncion];"; String cabeceras[][] = bd.consulta(cab,anno); String datos[][] = bd.consulta(dat,anno); // Por si quiere los datos en Excel String camino = request.getRealPath("/"); String cabecera[] = new String[cabeceras.length + 1]; cabecera[0] = "Fecha"; for (int i = 0; i < cabeceras.length; i++) { cabecera[i + 1] = cabeceras[i][1] + "(" + cabeceras[i][2] + ")"; } -107- Proyecto Final de Carrera EscritorExcel ficheroExcel = new EscritorExcel(cabecera, datos, "Datos de la Estación meteorologica de la ETSII de la UNED", out, camino); // Por si quiere los datos en BUFR Bufr bufr = new Bufr(out, camino); // Imprimimos la cabecera out.println("<br><table class=tabla1 align=center>"); for (int i = 1; i < 4; i++) { out.println("<tr>"); if (i == 1) { out.println("<th>Fecha</th>"); } if (i == 2) { out.println("<th>Dia</th>"); } if (i == 3) { out.println("<th>Hora</th>"); } for (int j = 0; j < cabeceras.length; j++) { out.println("<th>" + cabeceras[j][i] + "</th>"); } out.println("</tr>"); } // Imprimimos los datos java.text.DecimalFormat formateador = new java.text.DecimalFormat("##0.00"); int par = 0; for (int fila = 0; fila < datos.length; fila++) { if (par == 0) { par = 1; out.println("<tr class=filaImpar>"); } else { par = 0; out.println("<tr class=filaPar>"); } out.println("<td align=center>" + datos[fila][0] + "</td>"); for (int campo = 1; campo < datos[0].length; campo++) { out.println("<td align=center>" + formateador.format(Float.parseFloat(datos[fila][campo])) + "</td>"); } out.println("</tr>"); } out.println("</table>"); } // Accion: Visualizar los valores del periodo if (accion.equals("Tipico")) { BaseDatos bd = new BaseDatos(); java.text.DecimalFormat formateador = new java.text.DecimalFormat("##0.00"); out.println("<h2>Resumen del "+dia_inicial+"/"+mes_inicial+"/"+anno+ " al "+dia_final+"/"+mes_final+"/"+anno+"</h2>"); // Tabla de datos out.println("<table align=center>"); out.println("<tr><th></th><th>Parametro</th><th>Valor</th><th></th><th>Dia</th></tr>"); // Lluvia caida en el total del periodo String orden = "SELECT Sum(Valor) FROM Datos "+ "WHERE Int(Fecha)>=Int(#" + mes_inicial + "/" + dia_inicial + "/" + anno + "#) "+ -108- J.M.Estepa "AND Int(Fecha)<Int(#" + mes_final + "/" + dia_final + "/" + anno + "#)+1 " + "AND NumParametro=4 AND NumFuncion=2"; String lluvia[][] = bd.consulta(orden,anno); out.println("<tr><td><img src=./meteo/lluvia.JPG></td><td>Lluvia recogida</td><td>"+formateador.format(Float.parseFloat(lluvia[0][0]))+"</td><td>mm</td></tr>"); // Temperaturas máxima y minima orden = "SELECT Valor, Fecha FROM Datos "+ "WHERE Int(Fecha)>=Int(#" + mes_inicial + "/" + dia_inicial + "/" + anno + "#) "+ "AND Int(Fecha)<Int(#" + mes_final + "/" + dia_final + "/" + anno + "#)+1 " + "AND NumParametro=6 ORDER BY Valor"; String temperatura[][] = bd.consulta(orden,anno); out.println("<tr><td><img src=./meteo/tempmin.JPG></td><td>Temperatura mÃnima</td><td>"+formateador.format(Float.parseFloat(temperatura[0][0]))+"</td><td>ºC</td><td>"+temp eratura[0][1]+"</td></tr>"); out.println("<tr><td><img src=./meteo/tempmax.JPG></td><td>Temperatura máxima</td><td>"+formateador.format(Float.parseFloat(temperatura[temperatura.length1][0]))+"</td><td>ºC</td><td>"+temperatura[temperatura.length-1][1]+"</td></tr>"); // Radiacion solar orden = "SELECT Valor, Fecha FROM Datos "+ "WHERE Int(Fecha)>=Int(#" + mes_inicial + "/" + dia_inicial + "/" + anno + "#) "+ "AND Int(Fecha)<Int(#" + mes_final + "/" + dia_final + "/" + anno + "#)+1 " + "AND NumParametro=5 ORDER BY Valor desc"; String radiacion[][] = bd.consulta(orden,anno); out.println("<tr><td><img src=./meteo/radiacion.JPG></td><td>Máxima radiacion solar</td><td>"+formateador.format(Float.parseFloat(radiacion[0][0]))+"</td><td>W/m2</td><td>"+radiaci on[0][1]+"</td></tr>"); // Velocidad del viento orden = "SELECT Valor, Fecha FROM Datos "+ "WHERE Int(Fecha)>=Int(#" + mes_inicial + "/" + dia_inicial + "/" + anno + "#) "+ "AND Int(Fecha)<Int(#" + mes_final + "/" + dia_final + "/" + anno + "#)+1 " + "AND NumParametro=7 ORDER BY Valor desc"; String viento[][] = bd.consulta(orden,anno); out.println("<tr><td><img src=./meteo/viento.JPG></td><td>Máxima ráfaga de viento</td><td>"+formateador.format(Float.parseFloat(viento[0][0])*3.6)+"</td><td>Km/h</td><td>"+vient o[0][1]+"</td></tr>"); // Presión atmosférica máxima y minima orden = "SELECT Valor, Fecha FROM Datos "+ "WHERE Int(Fecha)>=Int(#" + mes_inicial + "/" + dia_inicial + "/" + anno + "#) "+ "AND Int(Fecha)<Int(#" + mes_final + "/" + dia_final + "/" + anno + "#)+1 " + "AND NumParametro=15 ORDER BY Valor"; String presion[][] = bd.consulta(orden,anno); out.println("<tr><td><img src=./meteo/presmin.JPG></td><td>Presión atmosférica mÃnima</td><td>"+formateador.format(Float.parseFloat(presion[0][0]))+"</td><td>mb</td><td>"+presion[0][ 1]+"</td></tr>"); out.println("<tr><td><img src=./meteo/presmax.JPG></td><td>Presión atmosférica máxima</td><td>"+formateador.format(Float.parseFloat(presion[presion.length1][0]))+"</td><td>mb</td><td>"+presion[presion.length-1][1]+"</td></tr>"); // Cierro la tabla out.println("</table>"); } // Cerramos la pagina html out.println("</body>"); -109- Proyecto Final de Carrera out.println("</html>"); } } catch (Exception e) { out.println("No hay datos (historico_meteo) "); } } // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."> /** * Handles the HTTP <code>GET</code> method. * @param request servlet request * @param response servlet response */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Handles the HTTP <code>POST</code> method. * @param request servlet request * @param response servlet response */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); } /** * Returns a short description of the servlet. */ public String getServletInfo() { return "Short description"; } // </editor-fold> } -110- J.M.Estepa III.XIV. meteo\graficoXY.class Appet java que permite representar parámetros en un gráfico de 2 ejes. Es configurable respecto del número de valores a representar y se utiliza para mostrar tempèraturas máximas y mínimas en la representación de valores diarios import java.awt.*; import java.awt.event.*; import java.applet.*; public class graficoXY extends Applet{ String titulo=""; String mostrarX=""; String valoresX[]; String mostrarY=""; double valoresY[]; int alto=0; int ancho=0; Image dobleBuffer; Graphics miCG; public void init (){ titulo=getParameter("Titulo"); mostrarX=getParameter("MostrarX"); if(mostrarX.equals("SI")){ String v1=getParameter("ValoresX"); String [] v2=v1.split("#"); valoresX=new String[v2.length]; for(int i=0;i<v2.length;i++){ valoresX[i]=v2[i]; } } mostrarY=getParameter("MostrarY"); String v3=getParameter("ValoresY"); String [] v4=v3.split("#"); valoresY=new double[v4.length]; for(int i=0;i<v4.length;i++){ valoresY[i]=Double.parseDouble(v4[i]); } alto=this.getHeight(); ancho=this.getWidth()-20; dobleBuffer = createImage (ancho+20,alto); miCG = dobleBuffer.getGraphics (); //Limpia la pantalla miCG.clearRect (0, 0, ancho, alto); lineas (); // Ahora muestra la imagen de golpe repaint (); } -111- Proyecto Final de Carrera public void paint (Graphics g){ // Lo se tiene que presentar la imagen del buffer g.drawImage (dobleBuffer, 0, 0, this); } public void lineas (){ // TITULO miCG.setColor (Color.red); miCG.setFont (new Font ("Arial", Font.BOLD, 18)); miCG.drawString (titulo, 0, 15); // Lineas de Ymáximo e Ymínimo miCG.setColor (Color.black); miCG.setFont (new Font ("Arial", Font.PLAIN, 10)); double min=minimo(); miCG.drawLine(0,alto-20,ancho,alto-20); miCG.drawString("min="+min,0,alto-20); double max=maximo(); miCG.drawLine(0,30,ancho,30); miCG.drawString("max="+max,0,30); // GRAFICO double factor=(alto-50)/(max-min); int x1=70; int y1=alto-20-(int)((valoresY[0]-min)*factor); for(int i=0;i<valoresY.length;i++){ int x2=70+((ancho-70)/(valoresY.length-1))*i; int y2=alto-20-(int)((valoresY[i]-min)*factor); if(mostrarY.equals("SI")){ miCG.setColor (Color.red); miCG.drawString(""+valoresY[i],x2-12,y2-3); } if(mostrarX.equals("SI")){ miCG.setColor (Color.red); miCG.drawString(valoresX[i],x2-12,alto-10); } miCG.setColor (Color.blue); miCG.fillOval(x2-2,y2-2,4,4); miCG.drawLine (x1,y1,x2,y2); x1=x2;y1=y2; } } double minimo(){ double minimo=valoresY[0]; for(int i=0;i<valoresY.length;i++){ if(valoresY[i]<minimo) minimo=valoresY[i]; } return minimo; } } double maximo(){ double maximo=valoresY[0]; for(int i=0;i<valoresY.length;i++){ if(valoresY[i]>maximo) maximo=valoresY[i]; } return maximo; } -112- J.M.Estepa III.XV. meteo\fotos\camarafotos.htm Página web que permite mostrar las fotos de la estación fotovoltaica mediante el applet camarafotos.class (su código ya ha sido mostrado en el apartado II.X) <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="STYLESHEET" type="text/css" href="../../estilos/estilos.css"> </head> <body> <h1>Fotos estación meteorológica</h1> <center> Pulse sobre los botones para ver un carrusel de fotografias de la estación meteorológica<br> <applet code=camarafotos.class width=480 height=530> <param name=num_fotos value=31> </applet><br> <h5>FotografÃas por cortesia de Manuel Castro Gil</h5> </center> </body> </html> -113- Proyecto Final de Carrera III.XVI. BaseDatos.class Servlet que permite abrir la base de datos de la estación meteorológica y devolver el resultado de una consulta a la misma mediante una orden SQL. Para su funcionamiento necesita de la correcta localización del fichero *.mdb correspondiente mediante el fichero de configuración C:\PFC_JMEstepa.conf package paquetes; import java.sql.*; import java.util.Vector; import java.io.*; public class BaseDatos { String directorioBD; public BaseDatos() throws Exception { // Leo del fichero de configuración dónde está la base de datos FileReader fr = new FileReader("C:/PFC_JMEstepa.conf"); BufferedReader br = new BufferedReader(fr); String linea = br.readLine(); directorioBD = ""; while (linea != null) { if (linea.contains("Directorio_Meteorologico")) { String s[] = linea.split("="); directorioBD = s[1]; } linea = br.readLine(); } br.close(); fr.close(); // Compruebo si se ha cambiado de año // y no está dividida la la base de datos (no existe la BD del año anterior) // entonces se divide en 2 partes java.util.Calendar ahora = java.util.Calendar.getInstance(); String annoActual = "" + ahora.get(java.util.Calendar.YEAR); int annoAnterior = Integer.parseInt(annoActual) - 1; File f = new File(directorioBD + "MeteoStation" + annoAnterior + ".mdb"); // Si no existe la base de datos del año anterior if (!f.exists()) { // se hace una copia de MeteoStation.mdb byte[] buffer = new byte[2048]; InputStream in = new FileInputStream(directorioBD + "MeteoStation.mdb"); OutputStream out = new FileOutputStream(directorioBD + "MeteoStation" + annoAnterior + ".mdb"); int amountRead; while (true) { amountRead = in.read(buffer); if (amountRead == -1) { break; } out.write(buffer, 0, amountRead); } -114- J.M.Estepa in.close(); out.close(); Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // Elimino los datos del año actual de la BD del año anterior String s1 = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=" + directorioBD + "MeteoStation" + annoAnterior + ".mdb"; Connection c1 = java.sql.DriverManager.getConnection(s1, "", ""); Statement o1 = c1.createStatement(); o1.executeUpdate("DELETE FROM Datos WHERE fecha>=#01/01/" + annoActual + "#"); o1.close(); c1.close(); // Elimino los datos del año anterior del fichero MeteoStation.mdb String s2 = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=" + directorioBD + "MeteoStation.mdb"; Connection c2 = java.sql.DriverManager.getConnection(s2, "", ""); Statement o2 = c2.createStatement(); o2.executeUpdate("DELETE FROM Datos WHERE fecha<#01/01/" + annoActual + "#"); o2.close(); c2.close(); } } public String[][] consulta(String sql, String anno) { try { // Conexion con la Base de datos de Access correspondiente String fichero = "MeteoStation"; java.util.Calendar ahora = java.util.Calendar.getInstance(); String annoActual = "" + ahora.get(java.util.Calendar.YEAR); if (!annoActual.equals(anno)) { fichero = fichero + anno; } Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); String server = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=" + directorioBD + fichero + ".mdb"; Connection conexion = java.sql.DriverManager.getConnection(server, "", ""); Statement orden = conexion.createStatement(); ResultSet rs = orden.executeQuery(sql); ResultSetMetaData metaDatos = rs.getMetaData(); int numCols = metaDatos.getColumnCount(); Vector v = new Vector(); while (rs.next()) { for (int i = 1; i <= numCols; i++) { v.addElement(rs.getString(i)); } } rs.close(); orden.close(); conexion.close(); String matriz[][] = new String[v.size() / numCols][numCols]; for (int fila = 0; fila < (v.size() / numCols); fila++) { for (int i = 0; i < numCols; i++) { -115- Proyecto Final de Carrera matriz[fila][i] = (String) v.elementAt(fila * numCols + i); if (matriz[fila][i].isEmpty()) matriz[fila][i]="0"; } } return matriz; } catch (Exception e) { String matriz[][] = new String[1][1]; matriz[0][0] = "Función consulta()"; return matriz; } } } -116- J.M.Estepa III.XVII. Bufr.class Servlet que permite generar y exportar mediante un hiperenlace un fichero con formato BUFR cuyo contenido son los últimos valores registrados de la estación meteorológica package paquetes; import java.util.Vector; import java.io.*; public class Bufr { public Bufr(PrintWriter out, String camino){ // Localizamos el Directorio Meteorológico // Leo del fichero de configuración dónde está el fichero String directorio=""; try{ FileReader fr = new FileReader("C:/PFC_JMEstepa.conf"); BufferedReader br = new BufferedReader(fr); String linea = br.readLine(); while (linea != null) { if (linea.contains("Directorio_Meteorologico")) { String s[] = linea.split("="); directorio = s[1]; } linea = br.readLine(); } br.close(); fr.close(); }catch(Exception e){ System.out.println("Error 1 en Bufr"); } // Leemos los datos del fichero String primera_linea=""; String ultima_linea=""; try{ FileReader fr=new FileReader(directorio+"DATOSMETEO_Inst.LOG"); BufferedReader br=new BufferedReader(fr); primera_linea=br.readLine(); String leido=""; while(leido!=null){ ultima_linea=leido; leido=br.readLine(); } br.close(); fr.close(); }catch(Exception e){ System.out.println("Error 2 en Bufr"); } // Troceo en campos String t[]=primera_linea.split(";"); String d[]=ultima_linea.split(";"); String datetime=d[0]; // Informacion de los 9 datos a grabar en el BURF // dato[0]=Latitud -117- Proyecto Final de Carrera // dato[1]=Longitud // dato[2]=velocidad del viento // dato[3]=direccion del viento // dato[4]=temperatura // dato[5]=humedad relativa // dato[6]=presion // dato[7]=radiacion solar // dato[8]=lluvia String titulo[]=new String[9]; double dato[]=new double[9]; titulo[0]="Latitud"; dato[0]=40.4515F; titulo[1]="Longitud";dato[1]=-3.7371F; for(int i=1;i<8;i++){ titulo[i+1]=t[i]; dato[i+1]=Double.parseDouble(d[i]); } int escala[]={2,2,1,0,0,0,-1,1,1}; int referencia[]={-9000,-18000,0,0,-99,0,0,0,-1}; int bits[]={15,16,12,9,8,7,14,14,14}; int F[]={0,0,0,0,0,0,0,0,0}; int X[]={5,6,11,11,12,13,7,14,13}; int Y[]={2,2,2,1,23,3,4,35,11}; // Empieza la creación a pedal Vector <Byte>s1=new Vector<Byte>(); // Sección 0 = Indicator Section s1.add((byte)'B');s1.add((byte)'U');s1.add((byte)'F');s1.add((byte)'R'); // BURF s1.add((byte)0);s1.add((byte)0);s1.add((byte)0); // Longitud total del fichero s1.add((byte)3); // Versión=3 // Sección 1 = Identification Section s1.add((byte)0);s1.add((byte)0);s1.add((byte)18); // Longitud de la sección 1 (18 bytes) s1.add((byte)0); // 0=Standar s1.add((byte)0);s1.add((byte)58); // 0-58=USNavy FNMOC s1.add((byte)0); // Sin utilizar s1.add((byte)0); // No hay Seccion 2 (lo habitual) s1.add((byte)0);s1.add((byte)0); // 0=Datos tomados en superficie s1.add((byte)9);s1.add((byte)1); // 9=versión master de tabla; 1=versión local de tablas // La hora y el minuto de la observación datetime=datetime.replace(' ','/'); datetime=datetime.replace(':','/'); String trozos[]=datetime.split("/"); // Rompo el DateTime en sus componentes int mes=Integer.parseInt(trozos[1]); int dia=Integer.parseInt(trozos[0]); int anno=Integer.parseInt(trozos[2])-2000; int hora=Integer.parseInt(trozos[3]); int minuto=Integer.parseInt(trozos[4]); s1.add((byte)anno);s1.add((byte)mes);s1.add((byte)dia);s1.add((byte)hora);s1.add((byte)minuto); s1.add((byte)0); // Longitud de la sección 1 es siempre par (en este caso 18) // Seccion 2 = Optional Section // Seccion vacia // Seccion 3 = Data Description // Describe los datos que va a grabar -118- J.M.Estepa s1.add((byte)0);s1.add((byte)0);s1.add((byte)26); // Longitud de la sección = 3+1+2+1+9*2+1=26 s1.add((byte)0); // Este byte vale siempre 0 s1.add((byte)0);s1.add((byte)9); // Vamos a grabar 9 datos s1.add((byte)128); // 128->Datos observados y no comprimidos // Estos son los 9 datos for(int i=0;i<9;i++){ s1.add((byte)X[i]);s1.add((byte)Y[i]); } s1.add((byte)0); // Tiene que haber un número par de bytes, añado uno // Seccion 4 = Data // Contiene el valor de los datos transmitidos s1.add((byte)0);s1.add((byte)0);s1.add((byte)18); // Longitud de la sección = 3+1+(15+16+12+9+8+7+14+14+14)/8=3+1+14=18 (sobran 3 bits) s1.add((byte)0); // Este byte vale siempre 0 // Este Vector va a contener los 1 y 0 de los datos codificados Vector <Integer>chorizo=new Vector<Integer>(); // Codifico los datos pasándolos al Vector for(int i=0;i<9;i++){ chorizo=codifica(chorizo,dato[i],escala[i],referencia[i],bits[i]); } // Relleno para que el numero de bits sea un multiplo de 8 int resto=chorizo.size()%8; if(resto>0){ for(int i=0;i<8-resto;i++){ chorizo.addElement(0); } } // Y ahora a escribir int bytes_datos=0; int puntero=0; for(int i=0;i<chorizo.size()/8;i++){ int valor=0; for(int j=0;j<8;j++){ valor=valor+(int)chorizo.elementAt(puntero)*(int)Math.pow(2d,(double)(7-j)); puntero++; } bytes_datos++; s1.add((byte)valor); } // Seccion 5 = Final // Contiene 4 '7' para indicar el final s1.add((byte)'7'); s1.add((byte)'7'); s1.add((byte)'7'); s1.add((byte)'7'); // Cuento los bytes y los pongo en la posicion 7 (la 6 del Vector) s1.setElementAt((byte)s1.size(),6);//s1.size() // Creo la matriz de bytes para escribir en el fichero byte[]trama=new byte[s1.size()]; for(int i=0;i<s1.size();i++){ trama[i]=s1.elementAt(i); } -119- Proyecto Final de Carrera try{ // Abro el fichero RandomAccessFile fich=new RandomAccessFile(camino+"ETSII_UNED.BUFR","rw"); // Me desplazo a la posición 0 fich.seek(0L); // Escribo fich.write(trama); // Cierro el fichero fich.close(); }catch(Exception e){ System.out.println("Error 3 en Bufr"); } out.println("<a href=ETSII_UNED.BUFR>Descargar datos actuales en formato BUFR</a><br>"); } Vector codifica(Vector v,double valor,int escala,int referencia,int bits){ // Para codificar, primero se multiplica por 10^escala ... valor=valor*Math.pow(10d,(double)escala); // ... luego se le resta la referencia ... valor=valor-referencia; // ... tomo la parte entera ... int valor_codificar=(int)valor; // ... lo paso a binario ... for(int i=bits-1;i>=0;i--){ if(valor_codificar>=(int)Math.pow(2d,(double)i)){ v.addElement(1); valor_codificar-=(int)Math.pow(2d,(double)i); }else{ v.addElement(0); } } return v; } void ver(byte b){ byte c[]=new byte[8]; for(int i=0;i<8;i++){ int ci=b&(byte)(Math.pow(2d,(double)(7-i))); if(ci!=0) System.out.print("1"); else System.out.print("0"); } System.out.println(""); } byte[] pasaCadenaAHexadecimal(String s){ byte b[]=new byte[s.length()] ; for(int i=0;i<s.length();i++){ char c=s.charAt(i); b[i]=pasaCharAHexadecimal(c); } return b; } -120- J.M.Estepa byte pasaCharAHexadecimal(char c){ byte b=(byte)c; System.out.println(c+" - "+b); return b; } } -121- Proyecto Final de Carrera III.XVIII. EscritorExcel.class Servlet que permite generar y exportar un fichero con formato excel (xls) con los valores que se le pasen como parámetros package paquetes; import java.io.*; import jxl.*; import jxl.write.*; // Genera un documento en formato excel con los datos que se le envian public class EscritorExcel { String nombreFichero = ""; EscritorExcel(String c[], String d[][], String encabezamiento_hoja, PrintWriter out, String camino) { try { nombreFichero = camino + "ETSII_UNED_renovables.xls"; WritableWorkbook libro = Workbook.createWorkbook(new File(nombreFichero)); WritableSheet hoja = libro.createSheet("Datos", 0); // Las columnas celdas se numeran asi: A=0, B=1, ... // Las filas se numeran asi: 1=0, 2=1, ... // Imprimo en A1 el encabezamiento que me han dado Label label = new Label(0, 0, encabezamiento_hoja); hoja.addCell(label); // Imprimo en la fila 2 las cabeceras for (int i = 0; i < c.length; i++) { Label etiqueta = new Label(i, 1, c[i]); hoja.addCell(etiqueta); } // Imprimo a partir de la fila 3 los datos for (int i = 0; i < d.length; i++) { // Escribo primero siempre la fecha Label fecha = new Label(0, i + 2, d[i][0]); hoja.addCell(fecha); // Luego todos los datos como numeros for (int j = 1; j < d[i].length; j++) { jxl.write.Number number = new jxl.write.Number(j, i + 2, Double.parseDouble(d[i][j])); hoja.addCell(number); } } libro.write(); libro.close(); out.println("<img src=excel.gif><a href=ETSII_UNED_renovables.xls> Descargar datos en formato Excel </a><img src=excel.gif><br>"); } catch (Exception e) { out.println("No hay datos (EscritorExcel) "); } } } -122- J.M.Estepa III.XIX. LectorExcel.class Servlet que permite leer y pasar al programa que cree un objeto de este tipo los datos procedentes de un fichero excel. Normalmente se utiliza con los ficheros xls generados por la estación fotovoltaica. Precisa de la correcta configuración del fichero C:\PFC_JMEstepa.conf package paquetes; import java.io.*; import jxl.*; public class LectorExcel { public String[][] lee(String ficheroExcel) { // Creo una matriz salvaje para recoger datos try { // Leo del fichero de configuración dónde está la base de datos FileReader fr = new FileReader("C:/PFC_JMEstepa.conf"); BufferedReader br = new BufferedReader(fr); String linea = br.readLine(); String directorioHC = ""; while (linea != null) { if (linea.contains("Directorio_Fotovoltaico")) { String s[] = linea.split("="); directorioHC = s[1]; } linea = br.readLine(); } br.close(); fr.close(); // Si es un fichero diario, bajo a la carpeta Daily if (ficheroExcel.length() == 14) { directorioHC += "Daily/"; } File f = new File(directorioHC, ficheroExcel); if (f.exists()) { // Declaro un workbook con el archivo Workbook workbook = Workbook.getWorkbook(new File(directorioHC + ficheroExcel)); // Tomo la primera hoja Sheet sheet = workbook.getSheet(0); // Leo la cantidad de filas con datos Cell celda = sheet.getCell(0, 0); int filas = Integer.parseInt(celda.getContents()); // Elaboro la respuesta -ojo, va como getCell(columna, fila)int columnas = 0; if (ficheroExcel.contains("SDT_")) { columnas = 2; } else { columnas = 13; } String[][] respuesta = new String[filas][columnas]; for (int i = 0; i < filas; i++) { // Recojo los datos (y pongo el caracter decimal correcto) for (int j = 0; j < columnas; j++) { celda = sheet.getCell(j, i + 7); String contenido = "" + celda.getContents(); -123- Proyecto Final de Carrera contenido = contenido.replace(',', '.'); respuesta[i][j] = contenido; } } /* // En el caso que quisiera obtener el tipo de dato que contiene la celda: String stringa1 = null; double numberb2 = 0; Date datec2 = null; Cell a1 = sheet.getCell(0,0); Cell b2 = sheet.getCell(1,1); Cell c2 = sheet.getCell(2,1); if (a1.getType() == CellType.LABEL){ LabelCell lc = (LabelCell) a1; stringa1 = lc.getString(); } if (b2.getType() == CellType.NUMBER){ NumberCell nc = (NumberCell) b2; numberb2 = nc.getValue(); } if (c2.getType() == CellType.DATE){ DateCell dc = (DateCell) c2; datec2 = dc.getDate(); } */ // Finalmente cerramos el workbook y liberamos la memoria workbook.close(); return respuesta; } else { String respuesta_mala[][] = new String[1][1]; respuesta_mala[0][0] = "No hay datos (LectorExcel)"; return respuesta_mala; } } catch (Exception ex) { String[][] respuesta_mala = new String[1][1]; respuesta_mala[0][0] = "No hay datos (LectorExcel) "; return respuesta_mala; } } } -124- J.M.Estepa III.XX. LeeMeteoActual.class Servlet que permite leer los valores correspondiente al fichero LOG, el cual contiene los valores instantáneos leidos de la estación meteorológica. Sirve para mostrar los valores meteorológicos más recientes en la portada de la aplicación package paquetes; import java.io.*; public class LeeMeteoActual { String directorio = ""; String primera_fila; String ultima_fila; public LeeMeteoActual() throws Exception { // Leo del fichero de configuración dónde está el fichero FileReader fr = new FileReader("C:/PFC_JMEstepa.conf"); BufferedReader br = new BufferedReader(fr); String linea = br.readLine(); while (linea != null) { if (linea.contains("Directorio_Meteorologico")) { String s[] = linea.split("="); directorio = s[1]; } linea = br.readLine(); } directorio += "DATOSMETEO_Inst.LOG"; br.close(); fr.close(); // Leo la primera fila y la última del fichero de datos fr = new FileReader(directorio); br = new BufferedReader(fr); linea = br.readLine(); primera_fila = linea; while (linea != null) { ultima_fila = linea; linea = br.readLine(); } br.close(); fr.close(); // Por si hay muchos datos, reescribo el fichero FileWriter fw = new FileWriter(directorio); BufferedWriter bw = new BufferedWriter(fw); bw.write(primera_fila); bw.newLine(); bw.write(ultima_fila); bw.newLine(); bw.close(); fw.close(); } -125- Proyecto Final de Carrera public String[] cabecera() throws Exception { String c[] = primera_fila.split(";"); for (int i = 0; i < c.length; i++) { c[i] = c[i].trim(); } return c; } public String[] datos() throws Exception { String d[] = ultima_fila.split(";"); return d; } } -126- J.M.Estepa IV. Instalación de servicios en Windows Debido a que algunos programas antivirus consideran al programa NTServiceInstaller como “peligroso” (modifica claves de registro y ejecuta tareas en segundo plano), se puede realizar la instalación de los programas siguiendo el siguiente procedimiento: 1.- Descargar las herramientas del kit de recursos de Microsoft Windows. Este programa una vez descomprimido proporciona los programas instsrv.exe y srvany.exe 2.- Crear desde la linea de comandos el servicio tecleando la instrucción: instsrv <nombre_servicio> <archivo.exe> srvany.exe Por ejemplo, si tratáramos de ejecutar como servicio TeleTrans-w3k.exe (el programa que pide datos a la estación meteorológica) que está instalado en c:\dirw3k, la instrucción sería: Instrsrv W3K c:\dirw3k\TeleTrans-w3k.exe srvany.exe 3.- Añadir parámetros al servicio (CUIDADO: ESTE PASO PUEDE SER PELIGROSO PARA EL EQUIPO. Conviene realizar una copia de seguridad del registro y cuidar los parámetros que se modifican) o Ejecutar el comando regedit o HKEY_LOCAL_MACHINE-SYSTEM-CURRENTCONTROLSET-SERVICES o Desplazarse hasta la clave del servicio (ej:W3K) y hacer los siguientes ajustes: o Modificar la clave ImagePath para que su contenido sea el camino absoluto para ejecutar srvany.exe o Añadir la clave (carpeta) Parameters o Añadir un valor de cadena en la clave Parameters llamado Application con el valor del camino completo hasta el programa correspondiente, en nuestro ejemplo Application=c:\dirw3k\TeleTrans-w3k.exe o Añadir un valor de cadena en la clave Parameters llamado AppDirectory con la carpeta donde se debe ejecutar el programa. En nuestro ejemplo AppDirectory=c:/dirw3k o o o o o o 4.- Configurar el servicio. Accedemos al servicio mediante Inicio-Panel de Control-Herramientas AdministrativasServicios. Marcamos el servicio (en el ejemplo W3K) y con el botón derecho accedemos a sus propiedades. En la pestaña de “Iniciar sesión” marcamos la casilla “Permitir que el servicio interactue con el escritorio”. Arrancamos el servicio y se mostrará el programa como si se ejecutara de forma normal. Configurarlo para que se ejecute tal como deseamos Parar el servicio Acceder a sus propiedades y desmarcar la casilla de “Permitir que el servicio interactue con el escritorio”. Indicar que el servicio se ejecute de forma automática 6.- Eliminación de servicios. Si fuera necesario, se podría eliminar un servicio mediante el comando Instsvr <nombre_servicio> REMOVE En nuestro ejemplo teclearíamos instsvr W3K remove -127- Proyecto Final de Carrera A modo de ejemplo, se relata el proceso paso a paso para instalar un programa compactado en formato jar como un servicio Condiciones de partida: • • • • Los programas instsrv.exe y srvany.exe están en c:\windows\ Java.exe está en c:\Archivos de programa\java\jre1.6.0_05\bin\ La aplicación a transformar en servicio está en c:\aplic_nav\buscador.jar El servicio se llamará busca A.- Crear servicio (desde línea de comandos): c:\windows\Instsrv busca “c:\Archivos de programa\java\jre1.6.0_05\bin\java.exe” c:\windows\srvany.exe B.- Editar el registro del sistema Regedit HKEY_LOCAL_MACHINE-SYSTEM-CURRENTCONTROLSET-SERVICES-busca B.1.- Cambiar el programa lanzador ImagePath=D:\Chema\Proyecto\InstaladorServiciosWindows\srvany.exe B.2.- Crear el entorno Crear una nueva clave en busca llamada Parameters B.3.- Crear 2 valores alfanumericos fijos dentro de Parameters Application=C:\Archivos de programa\Java\jre1.6.0_05\bin\java.exe -jar buscador.jar AppDirectory=C:\aplic_nav C.- Probar el entorno Acceder a los servicios a través del Panel de Control-Herramientas Administrativas-Servicios Elegir el servicio llamado “busca” Propiedades-Permitir a los servicios que interactúen con el escritorio Arrancar el servicio y probar su funcionamiento Parar el servicio Quitar la propiedad de permitir a los servicios interactuar con el escritorio Poner el servicio con arranque automático D.- Rearrancar el equipo para probar el funcionamiento E.- En el caso de que fuera necesario eliminar el servicio: Parar el servicio Salir a la linea de comandos con cmd c:\windows\Instsrv busca remove -128- J.M.Estepa V. Instalación de la aplicación El proceso de instalación de la aplicación se realizó en la segunda quincena del mes de septiembre de 2010. En principio todos el software se implementó en el ordenador meteo.ieec.uned.es (IP=62.204.201.181) del laboratorio de Ingeniería Eléctrica, Electrónica y de Control de la Escuela de Ingenieros Industriales de la UNED. En este proceso se anotaron las siguientes incidencias: Proceso Instalación del servidor de servlets Tomcat Gestión del servidor Tomcat Instalación de los programas de anteriores proyectos como servicios Inexistencia de datos fotovoltaicos utilizables por la antiguo sistema de monitorización desde el 14 de abril de 2009 Posibilidad de incidencias en los datos de respaldo Incidencia-Causa Los puertos 80 y 8080 (estándar para servidores web) del equipo estaban ocupados por aplicaciones instaladas anteriormente (IIS y repositorio de objetos de aprendizaje de electrónica) Necesidad de poder desplegar aplicaciones y gestionar el servicio sin necesidad de entrar físicamente en el servidor meteo El antivirus de meteo.ieec.uned.es marcó como posible virus al programa NTServiceInstaller procediendo a su bloqueo No se llevaba a cabo la serialización de los ficheros xls por no tener derechos de escritura en la carpeta contenedora de las páginas web del antiguo sistema No existen copias de seguridad de los datos. En caso de avería del equipo (o equipos) que mantienen la bases de datos meteorológicas y los ficheros xls fotovoltaicos las aplicaciones pueden ser reinstaladas, pero los datos se perderían Solución Instalar el servidor de servlets en el puerto 8086. De esta forma la aplicación será accesible en la dirección http://meteo.ieec.uned.es:8086/PFC_JMEstepa Creación de un usuario con nombre ‘meteoieec’ y contraseña ‘meteoieec’ que permite realizar labores de mantenimiento del servidor de forma remota. Se accede en la dirección http://meteo.ieec.uned.es:8086 , pulsando el enlace ‘Tomcat Manager’ Realizar la instalación de los programas como servicios con el kit de recursos de Windows Server 2003 tal como se indica en el Anexo IV Dar permisos de escritura al cliente ftp Recuperar de forma manual todos los datos de acuerdo al procedimiento seguido en el siguiente apartado de este apéndice Establecimiento de una política de copias de seguridad (backup) de los ficheros contenidos en el directorio meteorológico y fotovoltaico. Basta hacer copias periódicas de los mismos Creación manual de ficheros de datos de la estación fotovoltaica Cuando se observe en applet de la representación gráfica de los datos de la estación fotovoltaica accesible desde la página http://meteo.ieec.uned.es/www_Usumeteo4/AppletPFV.html que no hay datos porque faltan los ficheros manejables por la antigua aplicación (se muestra el mensaje de error FileNotFoundException) puede ser porque la estación no ha transmitido la información o porque el programa de serialización (LectorArchivosExcel.jar) no ha funcionado correctamente Si existiese el fichero xls transmitido por la estación, se puede recuperar de manera manual. Para ello hay que realizar las siguientes operaciones: 1. Parar el servicio llamado LeeArchivoExcel mediante la secuencia Inicio-Panel de Control-Herramientas Administrativas-Servicios-Marcar el servicio-Detener 2. Arrancar de forma manual la aplicación LeeArchivoExcel.jar que está en el escritorio de meteo. De esta forma se puede operar sobre las opciones del programa -129- Proyecto Final de Carrera 3. Ejecutar desde el menú de LeeArchivoExcel.jar la siguiente secuencia: Archivo-Leer archivos de Excel-Buscar en el directorio de la estación fotovoltaica (c:\Archivos de programa\SMA Regelsysteme\Sunny Data Control\Plants\DIEEC\SBC106367711) el fichero del que faltan datos (diario-mensual-anual). De esta forma se convierte al formato manejable por el programa del antiguo sistema de monitorización. El fichero convertido queda en la carpeta “Archivos Actualizacion Manual” 4. Cortar el fichero generado en el punto 3 y pegarlo en la carpeta de la página web (c:\Inetpub\wwwRoot\ftproot\www_Usumeteo4) 5. Salir de la aplicación que se ha abierto en el punto 2 6. Volver a arrancar el servicio parado en el punto 1 realizando el mismo procedimiento de ese apartado Si el comportamiento erróneo del programa se debiera a la imposibilidad de escribir los ficheros convertidos el error se deberá a no tener derechos de escritura. Bastará otorgar este derecho al usuario anónimo sobre la carpeta que tiene la web de www_usumeteo4. De esta forma se podrá obtener información de la página de Jose Alberto Sánchez. -130- J.M.Estepa CURRÍCULUM VITAE DEL AUTOR Datos Personales • • • • • • • Nombre y Apellidos: Fecha de nacimiento: Lugar de nacimiento: DNI : Dirección: Teléfono: Email: José María Estepa Martínez 19 de Marzo de 1964 Soria 16.795.560 V C/ Las Casas, nº 42 – 42004 Soria 975 232 402 [email protected] Formación Académica • • • 1982-1986: Ingeniero Técnico Industrial en la especialidad de Electrónica Industrial, por la Universidad Rovira i Virgili de Tarragona Curso 2007-2008: Master Universitario de Ingeniería Informática en Comunicación, redes y gestión de contenidos, por la UNED 2006-2010: Ingeniero Industrial, intensificación de Técnicas Energéticas, por la UNED Experiencia Profesional Desde 1987 Profesor de Educación Secundaria en la especialidad de Informática. En estos 23 años ha impartido asignaturas relacionadas con los sistemas operativos monousuario y multiusuario, redes de área local, sistemas gestores de bases de datos, arquitectura de computadores, implantación de aplicaciones en lenguajes estructurados y orientados a objetos. Desde 1993 Profesor-tutor en el centro asociado de la UNED de Soria en las asignaturas de “Estructura y Tecnología de los Computadores I”, “Estructura y Tecnología de los Computadores II” y “Redes” de las carreras de Informática, en el Centro Asociado de la UNED en Soria. En este mismo centro he impartido numerosos cursos monográficos relacionados con la informática y dirigidos a varios colectivos. Desde 2003 Coordinador Virtual del Centro asociado de la UNED en Soria. Entre los años 1988 al 1994 Administrador-Secretario del Instituto “Politécnico” de Soria. Jefe del departamento de Informática del Instituto “Virgen del Espino” de Soria en los cursos 1995-1996 y del 2003 al 2007 Entre los años 1996 y 2003 Asesor técnico-docente del Área de Programas Educativos de la Dirección Provincial de Educación de Soria. Encargado de tareas relacionadas con la Formación Profesional y programas relacionados con las Nuevas Tecnologías de la Información y la Comunicación y su implantación en centros docentes. Entre los años 2000 al 2007 Miembro de la “Comisión de Expertos para el desarrollo curricular” de la Consejería de Educación de la Junta de Castilla y León, elaborando los -131- Proyecto Final de Carrera currículums de las asignaturas de “Informática” y “Tecnología y Nuevas Tecnologías” para la ESO y “Tecnologías de la Información” para el Bachillerato. Formación Complementaria Ha recibido más de 1500 horas de formación relacionada con aspectos profesionales y docentes en el campo de la Informática, relacionadas, sobre todo, con los Sistemas Operativos, las redes de ordenadores, los Sistemas Gestores de Bases de Datos, la programación, la gestión de recursos humanos y los centros docentes. Ha colaborado como ponente en múltiples actividades formativas programadas, entre otros organismos por el centro asociado de la UNED de Soria, el Instituto de Tecnologías Educativas (antiguo PNTIC y CNICE) dependiente del Ministerio de Educación, la Consejería de Educación de la Junta de Castilla y León y los Centros de Formación del Profesorado de la Dirección Provincial de Educación de Soria -132- J.M.Estepa -133- Proyecto Final de Carrera -134-