Tutorial: conexión a red en dispositivos móviles
Versión: 1.0, Septiembre, 2006 Autor: Manuel Gómez Olmedo Web: http://decsai.ugr.es/~mgomez, Mail: mgomez@decsai.ugr.es |
(C) Dpto. de CCIA Web: http://decsai.ugr.es |
En este tutorial se explica la forma de conectar un dispositivo móvil con la red. La
exposición se basará en la realización de una serie de ejercicios que
irán introduciendo los conceptos necesarios. Se incluyen algunos comentarios sobre
operaciones de entrada/salida que son necesarias para poder intercambiar datos mediante
las conexiones pertinentes.
Para quien conozca Java estándar, hay poca diferencia entre la forma de programar la conexión a red en Java para dispositivos móviles. Para apreciar esta semejanza, el primer ejemplo consistirá en el desarrollo completo de un MIDlet que obtendrá datos a partir de una conexión de red y los mostrará por pantalla.
La aproximación a conexión a redes parte de la definición de un marco genérico de conexión (GCF: generic connection framework). El propósito de este marco genérico es ofrecer un nivel de abstracción para los servicios de red, lo que permite que diferentes dispositivos habiliten únicamente los protocolos de red precisos para sus necesidades.
En verdad, el dispositivo no es quien para decidir las características de conectividad que soportará. Esto es responsabilidad de los diferentes perfiles. El marco GCF define una clase genérica, Connector, que está incluida en el paquete javax.microedition.io. Esta clase, junto con un conjunto de interfaces que definen los tipos de conexiones sirven como plataforma de tratamiento de la conexión de los MIDlets con la red. Se exponen algunas de las características relevantes de las clases a usar para ofrecer la conexión a red:
En realidad se trata de un conjunto de interfaces generales que no están próximas a ningún protocolo real de comunicaciones. Ofrecen, por tanto, una arquitectura básica capaz de soportar un amplio rango de características de conexión. Esto tiene la ventaja de conseguir que las aplicaciones de conexión a red tengan una estructura similar independientemente del protocolo de red usado.
Para implementar esta arquitectura general, los perfiles agregarán las clases necesarias para complementar esta plataforma básica. Por ejemplo, el API de MIDP agrega la interfaz HttpConnection, que agrega la posibilidad de establecer conexiones HTTP (conexiones a páginas web). En realidad, la conexión HTTP es la única que obligatoriamente debe incluir la implementación de MIDP. Por tanto, siguiendo de forma estricta el estándar MIDP es el único tipo de conexión posible. Esto es, de alguna forma, una limitación con gran impacto en el diseño de MIDlets.
Siempre se usa la clase Connector para establecer conexiones de red, independientemente del tipo de conexión. Todos los métodos de esta clase son estáticos, siendo el más importante el método open(), con tres versiones diferentes:
El primer parámetro de estos métodos es la cadena de conexión. Se trata del parámetro más importante, ya que determina el tipo de conexión a realizar. La cadena de conexión describe qué tipo de conexión se usará y debe seguir el esquema: Protocolo:Objetivo[;Parámetros]
El parámetro Protocolo es el nombre del protocolo a usar, como http o ftp. El parámetro Objetivo es, típicamente, el nombre de la dirección de red a acceder, pero puede variar según el protocolo usado. El último argumento, Parámetros, es una lista de parámetros asociados a la conexión. Algunos ejemplos de diferentes tipos de conexión se incluyen a continuación:
Hemos de tener en cuenta que el único tipo de conexión que MIDP soporta es la conexión HTTP. Disponer o no de las otras dependerá de la implementación de MIDP que se use.
La segunda y tercera versión del método open() admiten un segundo parámetro relativo al modo. Este argumento describe si la conexión se abre para lectura, escritura o para ambas operaciones. En la clase Connector se definen las siguientes constantes a usar como valores posibles para este parámetro: READ, WRITE y READ_WRITE.
En el caso de la primera versión del método, donde no aparece este argumento, se abrirá una conexión tanto para lectura como para escritura. La última versión del método consta de un único argumento que permite especificar el tiempo límite de espera a establecimiento de la conexión. Si este tiempo se sobrepasa se lanzará una excepción.
En cualquier caso, el método open() devuelve un objeto de la clase Connection, que es la interfaz base de todos los tipos de conexión disponibles. Será necesario hacer una conversión de tipos para convertir este objeto al tipo de conexión que deseemos manejar. Por ejemplo, la siguiente línea de código muestra cómo crear una conexión HTTP mediante la interfaz StreamConnection::
StreamConnection conn = (StreamConnection)Connector.open("http://poldo.ugr.es/frases.txt");
Más adelante se verá la forma de usar este flujo para poder leer datos.
La clase Connector y los interfaces de conexión asociados se usan para obtener una conexión a red mediante un protocolo específico. Tras el establecimiento de la conexión deben usarse clases que permitan realizar operaciones de entrada salida de la conexión. Estas clases para realizar operaciones de E/S están contenidas en el paquete java.io y son:
Estas clases son similares a las usadas para entrada salida en la plataforma estándar de Java. A continuación se explica cómo usar estas clases para hacer operaciones de entrada y salida. Quizás las clases más importantes sean InputStream y OutputStream, ya que proporcionan la funcionalidad básica de E/S con flujos de datos.
La clase InputStream es una clase abstracta que sirve como clase base para las otras clases de flujos de entrada de MIDP. Esta clase define una interfaz básica para lectura de información de un flujo. El escenario típico de uso de los flujos de entrada consiste en crear un objeto de esta clase a partir de una conexión y después indicar que se desea leer información invocando al método read(). Si no hay información de entrada disponible, entonces el flujo de entrada usa una técnica conocida como bloqueo para esperar hasta la llegada de datos.
Un ejemplo de bloqueo se presenta en el caso de usar un flujo de entrada para leer información de una conexión HTTP. Hasta que el servidor Web no entregue la información no habrá entrada disponible para el objeto de la clase InputStream que hayamos creado. De esta forma. el objeto espera (se bloquea) hasta disponer de información, momento en el que la información se procesa como datos de entrada.
La clase InputStream define los métodos siguientes:
Como se aprecia, hay tres versiones diferentes del método de lectura. El primer método carece de argumentos y simplemente lee un byte de datos del flujo y devuelve un valor entero. Este versión devuelve el valor -1 si se alcanza el final del flujo de entrada. Al devolverse un entero será necesario hacer una conversión a carácter (char) en el caso de leer caracteres.
La segunda versión de read() tiene un array de bytes como único argumento. Esto permite leer varios bytes de datos a la vez, almacenándose los datos leidos en el array. Este método devuelve el número de bytes leidos o bien -1 en caso de alcanzar el final del flujo.
La última versión de read() es similar a la segunda, pero permite especificar las posiciones del array en que se almacenarán los datos leidos. El parámetro off especifica el desplazamiento respecto al inicio del array del lugar de comienzo de almacenamiento. El parámetro len especifica el máximo número de bytes a leer.
El método skip() se usa para saltar bytes del flujo de entrada. El argumento de este método indicará cuántos bytes hay que saltar (ignorar). Devuelve el número de bytes saltados o bien -1 en caso de alcanzarse el final del flujo.
El método available() se usa para determinar el número de bytes de datos de entrada que pueden leerse sin bloquearse. Este méetodo no usa parámetros y devuelve el número de datos disponibles. El método es útil si desea asegurar que hay datos de entrada disponibles antes de llamar al método read() y evitar así el bloqueo.
El método mark() marca la posición actual del flujo. Posteriormente puede volver a esta posición usando el método reset(). Estos métodos son útiles en casos en que se desea leer datos por adelantado, siendo necesario recordar la posición inicial. El método mark() precisa un argumento que especifica el número de bytes que pueden leerse antes de que la marca quede invalidada. Es decir, indica cuántos bytes pueden leerse hacia adelante antes de poder volver atrás. El método markSupported() devulve un valor booleano que indica si un flujo de entrada admite la funcionalidad de establecimiento de marca.
Finalmente, el método close() cierra un flujo de entrada y libera los recursos asociados con el flujo. No es necesario llamar explícitamente al método close() ya que los flujos de entrada se cierran automáticamente al destruirse los objetos de la clase InputStream.
La clase OutputStream es la clase de salida equivalente a InputStream, pero ahora para salida de datos. Sirve como clase base abstracta para todos los flujos de salida de MIDP. Esta clase define el protolo básico para escribir datos en flujos de salida. El uso típico consistirá en crear un objeto de esta clase a partir de la conexión y después llamar al método write() para indicar que se desea escribir información. Esta clase utiliza la técnica de bloqueo similar a la usada por InputStream: el flujo se bloquea hasta haber escrito datos en un dispositivo de salida. Mientras está bloqueado no se admiten nuevas operaciones de escritura. Los métodos soportados por esta clase son los siguientes:
De forma similar a como ocurría con la clase InputStream, esta clase define tres métodos write() diferentes. El primero de ellos escribe un byte en el flujo. Este byte está especificado por el argumento b. La segunda versión de write() toma como argumento un array de bytes, que se escribirán al flujo de salida. La última versión usa tres argumentos: un array, un desplazamiento y una longitud. Es similar a la segunda versión, pero en este caso se define la posición del array a partir de donde empezará la escritura en el flujo y el número de bytes que habrán de enviarse al mismo.
El método flush() se usa para forzar el envío de los datos al flujo.
Por último, el método close() cierra el flujo de salida y libera los recursos que pudieran estar usándose. Como ocurría en el caso de la clase InputStream, no es preciso el cierre explícito del flujo de salida, ya que la destrucción de los objetos de esta clase implica realizar esta operación.
Tras esta presentación de los aspectos generales de las conexiones a red mediante MIDP y de las clases necesarias para hacer entrada/salida, hay que conjugar ambas cosas para realizar una conexión de red. Esto es más fácil de lo que en principio pudiera parecer. La realización de la conexión consta de los tres pasos básicos indicados a continuación:
Esto es todo lo necesario. Obviamente, lo realmente importante es lo que luego se hace con los datos enviados, pero esto forma parte de la aplicación a realizar y no tiene que ver con lo considerado en este tema de conexión a redes. A continuación se explicará cómo se realizan los tres pasos básicos descritos previamente.
El primer paso necesario consiste en establacer la conexión de red. Esto se consigue mediante el método open() de la clase Connector. La forma más sencilla de este método precisa el uso de un parámetro: la cadena de conexión. El siguiente ejemplo muestra cómo abrir un flujo en una conexión HTTP a una página Web:
StreamConnection conexion = null; // Como argumento se pasa la dirección URL a acceder conexion=(StreamConnection)Connector.open("http://www.ugr.es");
El siguiente paso consiste en obtener un flujo de entrada y salida a partir de la conexión. Esto es necesario para poder realizar operaciones de entrada y salida.
Obtener un flujo de entrada es muy sencillo. El código necesario aparece a continuación:
InputStream entrada=conexion.openInputStream();
El método openInputStream() es todo lo que se necesita para obtener el flujo de entrada de la conexión. Una vez obtenido el flujo, puede usarse para leer datos de la conexión HTTP.
Antes se ha comentado que el método read() es el necesario para poder leer datos de un flujo de entrada. La versión más básica del método lee un byte de entrada, devolviendo su valor como un entero. Las llamadas sucesivas irán devolviendo bytes adicionales de la entrada. La lectura debería seguir hasta agotar los datos disponibles en el flujo (es decir, hasta que una operación de lectura devuelva -1). A continuación se muestra un ejemplo de cómo se haría esto, utilizando un bucle de lectura que muestra por la consola lo que se va leyendo:
StringBuffer datos = new StringBuffer(); // Bucle de lectura hasta que no haya mas datos disponibles while ((ch = entrada.read()) != -1) { if (ch != '\n') { // Se lee una linea completa: hasta salto de linea datos.append((char)ch); } else{ // Ha finalizado la linea y se muestra System.out.println(datos.toString()); // Se limpia el buffer de datos para preparar la lectura // de nuevas lineas datos = new StringBuffer(); } }
En este código la variable datos en un búfer de cadenas de caracteres para mantener una línea de datos cada vez. El método read() se utiliza para ir leyendo caracteres hasta alcanzar el salto de línea. Cuando se alcanza el fin de línea se presenta por pantalla y se limpia el buffer para preparar la recepción de una nueva línea.
Este código representa la premisa básica de cómo deberían leerse datos de un flujo de entrada definido sobre una conexión HTTP. Si se tiene en cuenta la gran cantidad de datos disponibles en páginas Web, la pàrte realmente complicada radica en analizar el texto recibido a través del flujo de entrada para extraer la información necesaria. Se verán algunos ejemplos de cómo hacer esto.
El MIDlet que realizaremos a continuación tiene como objetivo poner en práctica los conocimientos vistos hasta ahora. Nuestro MIDlet se llamará Frases y tiene como objetivo leer y mostrar, de forma aleatoria, frases localizadas en un archivo ubicado en un servidor Web remoto. Este MIDlet usará una conexión HTTP para abrir el archivo de texto y poder leer de él. El contenido del archivo se volcará en un vector de cadenas de caracteres. Posteriormente, se seleccionará de forma aleatoria una de las frases y se mostrará por pantalla.
La función básica del MIDlet es establecer una conexión de red y leer líneas de un archivo de texto ubicado en un servidor Web. El archivo de texto debe, por tanto, poder abrirse en un navegador Web poniendo su dirección completa.
El archivo de texto ubicado en http://poldo.ugr.es se denomina frases.txt y su contenido es el siguiente:
Aprendemos de la historia que realmente no aprendemos de la historia. Las leyes mezquinas producen grandes crímenes. El derecho a estar solo es el comienzo de toda libertad. Entre amigos, ¿qué es la Constitución?. El mejor resultado de la educación es la tolerancia. La tiranía siempre se organiza mejor que la libertad.
Cada frase del archivo debe aparecer en una línea aparte. Esto es necesario porque el MIDlet procesará las líneas una a una. Esto facilita el análisis del texto. Para conseguir la funcionalidad deseada dividiremos el código del MIDlet en los siguientes componentes:
Al ejecutar este MIDlet por primera vez se recupera el texto completo del archivo. Posteriormente se irán seleccionando las frases de forma aleatoria. La selección se hace al activar el comando Siguiente. Sólo se precisa un comando más, Salir, con el que finaliza la ejecución del MIDlet. Estos comandos se crean como datos miembros de la clase Frases, junto con los elementos de la interfaz de usuario del MIDlet, la cadena de caracteres que almacena la frase actualmente seleccionada, el vector de cadenas necesario para almacenar el contenido del archivo y una variable booleana para controlar si se trata de la primea vez que se llama al método startApp().
// Comandos de gestion del MIDlet private Command comandoSalir, comandoSiguiente; // Display del dispositivo movil private Display display; // Formulario para posicionar los elementos de // la aplicacion private Form formulario; // Para almacenar la frase seleccionada private StringItem frase; // Vector para guardar todas las frases private Vector frases; // Variable booleana para controlar la ejecucion // de startApp la primera vez y en sucesivas // llamadas despues de cada pausa private boolean primeraVez;
Como se aprecia, en primer lugar se definen los comandos necesarios: comandoSalir y comandoSiguiente. El objeto display se usará para conseguir mostrar cosas en la pantalla del terminal móvil. El objeto formulario, de la clase Form, se precisa para que contenga la frase seleccionada en cada momento. En este contenedor se mostrará el contenido de la frase seleccionada, que estará almacenada en el objeto frase, de la clase StringItem. Finalmente, se declara el vector frases usado para contener todas las frases del archivo. Para poder usar objetos de la clase Vector es necesario importar la clase (se consigue mediante la sentencia import java.util.Vector;). A continuación se muestran las líneas a incluir en el constructor de la clase:
// Constructor de la clase Frases. Inicializa los datos // miembros public Frases() { // Se obtiene una referencia al display display = Display.getDisplay(this); // Se crean los comandos comandoSalir=new Command("Salir", Command.EXIT, 2); comandoSiguiente = new Command("Siguiente", Command.OK, 2); // Se crea el formulario formulario = new Form("Frase del día"); // Se crea el StringItem para contener la frase seleccionada frase = new StringItem("", "Leyendo frases..."); // Se agrega el objeto al formulario formulario.append(frase); // Se establecen los comandos al formulario formulario.addCommand(comandoSalir); formulario.addCommand(comandoSiguiente); // Se agrega un gestor de eventos para atender a los comandos formulario.setCommandListener(this); // Se crea el vector de frases frases = new Vector(); // Se inicializa primeraVez a true primeraVez=true; }
El código del método startApp(). Siguiendo las indicaciones vistas previamente, se prepara el método para la posible ocurrencia de eventos de pausa. A tal efecto se incluyó el dato miembro primeraVez.
// Se inicia la ejecucion del MIDlet y se muestra la primera de las frases public void startApp() throws MIDletStateChangeException { // Mostrar el formulario y leer las frases solo se hara la primera // vez if (primeraVez == true){ // Se muestra el formulario por pantalla display.setCurrent(formulario); // Se leen las frases leerFrases(); // Se hace que primeraVez sea false primeraVez=false; } // Sea o no la primera vez, se selecciona aleatoriamente // una frase y se muestra mostrarFrase(); }
La gestión de comandos se realiza en el método commandAction(), cuyo código se incluye a continuación:
// Método de gestión de los comandos public void commandAction(Command c, Displayable s) { // Si se trata del comando salir se llama de destroyApp() if (c == comandoSalir) { // Se llama con argumento false para controlar la // posible solicitud de salida mientras se esta // leyendo el archivo destroyApp(false); // Se indica al dispositivo que se desea finalizar notifyDestroyed(); } else if (c == comandoSiguiente) { // Mostrar de forma aleatoria la siguiente frase mostrarFrase(); } }
La funcionalidad de red de este MIDlet se encuentra dentro del método leerFrases(). Recordad que los pasos básicos necesarios son:
Los puntos 2 y 3 se realizan mediante un bucle while que realiza la lectura hasta alcanzar el final del archivo. A continuación se incluye el código comentado del método leerFrases():
// Método que lee las frases del archivo del servidor web private void leerFrases() { StreamConnection conexion = null; InputStream entrada = null; StringBuffer datos = new StringBuffer(); // Se procede a realizar la conexion try { // Se abre la conexión HTTP conexion=(StreamConnection)Connector.open("http://poldo.ugr.es/frases.txt"); // Se obtiene un flujo de entrada a partir de la conexión entrada = conexion.openInputStream(); // Se leen lineas del flujo de entrada int ch; boolean hecho = false; while ((ch = entrada.read()) != -1) { if (ch != '\n') { // La linea se lee caracter a caracter datos.append((char)ch); } else { // Se agrega la frase al vector de frases frases.addElement(datos.toString()); // Se limpia el StringBuffer datos = new StringBuffer(); } } } // Se recoge la excepcion, si se produjera catch (IOException e) { // En caso de producirse error, se muestra el mensaje por la pantalla System.err.println("No pudo establecerse la conexión."); } }
Quedarí por programar el método que selecciona al azar una frase y la muestra por pantalla:
// El metodo mostrarFrase selecciona frase al azar y la muestra por pantalla private void mostrarFrase() { // Se comprueba que el vector de frases no esté vacío if (!frases.isEmpty()) { // Se crea el generador de números aleatorios. Se inicializa a // partir de la fecha y hora actual Random generador = new Random(Calendar.getInstance().getTime().getTime()); // Se selecciona frase al azar. El número generado estará entre 0 y // el tamaño del vector -1 (que es el índice de la última posición) int numeroFrase = Math.abs(generador.nextInt()) % frases.size(); // Se muestra la frase seleccionada frase.setText((String)frases.elementAt(numeroFrase)); } else frase.setText("No hay frases disponibles!"); }
Resumen
En esta parte se han introducido los conceptos básicos sobre conexión de redes. De ahora en adelante se considera la construcción de un MIDlet capaz de recuperar y mostrar las condiciones meteorológicas de un determinado lugar. No hay ninguna razón especial para elegir este problema y podría haberse trabajado con cualquier otra fuente de información soportada en la Web.
Una de las aplicaciones más interesantes de J2ME consiste en recuperar datos de Internet y hacerlos disponibles a los usuarios. Una de estas aplicaciones consistiría en obtener información meteorológica mediante el teléfono móvil. Este será el objetivo de esta sección: construir un MIDlet que pueda realizar esta función. Las acciones básicas que el MIDlet debe realizar son:
En la red existen diversos sitios Web que ofrecen información meteorológica en tiempo real. En la mayoría de estos sitios se introduce el nombre de una ciudad o un código postal y se ofrece la información relativa a dicha zona geográfica.
Sin embargo, al pensar en acceder a esta información desde un dispositivo móvil surgen varios problemas. En primer lugar, ¿;cómo actuar sobre la página Web para solicitar información sobre una determinada ciudad? Y en segundo lugar, ¿cómo visualizar la información de la página sobre la pantalla del dispositivo móvil?
Nota:
Para visualizar información meteorológica en un MIDlet es preciso encontrar un origen de los datos (una página Web) con el formato adecuado para poder leer y analizar. Uno de estos sitios es, por ejemplo, http://iwin.nws.noaa.gov/. En este sitio la información se ofrece en un formato simple fácil de analizar y mostrar. Es decir, resulta relativamente sencillo leer la página con los datos solicitados y analizarla para extraer la información de interés. Como la pantalla de los dispositivos móviles es limitada hay que filtrar la información recibida de la página Web antes de mostrarla.
La página web con información meteorológica está bien organizada y está en un formato fácil de acceder. Hemos de pensar en la forma de obtener la información deseada. Jugando un poco con la página vemos que la información de Nueva York se encuentra en la página: http://iwin.nws.noaa.gov/iwin/ny/hourly.html. Esta información URL incluye la dirección base (http://iwin.nws.noaa.gov/) y un par de directorios adicionales que se refieren a la información en la que estamos interesados (iwin/ny/). Finalmente, sigue la página en sí que deseamos recuperar: hourly.html.
Es decir, la información sobre los diferentes estados se organiza en directorios diferentes, de forma que si queremos acceder a la información sobre un determinado estado sólo hemos de modificar las dos letras relativas al estado: en este caso ny. Por ejemplo, si se desea acceder a la información meteorológica sobre Arizona la dirección a usar será: http://iwin.nws.noaa.gov/iwin/az/hourly.html. En realidad, la cadena que indica la dirección a acceder podría descomponerse de la forma siguiente:
String direccion="http://iwin.nws.noaa.gov/iwin/"+estado+"/hourly.html";
La variable estado indicaría las dos letras que identifican a cada uno de los estados.
Conviene ahora prestar atención a la información mostrada en la página de un estado cualquiera. En verdad, aunque parece que su contenido es texto únicamente, se trata de información ubicada en una página web, por lo que está codificada mediante HTML. Por tanto, habrá que ignorar las etiquetas de HTML para acceder a los datos reales. La página de un estado cualquiera sería la siguiente:
New York - Hourly data
NOAA's NWS will be accepting comments on proposed IWIN replacement pages until April 30, 2006. Please learn more about the replacement and how to leave a comment here |
ASUS41 KPHI 030810 RWRPHI REGIONAL WEATHER ROUNDUP NATIONAL WEATHER SERVICE MOUNT HOLLY NJ 400 AM EDT TUE OCT 03 2006 NOTE: "FAIR" INDICATES FEW OR NO CLOUDS BELOW 12,000 FEET WITH NO SIGNIFICANT WEATHER AND/OR OBSTRUCTIONS TO VISIBILITY. * = STATION DOES NOT REPORT PRECIPITATION (E.G. RAIN, SNOW, ETC.) OR FOG. NJZ015>026-030900- SOUTHERN NEW JERSEY CITY SKY/WX TMP DP RH WIND PRES REMARKS POMONA PTCLDY 54 49 83 CALM 30.22S TRENTON CLOUDY 51 48 89 CALM 30.20S $$ NJZ001>014-030900- NORTHERN NEW JERSEY CITY SKY/WX TMP DP RH WIND PRES REMARKS SUSSEX CLEAR 45 44 97 CALM 30.20F ANDOVER N/A 46 45 96 CALM 30.20S NEWARK PTCLDY 55 47 74 W6 30.19S TETERBORO PTCLDY 53 47 79 CALM 30.18F CALDWELL PTCLDY 48 47 96 CALM 30.20S SOMERVILLE PTCLDY 47 45 93 CALM 30.19S $$ PAZ043-044-047-054-055-060>062-066>071-030900- EASTERN PENNSYLVANIA CITY SKY/WX TMP DP RH WIND PRES REMARKS PHILADELPHIA NOT AVBL LANCASTER CLOUDY 57 54 89 CALM 30.19F ALLENTOWN CLOUDY 52 48 86 CALM 30.19F MOUNT POCONO CLOUDY 49 45 86 VRB3 30.20F WILKES BARRE PTCLDY 50 47 89 SE5 30.18F $$ DEZALL-MDZ008-012-015-019-020-030900- DELAWARE AND EASTERN MARYLAND CITY SKY/WX TMP DP RH WIND PRES REMARKS WILMINGTON CLOUDY 59 55 87 CALM 30.20S PATUXENT MOCLDY 62 56 80 SW3 30.21S OCEAN CITY PTCLDY 58 56 93 W3 30.22R WALLOPS ISLAND PTCLDY 57 53 86 CALM 30.22S $$ PAZ001-021-NYZ056-072-MDZ011-DCZ001-030900- OTHER NEARBY LOCATIONS CITY SKY/WX TMP DP RH WIND PRES REMARKS BINGHAMTON CLEAR 53 47 79 S6 30.16F NEW YORK CITY PTCLDY 58 50 75 CALM 30.21F BALTIMORE NOT AVBL WASHINGTON DC LGT RAIN 64 59 83 SE7 30.20F $$ |
ASUS41 KOKX 030810 RWROKX REGIONAL WEATHER ROUNDUP NATIONAL WEATHER SERVICE UPTON NY 400 AM EDT TUE OCT 03 2006 NOTE: "FAIR" INDICATES FEW OR NO CLOUDS BELOW 12,000 FEET WITH NO SIGNIFICANT WEATHER AND/OR OBSTRUCTIONS TO VISIBILITY. NYZ071-072-076-NJZ005-030900- NEW YORK CITY METRO AREA CITY SKY/WX TMP DP RH WIND PRES REMARKS CENTRAL PARK PTCLDY 58 50 75 CALM 30.21F LAGUARDIA APRT PTCLDY 60 49 66 CALM 30.18S KENNEDY INTL PTCLDY 53 50 89 CALM 30.19F NEWARK/LIBERTY PTCLDY 55 47 74 W6 30.19S WHITE PLAINS NOT AVBL $$ NYZ077>081-030900- LONG ISLAND NEW YORK CITY SKY/WX TMP DP RH WIND PRES REMARKS FARMINGDALE CLEAR 52 48 86 CALM 30.19S ISLIP NOT AVBL SHIRLEY NOT AVBL WESTHAMPTON CLEAR 42 39 89 CALM 30.20S MONTAUK POINT N/A 52 48 86 CALM 30.20R $$ NYZ052-065-067-030900- HUDSON VALLEY CITY SKY/WX TMP DP RH WIND PRES REMARKS NEWBURGH NOT AVBL MONTGOMERY NOT AVBL POUGHKEEPSIE PTCLDY 45 45 100 CALM 30.17F ALBANY PTCLDY 50 47 89 S6 30.15F $$ NJZ001-003-005-008-013-015-019-021-022-030900- NEW JERSEY CITY SKY/WX TMP DP RH WIND PRES REMARKS TETERBORO PTCLDY 53 47 79 CALM 30.18F CALDWELL PTCLDY 48 47 96 CALM 30.20S SOMERVILLE PTCLDY 47 45 93 CALM 30.19S ANDOVER N/A 46 45 96 CALM 30.20S TRENTON CLOUDY 51 48 89 CALM 30.20S MILLVILLE NOT AVBL WRIGHTSTOWN NOT AVBL BELMAR NOT AVBL $$ PAZ047>061-062-071-030900- EASTERN PENNSYLVANIA CITY SKY/WX TMP DP RH WIND PRES REMARKS PHILADELPHIA NOT AVBL ALLENTOWN CLOUDY 52 48 86 CALM 30.19F SCRANTON NOT AVBL $$ CTZ002-004>006-009-010-012-RIZ004-006-007-MAZ004-011-015-030900- SOUTHERN NEW ENGLAND IN CT CITY SKY/WX TMP DP RH WIND PRES REMARKS BRADLEY INTL CLEAR 47 45 93 CALM 30.17S HARTFORD CLEAR 49 47 93 CALM 30.18S DANBURY CLEAR 44 43 96 CALM 30.20F WTRBRY/OXFORD NOT AVBL BRIDGEPORT CLEAR 49 45 86 CALM 30.18F MERIDEN CLEAR 45 43 93 CALM 30.19R NEW HAVEN CLEAR 47 45 93 CALM 30.18S GROTON NOT AVBL WILLIMANTIC FOG 45 44 97 CALM 30.19R VSB 1/4 IN RI CITY SKY/WX TMP DP RH WIND PRES REMARKS PROVIDENCE PTCLDY 48 46 93 SW5 30.17S BLOCK ISLAND NOT AVBL WESTERLY CLEAR 46 44 93 CALM 30.19R IN MA CITY SKY/WX TMP DP RH WIND PRES REMARKS BOSTON NOT AVBL WORCESTER NOT AVBL WESTFIELD MOCLDY 45 44 97 CALM 30.17S PROVINCETOWN NOT AVBL NANTUCKET CLEAR 50 47 89 CALM 30.17R $$ ANZ350-353-355-338-335-330-030900- COASTAL MARINE OBSERVATIONS STATION/POSITION TIME SKY/WX TEMP WIND PRES VSBY WAVE AIR SEA DIR/SP/G HT/PER (UTC) (F) (DEG/KT/KT) (MB) (MI) (FT/S) AMBROSE LIGHT 0700 63 66 250/ 3/ 4 1022.9 BUOY 20S FIRE IS 0700 65 65 220/ 4/ 6 1022.2 3/13 BUOY 23SW MTP 0700 64 64 290/ 8/ 8 1022.0 3/12 CENTRAL LI SOUND 0700 63 67 300/ 10/ 14 1022.1 ROBBINS REEF 0700 58 270/ 6/ 7 1023.2 $$ >>>>>>>>>>>>>>>>>>>>>>>>>>>> KEY <<<<<<<<<<<<<<<<<<<<<<<<<<< > < > SKY/WX - SKY CONDITION/PRESENT WEATHER < > TMP - TEMPERATURE IN FAHRENHEIT < > DP - DEWPOINT IN FAHRENHEIT < > RH - RELATIVE HUMIDITY IN PERCENT < > WIND - DIRECTION AND SPEED IN MPH < > PRES - MEAN SEA LEVEL PRESSURE IN INCHES OF HG < > WCI - WIND CHILL INDEX < > VSB - VISIBILITY IN MILES < > HX - HEAT INDEX < > TC - TEMPERATURE IN CELSIUS < > VRB - VARIABLE WIND DIRECTION < > < >>>>>>>>>>>>>>>>>>>>>>>>>>>> KEY <<<<<<<<<<<<<<<<<<<<<<<<<<< |
ASUS41 KALY 030810 RWRALY NEW YORK STATE HOURLY WEATHER ROUNDUP NATIONAL WEATHER SERVICE ALBANY NY 400 AM EDT TUE OCT 03 2006 NOTE: "FAIR" INDICATES FEW OR NO CLOUDS BELOW 12,000 FEET WITH NO SIGNIFICANT WEATHER AND/OR NO OBSTRUCTIONS TO VISIBILITY. NYZ032-033-038>043-046>054-057>066-NYZ062>081-030900- EAST CITY SKY/WX TMP DP RH WIND PRES REMARKS ALBANY PTCLDY 50 47 89 S6 30.15F GLENS FALLS NOT AVBL POUGHKEEPSIE PTCLDY 45 45 100 CALM 30.17F NEW YORK CITY PTCLDY 60 49 66 CALM 30.18S CENTRAL PARK PTCLDY 58 50 75 CALM 30.21F $$ NYZ005>009-017-018-044>046-055-056-030900- CENTRAL CITY SKY/WX TMP DP RH WIND PRES REMARKS SYRACUSE PTCLDY 47 45 93 E5 30.10F UTICA NOT AVBL ELMIRA MOCLDY 43 43 100 CALM 30.14R FOG BINGHAMTON CLEAR 53 47 79 S6 30.16F $$ NYZ026>034-041>043-030900- NORTH CITY SKY/WX TMP DP RH WIND PRES REMARKS WATERTOWN NOT AVBL FORT DRUM NOT AVBL MASSENA CLEAR 44 42 93 CALM 30.04F SARANAC LAKE PTCLDY 37 35 92 CALM 30.09F PLATTSBURGH CLOUDY 47 45 93 CALM 30.10S $$ NYZ001>004-010>016-019>021-030900- WEST CITY SKY/WX TMP DP RH WIND PRES REMARKS NIAGARA FALLS CLEAR 63 57 81 S12 N/A BUFFALO CLEAR 60 54 80 S7 30.04F DUNKIRK MOCLDY 65 55 70 S12 30.05F ROCHESTER PTCLDY 57 54 89 S5 30.07R PENN YAN CLEAR 55 51 86 SW7 30.10F $$ KEY WCI = WIND CHILL INDEX VSB = VISIBILITY HX = HEAT INDEX $$ |
ASUS41 KBOX 030810 RWRBOX REGIONAL WEATHER ROUNDUP NATIONAL WEATHER SERVICE TAUNTON MA 400 AM EDT TUE OCT 03 2006 NOTE: "FAIR" INDICATES FEW OR NO CLOUDS BELOW 12,000 FEET WITH NO SIGNIFICANT WEATHER AND/OR OBSTRUCTIONS TO VISIBILITY. THE FOLLOWING OBSERVATION LOCATIONS DO NOT REPORT PRESENT WEATHER...PROVINCETOWN... SMITHFIELD...BLOCK ISLAND...KEENE...AND OXFORD. MAZALL-030900- EASTERN MASSACHUSETTS CITY SKY/WX TMP DP RH WIND PRES REMARKS BOSTON NOT AVBL BEVERLY CLEAR 45 43 93 CALM 30.15F LAWRENCE NOT AVBL BEDFORD NOT AVBL BLUE HILL N/A 52 46 80 SW8 30.15S NORWOOD PTCLDY 38 38 100 CALM 30.16S FOG MARSHFIELD NOT AVBL PLYMOUTH NOT AVBL TAUNTON CLEAR 41 40 96 CALM 30.15S FOG NEW BEDFORD CLEAR 42 40 92 CALM 30.16S FOG $$ MAZALL-030900- CAPE COD AND THE ISLANDS CITY SKY/WX TMP DP RH WIND PRES REMARKS FALMOUTH NOT AVBL HYANNIS NOT AVBL CHATHAM CLEAR 51 48 89 CALM 30.17R NANTUCKET CLEAR 50 47 89 CALM 30.17R MARTHAS VNYRD CLEAR 40 37 89 CALM 30.17S $$ MAZALL-030900- CENTRAL AND WESTERN MASSACHUSETTS CITY SKY/WX TMP DP RH WIND PRES REMARKS WORCESTER NOT AVBL FITCHBURG MOCLDY 44 42 93 CALM 30.17S ORANGE FOG 44 44 100 CALM 30.17R VSB 1/4 SPRINGFIELD NOT AVBL WESTFIELD MOCLDY 45 44 97 CALM 30.17S NORTH ADAMS PTCLDY 42 42 100 CALM 30.17F FOG $$ RIZALL-030900- RHODE ISLAND CITY SKY/WX TMP DP RH WIND PRES REMARKS PROVIDENCE PTCLDY 48 46 93 SW5 30.17S NEWPORT CLEAR 47 45 93 CALM 30.18R FOG WESTERLY CLEAR 46 44 93 CALM 30.19R $$ CTZALL-030900- CONNECTICUT CITY SKY/WX TMP DP RH WIND PRES REMARKS BRADLEY INTL CLEAR 47 45 93 CALM 30.17S HARTFORD CLEAR 49 47 93 CALM 30.18S BRIDGEPORT CLEAR 49 45 86 CALM 30.18F DANBURY CLEAR 44 43 96 CALM 30.20F GROTON NOT AVBL NEW HAVEN CLEAR 47 45 93 CALM 30.18S MERIDEN CLEAR 45 43 93 CALM 30.19R WILLIMANTIC FOG 45 44 97 CALM 30.19R VSB 1/4 $$ MEZ002-015-021-024-NHZ003-005-008-011-012-014-VTZ005-008-030900- NORTHERN NEW ENGLAND CITY SKY/WX TMP DP RH WIND PRES REMARKS PORTLAND ME CLEAR 45 43 93 CALM 30.13S BANGOR ME CLEAR 45 41 86 W6 30.10R CONCORD NH CLOUDY 42 41 96 CALM 30.15F MANCHESTER NH CLOUDY 46 43 89 CALM 30.14R NASHUA NH MOCLDY 44 42 93 CALM 30.16S PORTSMOUTH NH NOT AVBL JAFFREY NH FOG 41 40 96 CALM 30.16S VSB 1/4 KEENE NH NOT AVBL BURLINGTON VT MOCLDY 45 42 89 CALM 30.11F MT. WASHINGTON CLOUDY 36 18 48 NW55 N/A WCI 19 $$ NYZ052-076-030900- EASTERN NEW YORK CITY SKY/WX TMP DP RH WIND PRES REMARKS ALBANY PTCLDY 50 47 89 S6 30.15F NEW YORK CITY PTCLDY 60 49 66 CALM 30.18S $$ ANZALL-030900- MARINE OBSERVATIONS STATION/POSITION TIME TEMP WIND PRES VSBY WAVE AIR SEA DIR/SP/G HT/PER (UTC) (F) (DEG/KT/KT) (MB) (MI) (FT/S) BOSTON BUOY 0700 55 56 240/ 4/ 6 1021.1F 3/ 7 BUZZARDS BAY 0700 57 63 60/ 2/ 3 1021.5F SE OF CAPE COD 0700 60 62 330/ 10/ 12 1020.7S 5/ 6 S OF MONTAUK PT 0700 64 64 290/ 8/ 8 1022.0S 3/12 MASS BAY-STELLWA 0700 55 58 260/ 8/ 10 1020.5R 1 7/8 3/ 6 ISLE OF SHOALS 0700 53 260/ 9/ 10 1020.6R $$ ......................KEY......................... SKY/WX - SKY CONDITION/PRESENT WEATHER TMP - TEMPERATURE IN FAHRENHEIT DWPT - DEWPOINT IN FAHRENHEIT RH - RELATIVE HUMIDITY IN PERCENT WIND - DIRECTION AND SPEED IN MPH PRES - MEAN SEA LEVEL PRESSURE IN INCHES OF HG WCI - WIND CHILL INDEX VSB - VISIBILITY IN MILES HX - HEAT INDEX TC - TEMPERATURE IN CELSIUS VRB - VARIABLE WIND DIRECTION N/A - NOT AVAILABLE |
ASUS41 KGYX 030808 RWRGYX WEATHER ROUNDUP FOR MAINE AND NEW HAMPSHIRE NATIONAL WEATHER SERVICE GRAY ME 400 AM EDT TUE OCT 03 2006 MEZ002-005-006-010-012-015-018-020-021-024-026-027-029-030900- MAINE CITY SKY/WX TMP DP RH WIND PRES REMARKS PORTLAND CLEAR 45 43 93 CALM 30.13S WISCASSET NOT AVBL FRYEBURG FOG 39 37 93 CALM 30.13R VSB 3/4 AUGUSTA NOT AVBL BANGOR NOT AVBL GREENVILLE N/A 45 42 89 CALM 30.05S MILLINOCKET NOT AVBL HOULTON NOT AVBL PRESQUE ISLE NOT AVBL FRENCHVILLE NOT AVBL CARIBOU CLOUDY 44 41 89 SW3 30.00R $$ NHZ002-005-008-009-011-012-014-030900- NEW HAMPSHIRE CITY SKY/WX TMP DP RH WIND PRES REMARKS ROCHESTER PTCLDY 46 44 93 CALM 30.14S MANCHESTER NOT AVBL CONCORD CLOUDY 42 41 96 CALM 30.15F BERLIN CLOUDY 41 40 96 CALM 30.14R WHITEFIELD FOG 41 41 100 CALM 30.15R VSB 1/4 JAFFREY NOT AVBL LEBANON NOT AVBL MT WASHINGTON CLOUDY 36 18 48 NW55 N/A $$ VTZ005-007-008-030900- VERMONT CITY SKY/WX TMP DP RH WIND PRES REMARKS ST JOHNSBURY N/A 44 43 96 MISG 30.14R MONTPELIER FOG 41 39 93 CALM 30.16S VSB 1/2 BURLINGTON MOCLDY 45 42 89 CALM 30.11F $$ MAZ007-012-024-CTZ003-RIZ002-NYZ038-NYZ072-030900- SOUTHERN NEW ENGLAND AND NY CITY SKY/WX TMP DP RH WIND PRES REMARKS PROVIDENCE PTCLDY 48 46 93 SW5 30.17S HARTFORD CLEAR 47 45 93 CALM 30.17S ALBANY PTCLDY 50 47 89 S6 30.15F NEW YORK CITY PTCLDY 60 49 66 CALM 30.18S $$ ANZ081-ANZ082-ANZ150-NHZ014-MEZ023>029-030900- COASTAL MARINE OBSERVATIONS STATION/POSITION TIME TEMP WIND PRES WAVE AIR SEA DIR/SP/G HT/PER (UTC) (F) (DEG/KT/KT) (MB) (FT/S) MATINICUS ROCK 0700 54 270/ 12/ 14 1018.6F PORTLAND WX BUOY 0700 54 56 260/ 10/ 12 1019.3S 3/13 ISLE OF SHOALS 0700 53 260/ 9/ 10 1020.6R CASHES LEDGE BUO 0700 56 56 N/A 3/11 GEORGES BANK BUO 0700 59 60 320/ 16/ 19 1017.4R 7/ 7 $$ .............KEY.............. WCI - WIND CHILL TC - TEMPERATURE IN CELSIUS VSB - VISIBILITY IN MILES HX - HEAT INDEX FAIR- INDICATES FEW OR NO CLOUDS BELOW 12,000 FT, WITH NO SIGNIFICANT WEATHER AND/OR OBSTRUCTIONS TO VISIBILITY. |
ASUS41 KBUF 030800 RWRBUF BUFFALO CLEAR 60/16 54 81 30.04F S 7 |
ASUS41 KPHI 030710 RWRPHI REGIONAL WEATHER ROUNDUP NATIONAL WEATHER SERVICE MOUNT HOLLY NJ 300 AM EDT TUE OCT 03 2006 NOTE: "FAIR" INDICATES FEW OR NO CLOUDS BELOW 12,000 FEET WITH NO SIGNIFICANT WEATHER AND/OR OBSTRUCTIONS TO VISIBILITY. * = STATION DOES NOT REPORT PRECIPITATION (E.G. RAIN, SNOW, ETC.) OR FOG. NJZ015>026-030800- SOUTHERN NEW JERSEY CITY SKY/WX TMP DP RH WIND PRES REMARKS POMONA MOCLDY 52 48 86 CALM 30.22S $$ NJZ001>014-030800- NORTHERN NEW JERSEY CITY SKY/WX TMP DP RH WIND PRES REMARKS ANDOVER N/A 47 45 93 CALM 30.20S NEWARK NOT AVBL $$ PAZ043-044-047-054-055-060>062-066>071-030800- EASTERN PENNSYLVANIA CITY SKY/WX TMP DP RH WIND PRES REMARKS PHILADELPHIA NOT AVBL ALLENTOWN FAIR 50 47 89 NW5 30.20S WILKES BARRE CLOUDY 50 47 89 E3 30.19S $$ DEZALL-MDZ008-012-015-019-020-030800- DELAWARE AND EASTERN MARYLAND CITY SKY/WX TMP DP RH WIND PRES REMARKS WILMINGTON NOT AVBL PATUXENT FAIR 60 55 83 CALM 30.21R OCEAN CITY NOT AVBL WALLOPS ISLAND FAIR 58 53 84 CALM 30.22S $$ PAZ001-021-NYZ056-072-MDZ011-DCZ001-030800- OTHER NEARBY LOCATIONS CITY SKY/WX TMP DP RH WIND PRES REMARKS BINGHAMTON NOT AVBL NEW YORK CITY FAIR 59 51 75 CALM 30.22R BALTIMORE NOT AVBL WASHINGTON DC NOT AVBL $$ |
ASUS41 KALY 030710 RWRALY NEW YORK STATE HOURLY WEATHER ROUNDUP NATIONAL WEATHER SERVICE ALBANY NY 300 AM EDT TUE OCT 03 2006 NOTE: "FAIR" INDICATES FEW OR NO CLOUDS BELOW 12,000 FEET WITH NO SIGNIFICANT WEATHER AND/OR NO OBSTRUCTIONS TO VISIBILITY. NYZ032-033-038>043-046>054-057>066-NYZ062>081-030800- EAST CITY SKY/WX TMP DP RH WIND PRES REMARKS ALBANY FAIR 48 46 93 S3 30.17R GLENS FALLS NOT AVBL POUGHKEEPSIE NOT AVBL NEW YORK CITY NOT AVBL CENTRAL PARK FAIR 59 51 75 CALM 30.22R $$ NYZ005>009-017-018-044>046-055-056-030800- CENTRAL CITY SKY/WX TMP DP RH WIND PRES REMARKS SYRACUSE FAIR 47 45 93 E6 30.11F UTICA NOT AVBL ELMIRA NOT AVBL BINGHAMTON NOT AVBL $$ NYZ026>034-041>043-030800- NORTH CITY SKY/WX TMP DP RH WIND PRES REMARKS WATERTOWN NOT AVBL FORT DRUM NOT AVBL MASSENA NOT AVBL $$ NYZ001>004-010>016-019>021-030800- WEST CITY SKY/WX TMP DP RH WIND PRES REMARKS BUFFALO FAIR 60 53 77 SW7 30.06S ROCHESTER MOCLDY 57 53 86 SW6 30.06F $$ KEY WCI = WIND CHILL INDEX VSB = VISIBILITY HX = HEAT INDEX $$ |
ASUS41 KOKX 030710 RWROKX REGIONAL WEATHER ROUNDUP NATIONAL WEATHER SERVICE UPTON NY 300 AM EDT TUE OCT 03 2006 NOTE: "FAIR" INDICATES FEW OR NO CLOUDS BELOW 12,000 FEET WITH NO SIGNIFICANT WEATHER AND/OR OBSTRUCTIONS TO VISIBILITY. NYZ071-072-076-NJZ005-030800- NEW YORK CITY METRO AREA CITY SKY/WX TMP DP RH WIND PRES REMARKS CENTRAL PARK FAIR 59 51 75 CALM 30.22R LAGUARDIA APRT NOT AVBL KENNEDY INTL NOT AVBL NEWARK/LIBERTY NOT AVBL WHITE PLAINS NOT AVBL $$ NYZ077>081-030800- LONG ISLAND NEW YORK CITY SKY/WX TMP DP RH WIND PRES REMARKS FARMINGDALE NOT AVBL ISLIP NOT AVBL SHIRLEY NOT AVBL WESTHAMPTON NOT AVBL MONTAUK POINT N/A 53 48 83 CALM 30.19S $$ NYZ052-065-067-030800- HUDSON VALLEY CITY SKY/WX TMP DP RH WIND PRES REMARKS NEWBURGH NOT AVBL MONTGOMERY NOT AVBL POUGHKEEPSIE NOT AVBL ALBANY FAIR 48 46 93 S3 30.17R $$ NJZ001-003-005-008-013-015-019-021-022-030800- NEW JERSEY CITY SKY/WX TMP DP RH WIND PRES REMARKS TETERBORO NOT AVBL CALDWELL NOT AVBL SOMERVILLE NOT AVBL ANDOVER N/A 47 45 93 CALM 30.20S TRENTON NOT AVBL MILLVILLE NOT AVBL WRIGHTSTOWN NOT AVBL BELMAR NOT AVBL $$ PAZ047>061-062-071-030800- EASTERN PENNSYLVANIA CITY SKY/WX TMP DP RH WIND PRES REMARKS PHILADELPHIA NOT AVBL ALLENTOWN FAIR 50 47 89 NW5 30.20S SCRANTON NOT AVBL $$ CTZ002-004>006-009-010-012-RIZ004-006-007-MAZ004-011-015-030800- SOUTHERN NEW ENGLAND IN CT CITY SKY/WX TMP DP RH WIND PRES REMARKS BRADLEY INTL FAIR 48 46 93 CALM 30.17S HARTFORD NOT AVBL DANBURY NOT AVBL WTRBRY/OXFORD NOT AVBL BRIDGEPORT FAIR 52 46 80 CALM 30.19R MERIDEN NOT AVBL NEW HAVEN NOT AVBL GROTON NOT AVBL WILLIMANTIC NOT AVBL IN RI CITY SKY/WX TMP DP RH WIND PRES REMARKS PROVIDENCE FAIR 49 46 90 W5 30.17F BLOCK ISLAND NOT AVBL WESTERLY NOT AVBL IN MA CITY SKY/WX TMP DP RH WIND PRES REMARKS BOSTON NOT AVBL WORCESTER NOT AVBL WESTFIELD NOT AVBL PROVINCETOWN NOT AVBL NANTUCKET NOT AVBL $$ ANZ350-353-355-338-335-330-030800- COASTAL MARINE OBSERVATIONS STATION/POSITION TIME SKY/WX TEMP WIND PRES VSBY WAVE AIR SEA DIR/SP/G HT/PER (UTC) (F) (DEG/KT/KT) (MB) (MI) (FT/S) AMBROSE LIGHT 0600 63 66 270/ 2/ 2 1022.9 BUOY 20S FIRE IS 0600 65 65 200/ 2/ 4 1022.5 2/13 BUOY 23SW MTP 0600 64 65 290/ 6/ 8 1022.0 3/12 CENTRAL LI SOUND 0600 64 67 300/ 8/ 8 1022.1 ROBBINS REEF 0500 62 CALM 1023.0 $$ >>>>>>>>>>>>>>>>>>>>>>>>>>>> KEY <<<<<<<<<<<<<<<<<<<<<<<<<<< > < > SKY/WX - SKY CONDITION/PRESENT WEATHER < > TMP - TEMPERATURE IN FAHRENHEIT < > DP - DEWPOINT IN FAHRENHEIT < > RH - RELATIVE HUMIDITY IN PERCENT < > WIND - DIRECTION AND SPEED IN MPH < > PRES - MEAN SEA LEVEL PRESSURE IN INCHES OF HG < > WCI - WIND CHILL INDEX < > VSB - VISIBILITY IN MILES < > HX - HEAT INDEX < > TC - TEMPERATURE IN CELSIUS < > VRB - VARIABLE WIND DIRECTION < > < >>>>>>>>>>>>>>>>>>>>>>>>>>>> KEY <<<<<<<<<<<<<<<<<<<<<<<<<<< |
ASUS41 KBOX 030710 RWRBOX REGIONAL WEATHER ROUNDUP NATIONAL WEATHER SERVICE TAUNTON MA 300 AM EDT TUE OCT 03 2006 NOTE: "FAIR" INDICATES FEW OR NO CLOUDS BELOW 12,000 FEET WITH NO SIGNIFICANT WEATHER AND/OR OBSTRUCTIONS TO VISIBILITY. THE FOLLOWING OBSERVATION LOCATIONS DO NOT REPORT PRESENT WEATHER...PROVINCETOWN... SMITHFIELD...BLOCK ISLAND...KEENE...AND OXFORD. MAZALL-030800- EASTERN MASSACHUSETTS CITY SKY/WX TMP DP RH WIND PRES REMARKS BOSTON NOT AVBL BEVERLY NOT AVBL LAWRENCE NOT AVBL BEDFORD NOT AVBL BLUE HILL N/A 52 46 80 SW7 30.15S NORWOOD NOT AVBL MARSHFIELD NOT AVBL PLYMOUTH NOT AVBL TAUNTON NOT AVBL NEW BEDFORD NOT AVBL $$ MAZALL-030800- CAPE COD AND THE ISLANDS CITY SKY/WX TMP DP RH WIND PRES REMARKS FALMOUTH NOT AVBL HYANNIS NOT AVBL CHATHAM NOT AVBL NANTUCKET NOT AVBL MARTHAS VNYRD NOT AVBL $$ MAZALL-030800- CENTRAL AND WESTERN MASSACHUSETTS CITY SKY/WX TMP DP RH WIND PRES REMARKS WORCESTER NOT AVBL FITCHBURG NOT AVBL ORANGE NOT AVBL SPRINGFIELD NOT AVBL WESTFIELD NOT AVBL NORTH ADAMS NOT AVBL $$ RIZALL-030800- RHODE ISLAND CITY SKY/WX TMP DP RH WIND PRES REMARKS PROVIDENCE FAIR 49 46 90 W5 30.17F NEWPORT NOT AVBL WESTERLY NOT AVBL $$ CTZALL-030800- CONNECTICUT CITY SKY/WX TMP DP RH WIND PRES REMARKS BRADLEY INTL FAIR 48 46 93 CALM 30.17S HARTFORD NOT AVBL BRIDGEPORT FAIR 52 46 80 CALM 30.19R GROTON NOT AVBL NEW HAVEN NOT AVBL MERIDEN NOT AVBL WILLIMANTIC NOT AVBL $$ MEZ002-015-021-024-NHZ003-005-008-011-012-014-VTZ005-008-030800- NORTHERN NEW ENGLAND CITY SKY/WX TMP DP RH WIND PRES REMARKS PORTLAND ME NOT AVBL BANGOR ME NOT AVBL CONCORD NH FOG 39 39 100 CALM 30.15F VSB 3/4 MANCHESTER NH NOT AVBL NASHUA NH NOT AVBL PORTSMOUTH NH NOT AVBL JAFFREY NH NOT AVBL KEENE NH NOT AVBL BURLINGTON VT FAIR 45 43 93 CALM 30.13R MT. WASHINGTON CLOUDY 37 19 48 NW52 N/A WCI 22 $$ NYZ052-076-030800- EASTERN NEW YORK CITY SKY/WX TMP DP RH WIND PRES REMARKS ALBANY FAIR 48 46 93 S3 30.17R NEW YORK CITY NOT AVBL $$ ANZALL-030800- MARINE OBSERVATIONS STATION/POSITION TIME TEMP WIND PRES VSBY WAVE AIR SEA DIR/SP/G HT/PER (UTC) (F) (DEG/KT/KT) (MB) (MI) (FT/S) BOSTON BUOY 0600 56 57 270/ 6/ 8 1021.2R 2/ 7 BUZZARDS BAY 0600 58 63 30/ 4/ 4 1021.8R SE OF CAPE COD 0600 60 62 340/ 12/ 14 1020.7R 5/ 6 S OF MONTAUK PT 0600 64 65 290/ 6/ 8 1022.0R 3/12 MASS BAY-STELLWA NOT AVBL ISLE OF SHOALS 0600 53 250/ 8/ 9 1020.2S $$ ......................KEY......................... SKY/WX - SKY CONDITION/PRESENT WEATHER TMP - TEMPERATURE IN FAHRENHEIT DWPT - DEWPOINT IN FAHRENHEIT RH - RELATIVE HUMIDITY IN PERCENT WIND - DIRECTION AND SPEED IN MPH PRES - MEAN SEA LEVEL PRESSURE IN INCHES OF HG WCI - WIND CHILL INDEX VSB - VISIBILITY IN MILES HX - HEAT INDEX TC - TEMPERATURE IN CELSIUS VRB - VARIABLE WIND DIRECTION N/A - NOT AVAILABLE |
ASUS41 KGYX 030708 RWRGYX WEATHER ROUNDUP FOR MAINE AND NEW HAMPSHIRE NATIONAL WEATHER SERVICE GRAY ME 300 AM EDT TUE OCT 03 2006 MEZ002-005-006-010-012-015-018-020-021-024-026-027-029-030800- MAINE CITY SKY/WX TMP DP RH WIND PRES REMARKS PORTLAND NOT AVBL WISCASSET NOT AVBL FRYEBURG NOT AVBL AUGUSTA NOT AVBL BANGOR NOT AVBL GREENVILLE N/A 44 42 93 VRB3 30.05S MILLINOCKET NOT AVBL HOULTON NOT AVBL PRESQUE ISLE NOT AVBL FRENCHVILLE NOT AVBL CARIBOU CLOUDY 43 40 89 W5 29.99S $$ NHZ002-005-008-009-011-012-014-030800- NEW HAMPSHIRE CITY SKY/WX TMP DP RH WIND PRES REMARKS ROCHESTER NOT AVBL MANCHESTER NOT AVBL CONCORD FOG 39 39 100 CALM 30.15F VSB 3/4 BERLIN NOT AVBL WHITEFIELD NOT AVBL JAFFREY NOT AVBL LEBANON NOT AVBL MT WASHINGTON CLOUDY 37 19 48 NW52 N/A $$ VTZ005-007-008-030800- VERMONT CITY SKY/WX TMP DP RH WIND PRES REMARKS ST JOHNSBURY N/A 44 43 96 MISG 30.13F BURLINGTON FAIR 45 43 93 CALM 30.13R $$ MAZ007-012-024-CTZ003-RIZ002-NYZ038-NYZ072-030800- SOUTHERN NEW ENGLAND AND NY CITY SKY/WX TMP DP RH WIND PRES REMARKS PROVIDENCE FAIR 49 46 90 W5 30.17F HARTFORD FAIR 48 46 93 CALM 30.17S ALBANY FAIR 48 46 93 S3 30.17R $$ ANZ081-ANZ082-ANZ150-NHZ014-MEZ023>029-030800- COASTAL MARINE OBSERVATIONS STATION/POSITION TIME TEMP WIND PRES WAVE AIR SEA DIR/SP/G HT/PER (UTC) (F) (DEG/KT/KT) (MB) (FT/S) MOUNT DESERT ROC 0600 53 300/ 12/ 13 1018.9R MATINICUS ROCK 0600 54 280/ 10/ 11 1018.7R PORTLAND WX BUOY 0600 53 56 270/ 8/ 10 1019.3S 2/14 ISLE OF SHOALS 0600 53 250/ 8/ 9 1020.2S CASHES LEDGE BUO 0600 56 56 N/A 4/13 GEORGES BANK BUO 0600 59 60 320/ 16/ 17 1017.2R 8/ 8 $$ .............KEY.............. WCI - WIND CHILL TC - TEMPERATURE IN CELSIUS VSB - VISIBILITY IN MILES HX - HEAT INDEX FAIR- INDICATES FEW OR NO CLOUDS BELOW 12,000 FT, WITH NO SIGNIFICANT WEATHER AND/OR OBSTRUCTIONS TO VISIBILITY. |
ASUS41 KBUF 030700 RWRBUF BUFFALO MAINLY CLEAR 60/16 53 78 30.06S SW 7 |
El archivo con el código html de esta página puede descargarse en el siguiente enlace: hourly.html.
El comienzo de la página contiene información no relacionada con nuestro objetivo. Mirando la parte inferior se observa que cada línea de datos comienza con el nombre de la ciudad, seguido por un conjunto de datos meteorológicos, formateados en columnas. Por tanto, para buscar la información sobre una determinada ciudad basta con encontrar la línea en que se encuentra este nombre y extraer la información necesaria. Este es el enfoque que se seguirá en este ejemplo.
La función básica del MIDlet a construir es establecer una conexión de red y recuperar el contenido de una página Web, que se analizará para buscar la información deseada, que se mostrará en la pantalla del terminal.
Para tener más control en el desarrollo de la aplicación se divide el proceso de desarrollo en tres etapas:
La interfaz de usuario
El MIDlet está diseñado de forma que el usuario debe ser capaz de introducir la ciudad y el estado del que se busca la información meteorológica. Tras obtener la información se precisa alguna forma de presentación de los datos obtenidos. Por tanto sería conveniente disponer de dos pantallas diferentes: una para gestionar la introducción de ciudad y estado y otra diferente para mostrar la información recogida de la página Web. En definitiva. el usuario introduce la ciudad y el estado y, tras pulsar un botón, se realiza la conexión para obtener el contenido de la página. Tras su análisis los resultados se presentarán en la pantalla correspondiente. Los resultados se limitan a presentar la información sobre condiciones generales, temperatura, humedad relativa, velocidad del viento y dirección. La pantalla donde se mostrará esta información se denominará pantalla de salida.
Además, será preciso disponer de varios comandos para controlar el funcionamiento de la aplicación. La pantalla de localización, donde se introduce el estado y la ciudad, precisa de un comando Ir que inicia la recuperación de datos. Como esta pantalla será, de alguna forma, la pantalla principal de la aplicación, es conveniente disponer de un comando Salir que finaliza la aplicación. Además, la pantalla de salida precisa de una comando Atrás que permita volver a la pantalla inicial.
Para realizar las pantallas se utilizan varios componentes de la interfaz de usuario que se almacenan como datos miembros del MIDlet Tiempo. La declaración de datos miembros es la siguiente:
// Definicion de los comandos private Command comandoSalir, comandoIr, comandoAtras; // Display del dispositivo movil private Display display; // Especificacion del formulario de localizacion y de los campos de texto // que se usaran en el private Form pantallaLocalizacion; private TextField campoCiudad, campoEstado; // Especificacion del formulario de condiciones y de los textos que se // mostraran en el private Form pantallaCondiciones; private StringItem localizacion, condiciones, temperatura, humedad, viento;
Por su parte, el constructor de la clase se muestra a continuación:
// Constructor de la clase Tiempo public Tiempo() { // Obtiene una referencia al display display = Display.getDisplay(this); // Se crean los comandos necesarios comandoSalir = new Command("Salir", Command.EXIT, 2); comandoIr = new Command("Ir", Command.OK, 2); comandoAtras = new Command("Atras", Command.BACK, 2); // Se crea el formulario de localizacion pantallaLocalizacion = new Form("Introduzca localización"); // Se crea el campo de texto para introducir la ciudad campoCiudad = new TextField("Ciudad", "", 25, TextField.ANY); // Se agrega a la pantalla de localizacion pantallaLocalizacion.append(campoCiudad); // Se crea el campo de texto para introducir el estado campoEstado = new TextField("Estado", "", 2, TextField.ANY); // Se agrega el campo a la pantalla de localización pantallaLocalizacion.append(campoEstado); // Asocia los comandos de salida y de proceder a la busqueda pantallaLocalizacion.addCommand(comandoSalir); pantallaLocalizacion.addCommand(comandoIr); // Se asocia a la pantalla el gestor de comandos pantallaLocalizacion.setCommandListener(this); // Se crea el formulario de la pantalla de condiciones pantallaCondiciones = new Form("Condiciones actuales"); // Se crean los items de texto que apareceran en la pantalla. Se // comienza por el de localizacion localizacion = new StringItem("", ""); pantallaCondiciones.append(localizacion); // Se crea el string para las condiciones condiciones = new StringItem("", ""); pantallaCondiciones.append(condiciones); // Lo mismo para la temperatura temperatura = new StringItem("", ""); pantallaCondiciones.append(temperatura); // Igual para la humedad humedad = new StringItem("", ""); pantallaCondiciones.append(humedad); // Igual para el viento viento = new StringItem("", ""); pantallaCondiciones.append(viento); // Se asocia el comando Atrás a la pantalla de condiciones pantallaCondiciones.addCommand(comandoAtras); pantallaCondiciones.setCommandListener(this); }
El MIDlet que estamos construyendo consta de tres comandos: Salir, Ir y Atrás. El comando de salida ya se usó en el MIDlet previo, pero el funcionamiento de los otros dos precisa quizás algunos comentarios adicionales. El comando Ir está asociado a la pantalla de localización y es responsable de iniciar la recogida y presentación de datos meteorológicos sobre la ciudad y estado que el usuario haya introducido. El comando Atrás está asociado a la pantalla de condiciones y tiene como misión provocar que aparezca de nuevo la pantalla de localización, de forma que el usuario del MIDlet pueda volver a introducir otra ciudad y estado (o bien que se salga de aplicación). El método responsable de gestionar los comandos e implementar su funcionalidad se presenta a continuación:
// Método commandAction public void commandAction(Command comando, Displayable pantalla) { // Si se trata del comando salir, se sale de la aplicación. Se usa // false como argumento if (comando == comandoSalir) { destroyApp(false); notifyDestroyed(); } // Si el comando es Ir, se procede a obtener la información else if (comando == comandoIr) { // Se obtiene la información para el estado y ciudad indicados obtenerCondiciones(campoCiudad.getString().toUpperCase(), campoEstado.getString().toLowerCase()); } // Si el comando es Atras, se vuelve a la pantalla de localizacion else if (comando == comandoAtras) { // Se vacían los campos de ciudad y estado campoCiudad.setString(""); campoEstado.setString(""); // Se vuelve a la pantalla de localización display.setCurrent(pantallaLocalizacion); } }
Lectura de datos
El método obtenerCondiciones() lee la ciudad y el estado especificado y procede a leer los datos meteorológicos adecuados. La dirección URL de la página a consultar incluye las iniciales del estado en minúscula. Las iniciales de la ciudad, sin embargo, han de ir en mayúscula. De ahí la llamada a las funciones pertinentes para asegurarse que al producirse la conexión web la dirección URL esté convenientemente formada.
El corazón de la aplicación, por tanto, es el método encargado de obtener las condiciones meteorológicas deseadas. Este método debe realizar las siguientes tareas:
Estos pasos pueden apreciarse en el método, cuyo listado aparece a continuación:
// Método para obtener las condiciones meteorológicas private void obtenerCondiciones(String ciudad, String estado) { StreamConnection conexion = null; InputStream entrada = null; StringBuffer datos = new StringBuffer(); // Se intenta el establecimiento de la conexion. Esto debe hacerse // en un bloque try-catch try { // Se abre la conexion HTTP conexion = (StreamConnection)Connector.open("http://iwin.nws.noaa.gov/iwin/"+estado+"/hourly.html"); System.out.println("Conexion a : http://iwin.nws.noaa.gov/iwin/"+estado+"/hourly.html"); // Se obtiene el flujo de entrada de la conexion entrada = conexion.openInputStream(); // Se lee la entrada linea a linea int ch; boolean hecho = false; // Bucle de lectura. Si se alcanza el caracter -1 indica que no hay // mas datos while (((char)(ch = entrada.read()) != -1) && !hecho) { // Mientras no se lea el salto de linea if (ch != '\n') { // El caracter se agrega a los datos leidos datos.append((char)ch); } else { // Al ir leyendo vemos si aparece la ciudad buscada. Para que // pueda estar, la longitud de la cadena leida debe ser al menos // igual de larga que el nombre de la ciudad buscada if (datos.length() >= ciudad.length()) { // Se mira si la ciudad buscada es la primera palabra de la // linea leida if ((ciudad.length() > 0) && (datos.toString().substring(0, ciudad.length()).compareTo(ciudad) == 0)) { // Si se ha encontrado, se escriben los datos obtenidos localizacion.setText(ciudad + ", " + estado.toUpperCase()); // Se muestran las condiciones condiciones.setText("Cond.: " +datos.toString().substring(15, 22)); // Se extrae la temperatura y se muestra temperatura.setText("Temperatura: " +datos.toString().substring(25, 27) + '\260'); // Se extrae y muestra la humedad relativa humedad.setText("Humedad Rel.: " +datos.toString().substring(33, 35) + "%"); // Se extrae y muestra la velocidad del viento viento.setText("Viento: " +datos.toString().substring(36, 44) + " mph"); // Se muestra la pantalla de condiones display.setCurrent(pantallaCondiciones); // Se indica que se ha terminado, para no seguir leyendo hecho = true; } } // Se libera el string para leer los datos de la siguiente linea datos = new StringBuffer(); } } // Si al llegar aqui la variable booleana hecho vale false, // entonces se indica que hubo algun problema if (!hecho) display.setCurrent(new Alert("Tiempo","Localización no válida.", null, AlertType.ERROR)); } catch (IOException e) { System.err.println("Problema al establecer la conexión."); } }
Prueba del MIDlet
Tras compilar, preverificar y empaquetar el MIDlet, hay que probarlo en el emulador de Ktoolbar, por ejemplo. Para cubrir la funcionalidad siguiente se realizará el siguiente conjunto de acciones:
Ejercicio: completad el MIDlet anterior, montar el proyecto correspondiente y hacedlo funcionar.
Ejercicio: construid un MIDlet de consulta de distancias entre dos direcciones. Leed las notas siguientes para realizar este ejercicio:
Existen algunas páginas Web que permiten introducir una dirección de partida y otra de llegada y obtener la forma de alcanzar la segunda desde la primera. La idea de este ejercicio es usar estas páginas para construir un MIDlet que haga esta tarea desde un dispositivo móvil. En concreto, la página a usar es la de Microsoft MapPoint. Si se abre dicha página se obtiene una pantalla como la siguiente:
Conviene tener en cuentas las siguientes consideraciones:
Total Distance: 1.0 Kilometers Estimated Total Time: 5 minutes
Otra cosa a tener en cuenta es la posibilidad de que se produzca una redirección. Algunas veces, al teclear una dirección URL se produce un redireccionamiento directo a otra dirección distinta. Una posible forma de controlar esto sería como se indica en el siguiente fragmento de código:
// Método para realizar la conexion controlando la redireccion private void conectar() { HttpConnection conexion = null; InputStream entrada = null; StringBuffer datos = new StringBuffer(); String direccionURL="....la que sea...."; int respuesta=-1; int ch; System.out.println("Intento de conexion con: "+direccionURL); // Se intenta el establecimiento de la conexion. Esto debe hacerse // en un bloque try-catch try { // Se abre la conexion HTTP. Se hace bucle para volver a intentarlo // en caso de ser necesario, de haber redireccion while (true){ // Se intenta establecer la conexion conexion = (HttpConnection)Connector.open(direccionURL,Connector.READ_WRITE); // Se obtiene el codigo de respuesta a la peticion de conexion respuesta=conexion.getResponseCode(); // Por si queremos ver la respuesta por pantalla System.out.println("Respuesta: "+respuesta); // Si hay redireccion, se controla if (respuesta == HttpConnection.HTTP_TEMP_REDIRECT || respuesta == HttpConnection.HTTP_MOVED_TEMP || respuesta == HttpConnection.HTTP_MOVED_PERM) { // Se obtiene la nueva direccion direccionURL = conexion.getHeaderField("location"); direccionURL="http://maps.msn.com/"+direccionURL; // Se muestra por pantalla la nueva direccion System.out.println("Nueva direccion: "+direccionURL); conexion.close(); } else { // Si se pudo conectar, se rompe el bucle break; } } // Se controla, pese a todo, si hubo algun otro error if (respuesta != HttpConnection.HTTP_OK){ conexion.close(); System.out.println("Codigo error: "+respuesta); // En este caso se destruye el MIDlet destroyApp(true); notifyDestroyed(); } } catch (IOException e) { System.err.println("Problema al establecer la conexión."); // En este caso se destruye el MIDlet destroyApp(true); notifyDestroyed(); } // Si se llega aqui, la conexion esta realizada // a la lectura de la informacion ................................ }
En las aplicaciones Web es muy usual, como hemos visto, tener que rellenar datos en un formulario para solicitar información, registro, etc. Cuando el usuario de la página pulsa sobre el botón Enviar, el contenido de la página es procesado por un programa denominado CGI (Common Gateway interface). Los CGIs residen en el servidor y tienen como objetivo leer los datos introducidos por el usuario y componer una nueva página Web que se muestra en el navegador, conteniendo, normalmente, información para el usuario (subscripción correcta, falta de datos, página de registro, etc). Este mecanismo, sin embargo, presenta varios problemas:
Estas razones originan la aparición de la tecnología servlet. De esta forma, se hace que cada ejecución se haga en una hebra (y no en un proceso aparte) y que, al mismo tiempo, se pueda controlar los privilegios de seguridad del servlet.
Desde el punto de vista de programación del dispositivo móvil, lo que interesa saber es la forma de enviar datos a un servlet, de forma que este pueda realizar su trabajo. Esto es muy similar a los ejemplos vistos anteriormente. En realidad, en el ejemplo de las distancias entre direcciones, se estaba haciendo esto. La forma de especificar la dirección URL de un servlet es:
http://host/servlet?parámetros
Hay que tener en cuenta varias consideraciones a la hora de especificar los argumentos. En primer lugar, los argumentos se separan mediante el carácter &. Los espacios en blanco deben sustituirse por el carácter +. Los caracteres alfanuméricos deben cambiarse por % seguido del número hexadecimal que representa el código del carácter a representar. Por ejemplo, si se quiere enviar como argumento S. Antonio, entonces habrá que escribir S%2e+Antonio. Esto es así ya que el número hexadecimal 2e es el código ASCII del carácter ".".
En la dirección http://sesamo.ugr.es:8080/calcAvanzada se ha instalado el servlet calculadora, cuya misión es realizar operaciones aritméticas que no pueden realizarse en el dispositivo móvil, como por ejemplo, senos y logaritmos. Los parámetros de este servlet son:
Tanto el establecimiento de la conexión como la lectura de datos se realiza de forma análoga a como se ha visto en el resto de ejemplo.