Mi Proyecto - Portal de sistemas renovables del DIEEC

Anuncio
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ño del
sistema de monitorización de energías renovables:
acceso, estandarizació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-
Descargar