G A C E T A   D E   L I N U X
...haciendo a Linux un poco más divertido!

Estación Meteorológica Python
Por Phil Hughes
Traducción al español por José Gregorio Del Sol Cobos
el día 13 de Octubre 2003, para La Gaceta de Linux

 

Este programa es una simple interfaz que le permite construir una página web a a partir de la salida de los datos Metar de las estaciones meteorológicas de todo el mundo. No lo llamaría excitante, pero funciona.

Mejor que describir lo que usted ve, vaya aquí, y eche un vistazo. Debería ver al menos dos y posiblemente hasta cinco informes meteorológicos desde Costa Rica. O sea, el programa tiene una lista de cinco estaciones meteorológicas para probar y muestra la información de todo ese informe.

Estructura del Sistema

El corazón del sistema es el paquete Pymetar, disponible aquí. Éste es el programa en Python que trae los datos Metar descrito aquí. Pymetar es una herramienta en línea de comandos, pero hace todo el trabajo sucio.

Mi objetivo es hacer disponible esta información en una página web. No quería que esto se volviese un gran proyecto de programación, pero sí que la implementación tenga sentido. La aproximación más básica habría sido ejecutar el programa como un guión CGI para cada petición. Sin embargo, esto era potencialmente muy ineficiente porque requeriría que el programa se hiciera con todos los datos cada vez que llegara una petición al CGI. Más importante, significaría que el usuario tendría que esperar a que se completasen todas esas peticiones.

Decidí que el mejor compromiso era instalar un trabajo cron para recopilar los datos y construir una página meteorológica. Entonces, cada petición de una página simplemente estaría mostrando una página estática. Como los datos meteorológicos no cambian tan a menudo, esto efectivamente ofrece información bastante actual.

Implementación

Lo primero, aquí está el código:


#!/usr/bin/env python

import sys
import time
sys.path.insert(0, "/home/fyl/pymetar-0.5")
import pymetar

def stations(args):
    for arg in map(lambda x: x.strip(), args):
        try:
            weather = pymetar.MetarReport(arg)
        except IOError, msg:
            # descomentar lo siguiente y quitar el paso de línea para ver los errores
            # sys.stderr.write("Problem accessing the weather server: %s\n" % msg)
            pass
        else:
            if weather.valid:
		print "<h3>"
                print weather.getStationName()
                print " ( Lat: %s, Long: %s, Alt: %s m)" % \
		  weather.getStationPosition()
		print "</h3>"
		print "<table border=\"2\">"
                print "<tr><td>Updated</td><td> %s</td></tr>" % \
		  weather.getTime()
                if weather.getWindDirection() is not None:
		    print "<tr><td>Wind direction</td><td> %s°</td></tr>" % \
		      weather.getWindDirection()
                if weather.getWindSpeed() is not None:
                    print "<tr><td>Wind speed</td><td> %6.1f m/s</td></tr>" % \
		      weather.getWindSpeed()
                if weather.getTemperatureCelsius() is not None:
                    print "<tr><td>Temperature</td><td> %.1f°C (%.1f°F)</td></tr>" % \
		      (weather.getTemperatureCelsius(), \
		      weather.getTemperatureFahrenheit())
                if weather.getDewPointCelsius() is not None:
                    print "<tr><td>Dew point</td><td> %.1f°C (%.1f°F)</td></tr>" % \
		      (weather.getDewPointCelsius(), \
		      weather.getDewPointFahrenheit())
                if weather.getHumidity() is not None: 
                    print "<tr><td>Humidity</td><td> %.0f%%</td></tr>" % \
		      weather.getHumidity()
                if weather.getVisibilityKilometers() is not None:
                    print "<tr><td>Visibility</td><td> %.1f Km</td></tr>" % \
		      weather.getVisibilityKilometers()
                if weather.getPressure() is not None:
                    print "<tr><td>Pressure</td><td> %.0f hPa</td></tr>" % \
		      weather.getPressure()
                if weather.getWeather() is not None: 
			print "<tr><td>Weather</td><td> %s</td></tr>" % \
			  weather.getWeather()
                if weather.getSkyConditions() is not None: 
			print "<tr><td>Sky conditions</td><td> %s</td></tr>" % \
		          weather.getSkyConditions()
		print "</table>"
            else:
                print "Either %s is not a valid station ID, " % arg
		print "the NOAA server is down or parsing is severely broken."


print "<html>"
print "<head>"
print "<title>Costa Rica weather from PlazaCR.com</title>"
print "</head>"
print "<body>"
print "<h1>Costa Rica weather from PlazaCR.com</h1>"
print "<p>Latest reports as of %s CST" % time.ctime()
gm = time.gmtime()
print "(%d.%02d.%02d %02d%02d UTC)" % (gm[0], gm[1], gm[2], gm[3], gm[4])
print '<p><a href="images/costa_rica.gif" target="_blank">Costa Rica map</a>'

stations(["MROC", "MRLM", "MRCH", "MRLB", "MRPV"])

print "</body>"
print "</html>"
Nota del traductor: dado que el código es material del autor, he dejado en inglés lo que después se convierte ne la salida del programa

Elijo importar simplemente el código pymetar.py en la envoltura que genera la página HTML. Para esto, añadí el directorio de Pymetar a la ruta que sigue Python para buscar.

Seguido defino stations, una función que consulta las estaciones meteorológicas empleando el código de Pymetar y después formatea la salida en HTML. Parece muy fea porque consiste sólo en largas sentencias print que construyen las cadenas HTML con algunas sentencias para ver si efectivamente se obtienen los datos. El punto importante es que le pasas una lista de nombres de estaciones y obtiene a la vuelta el cuerpo de la página web.

Finalmente, las últimas puede que 15 líneas de código simplemente construyen el recipiente HTML y llaman a las estaciones para producir,

Testado e instalación

Debido al diseño, el testado es muy sencillo. No hay dependencias basadas en web en el diseño, de modo que simplemente puede ejecutar el programa desde la línea de comandos.

En mi caso, llamé al programa wcr, de modo que simplemente escribiendo ./wcr ejecutará el programa y mostrará el HTML en la salida habitual. Si todo va bien, ejecute de nuevo el programa, redirigiendo la salida a un fichero. Por ejemplo,

./wcr > /tmp/weather.html

Ahora usted puede apuntar un navegador web hacia el fichero y ver si visualiza la página que usted quiere. Si no, es el momento de hacer cambios en wcr y seguir testando.

Una vez que usted está contento con la salida, suba el código a su servidor web y prepare un trabajo cron para ejecutarlo. Normalmente, crontab -e le permitirá editar su entrada crontab.

Yo elegí ejecutar el programa dos veces cada hora, a y cinco y a menos veinticinco. La entrada crontab debe ejecutar el programa y escribir el fichero de salida en una localización que pueda conocer el servidor web. Yo usé:

5,35 * * * * /home/fyl/pymetar-0.5/bin/wcr > /var/www/htdocs/weather.html

Los cuatro asteriscos le dicen a cron que 5 y 35 minutos se aplican a cada hora de cada día. El siguiente campo es el nombre del programa a ejecutar. Finalmente, el operador de redirección (>) es seguido por el lugar donde se ha de almacenar el archivo HTML.

Asumiendo que pone todos los permisos bien, o sea, que el programa puede escribir el fichero y el servidor web puede leerlo, ya está todo. Simplemente apunte a ese fichero, y ya tiene una página meteorológica.

Conclusión

Para el perfeccionista, probablemente necesita una solución más elegante. ¿por qué? Bueno, hay un momento en el cual los contenidos del documento HTML no serán válidos. Cuando cron empieza la tarea, los contenidos de la salida se truncan. Entonces el programa se ejecuta y construye un nuevo fichero.

Debido a cómo trabajar el programa esta vez no es simplemente una ejecución corta de algo de código en Python según el programa consulta las diversas estaciones meteorológicas y tiene que esperar a la respuesta. Con las cinco estaciones que encuesté, vi tiempos transcurridos de entre uno y diez segundos. Si tener malos datos durante un máximo de 10 segundos cada 30 minutos es aceptable para usted, todo está bien. Si no, escriba la salida en un fichero temporal y entonces muévalo al fichero de verdad cuando todo esté completo. Aún no es perfecto, pero se acerca mucho.

Ahora, para nosotros los mortales, tenemos una bonita página meteorológica. Que se divierta.

 

Phil Hughes es el editor de Linux Journal. y por tanto de Linux Gazette. Sueña permanentemente con la teleconmutación desde su casa en la costa del Pacífico de la Península Olympic. Como empleador, él es "Vicioso, Malo, Tacaño, & Desagradable", pero agradable" como un jefe debe ser.


Copyright © 2003, Phil Hughes. Licencia de copiahttp://www.linuxgazette.com/copying.html
Publicado en el Número 94 de Linux Gazette, Septiembre de 2003