Ver Mensaje Individual
  #1  
Antiguo 06-05-2007
Avatar de gluglu
[gluglu] gluglu is offline
Miembro Premium
 
Registrado: sep 2004
Ubicación: Málaga - España
Posts: 1.455
Reputación: 22
gluglu Va por buen camino
Datos Meteorológicos

Estimados Compañeros del Foro :

Aquí os dejo mi versión de la lectura e interpretación de los datos meteorológicos obtenidos a traves del ftp de tgftp.nws.noaa.gov

Antes de pasar al código en sí mismo expongo las características particulares del código así como los componentes a incluir en el Form.

1. Leo los datos a partir de un TThread (METAR) creado para tal finalidad que se va a ejecutar cada cierto intervalo de tiempo, según viene definido en un componente adicional TTimer. En el ejemplo el intervalo está puesto a 600000, es decir, cada 10 minutos. Para saber si ha transcurrido el intervalo de 10 minuts establecido para volver a leer datos del FTP, hago uso de la propiedad Tag del propio TTimer.

2. Los datos del FTP se obtienen a través de un IdFTP de los componentes Indy.

3. En mi caso particular, muestro los datos en una barra de estado que a su vez contiene dos TLabels para la temperatura (LabelStMet1 y LabelStMet2), siendo LabelStMet2.Caption := 'ºC' un label fijo. El valor absoluto de la temperatura en grados centígrados se mostrará en el LabelStMet1.

4. Para mostrar el estado del cielo hago uso de dos TLabels adicionales (LabelStMet3 y LabelStMet4), que también se encuentran en la barra de estado al lado de la temperatura que me mostrarán símbolos obtenidos del juego de caracteres de font 'Wingdings 2' y 'Webdings'.

No puedo mostrar aquí los símbolos correspondientes, pero expongo los valores de caracteres que he utilizado en cada caso:

Cielo Despejado : Wingdings2 Chr(208)
Cielo Parcialmente Cubierto : Webdings Chr(158)
Cielo Casi Cubierto : Webdings Chr(157)
Cielo Totalmente Cubierto : Webdings Chr(235)

Lluvia : Webdings Chr(234)
Tormenta : Webdings Chr(154)
Nieve : Webdings Chr(233)

Al no tener un símbolo para Nubes y Claros, hago uso de los dos labels anteriormente expuestos, uno con el Cielo Despejado y otro con Cielo Totalmente Cubierto, predominando claramente el del Cielo Despejado por delante del Cielo Totalmente Cubierto. De esta manera consigo el efecto deseado de un sol grande delante de una nube pequeña.

5. La localización para el ejemplo es Málaga (código OACI = LEMG). Cada cual debería coger el aeropuerto de referencia más cercano a su localización. Más abajo os dejo la página para consultar tanto los códigos de aeropuertos españoles, como de cualquier aeropuerto del mundo.

En mi caso particular grabo la lectura del FTP en el directorio principal de mi disco duro C:. Se puede hacer de otras muchas maneras, por ejemplo también con un TMemoryStream, en vez de grabarlo a un fichero almacenado en el disco duro. Lo que pasa es que necesito ese fichero en mi disco duro para otros fines posteriores. (Aunque podreis ver que en el código incluido se borra al final).

6. La hora expresada en los METAR siempre es hora UTC. Por lo tanto si se quiere convertir en hora oficial de cada localización habrá que saber el Huso horario correspondiente y si tiene o no horario de verano en la fecha de lectura. Estos datos yo los tengo grabados en otra base de datos particular, pero a fines de ejemplo creí más conveniente eliminar dicho código e indicar directamente que en este caso he sumado 2 horas a la hora obtenida del FTP (Málaga = GMT+1 y hay que añadirle a la fecha de hoy el adelante de +1 hora por el horario de verano).

7. El viento se expresa en el METAR con velocidad en nudos (KT) y en grados según la dirección desde donde provenga el viento. La conversión se ha hecho a Km/h (KT x 1852), y la dirección de viento se ha convertido de grados a puntos cardinales. La aproximación a cada punto cardinal principal es de +- 20º. Así obtenemos direcciones de viento tales como N, NE, E, SE, S, SW, W, y NW.

8. El METAR también refleja además si el viento es mantenido o existen rachas de viento (gusts). Si en el METAR se añade la letra 'G' de rachas de viento, estas se muestran en el texto final detrás de la velocidad del viento mantenido y su dirección, entre paréntesis y en Km/h.

9. La temperatura del METAR muestra la temperatura en ºC y el punto de rocío. Con este dato (creo poco significativo para la mayoría de la gente, a no ser que practiquemos la nautica ...) podemos obtener la Humedad Relativa mediante la fórmula mostrada por ejemplo en http://www.jccm.es/edu/ies/cperezpastor/dptos/fq/matcien/humedad.htm

10. Finalmente la presión atmosférica se muestra en milibares (mb).

Todos estos datos se acumulan en un String que se puede mostrar en cualquier otra parte del form y en el momento que se precise.

Un ejemplo de string resultante es : Málaga 10:00 : 25 Km/h NW 27 ºC 67% 1013 mb

Aquí va el código :

Código Delphi [-]
type
  TMainform = class(TForm)
  ...
 
  TMetar = class(TThread)
  protected
    procedure Execute; override;
  public
  end;
 
var
  Mainform : TMainform;
  Metar    : TMetar;
 
implementation
  ...
 
procedure TMainform.FormActivate(Sender: TObject);
begin
 
  Self.OnActivate := nil;
 
  IdFTP1.Host     := 'tgftp.nws.noaa.gov';
  IdFTP1.Username := 'anonymous';

  Timer1.Interval := 600000;  // 10 Minutes
  Timer1.Tag      := 1;
  Metar := TMetar.Create(False);
  Metar.FreeOnTerminate := True;
 
end;
 
procedure TMainform.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  ...
  Metar.Terminate;
end;
 
procedure TMainform.Timer1Timer(Sender: TObject);
begin
  Timer1.Tag := 1;
end;
 
procedure TMetar.Execute;
var
  Temp       : TFileStream;
  Aux_METAR  : TStringList;
  Aux_Temp   : String;
  Aux_Met    : String;
  Aux_Val    : Integer;
  Aux_Val2   : Real;
  Aux_Val3   : Integer;
begin
 
  if MainForm.Timer1.Tag = 1 then begin
 
    Temp := TFileStream.Create('C:\LEMG.Met', fmCreate);

    try
      MainForm.idFTP1.Connect;
      MainForm.idFTP1.Get('data/observations/metar/stations/LEMG.TXT', Temp, True);
      MainForm.idFTP1.Disconnect;
    except
      Temp.Free;
      Exit;
    end;
    Temp.Free;
 
    Aux_METAR := TStringList.Create;
    Aux_METAR.LoadFromFile('C:\LEMG.Met');
 
    Aux_Temp := IntToStr(StrToInt(Copy(Aux_METAR[0], PosEx('/', Aux_METAR[0], 18)-2, 2)));
    MainForm.LabelStMet1.Caption := Aux_Temp;
 
    MainForm.LabelStMet3.Visible := False;
    MainForm.LabelStMet4.Visible := False;
    if (PosEx('RA', Aux_METAR[0], 18) <> 0) or
       (PosEx('SH', Aux_METAR[0], 18) <> 0) or
       (PosEx('DZ', Aux_METAR[0], 18) <> 0) then begin
      // Rain
      MainForm.LabelStMet3.Visible := True;
      MainForm.LabelStMet4.Visible := False;
      MainForm.LabelStMet3.Caption := 'Û';
    end else
    if PosEx('SN', Aux_METAR[0], 18) <> 0 then begin
      // Snow
      MainForm.LabelStMet3.Visible    := True;
      MainForm.LabelStMet4.Visible    := False;
      MainForm.LabelStMet3.Caption    := 'Ú';
    end else
    if PosEx('TS', Aux_METAR[0], 18) <> 0 then begin
      // Snow
      MainForm.LabelStMet3.Visible    := True;
      MainForm.LabelStMet4.Visible    := False;
      MainForm.LabelStMet3.Caption    := 'Ü';
    end else
    if PosEx('OVC', Aux_METAR[0], 18) <> 0 then begin
      // OverCast
      MainForm.LabelStMet3.Visible    := True;
      MainForm.LabelStMet4.Visible    := False;
      MainForm.LabelStMet3.Caption    := 'Ù';
    end else
    if PosEx('BKN', Aux_METAR[0], 18) <> 0 then begin
      // Broken
      MainForm.LabelStMet3.Visible    := True;
      MainForm.LabelStMet4.Visible    := False;
      MainForm.LabelStMet3.Caption    := 'Ø';
    end else
    if PosEx('SCT', Aux_METAR[0], 18) <> 0 then begin
      // Scatered
      MainForm.LabelStMet3.Visible    := True;
      MainForm.LabelStMet4.Visible    := False;
      MainForm.LabelStMet3.Caption    := '×';
    end else
    if PosEx('FEW', Aux_METAR[0], 18) <> 0 then begin
      // Few
      MainForm.LabelStMet3.Visible    := True;
      MainForm.LabelStMet4.Visible    := True;
      MainForm.LabelStMet3.Caption    := 'Ù';
    end else begin
      MainForm.LabelStMet3.Visible    := False;
      MainForm.LabelStMet4.Visible    := True;
    end;
 
    // Localización y Hora
    Aux_Met := 'Malaga ';
    Aux_Val := StrToInt(Copy(Aux_METAR[0], PosEx('Z', Aux_METAR[0], 24)-4, 2));
    Aux_Val := Aux_Val + 2;   // Horario oficial actual GMT+2
    if Aux_Val < 10 then
      Aux_Temp := '0'+IntToStr(Aux_Val)
    else
      Aux_Temp := IntToStr(Aux_Val);
    Aux_Met := Aux_Met + Aux_Temp + ':' + Copy(Aux_METAR[0], PosEx('Z', Aux_METAR[0], 24)-2, 2) + ' :  ';
 
    // Viento
    Aux_Val3 := 0;
    if Pos('G', Copy(Aux_METAR[0], PosEx('KT', Aux_METAR[0], 24)-5, 5)) <> 0 then begin
      Aux_Val3 := StrToInt(Copy(Aux_METAR[0], PosEx('KT', Aux_METAR[0], 24)-2, 2));
      Aux_Val  := StrToInt(Copy(Aux_METAR[0], PosEx('G', Aux_METAR[0],24)-2, 2));
    end
    else begin
      Aux_Val  := StrToInt(Copy(Aux_METAR[0], Pos('KT', Aux_METAR[0])-2, 2));
    end;
 
    Aux_Val2 := 1.852 * Aux_Val;
    Aux_Temp := FormatFloat('0', Aux_Val2);
    Aux_Met := Aux_Met + Aux_Temp + ' Km/h ';
 
    if Aux_Val3 = 0 then
      Aux_Val  := StrToInt(Copy(Aux_METAR[0], PosEx('KT', Aux_METAR[0], 24)-5, 3))
    else
      Aux_Val  := StrToInt(Copy(Aux_METAR[0], PosEx('G', Aux_METAR[0], 24)-5, 3));
 
    // Dirección del Viento
    if Aux_Val <=  20 then Aux_Temp := 'N'  else
    if Aux_Val <=  70 then Aux_Temp := 'NE' else
    if Aux_Val <= 110 then Aux_Temp := 'E'  else
    if Aux_Val <= 160 then Aux_Temp := 'SE' else
    if Aux_Val <= 200 then Aux_Temp := 'N'  else
    if Aux_Val <= 250 then Aux_Temp := 'SW' else
    if Aux_Val <= 290 then Aux_Temp := 'W'  else
    if Aux_Val <= 340 then Aux_Temp := 'NW' else
    Aux_Temp := 'N';
    Aux_Met  := Aux_Met + Aux_Temp + ' ';
 
    // Rachas de Viento
    if Aux_Val3 <> 0 then begin
      Aux_Val2 := 1.852 * Aux_Val3;
      Aux_Temp := FormatFloat('0', Aux_Val2);
      Aux_Met := Aux_Met + '(' + Aux_Temp + ' Km/h)  ';
    end
    else
      Aux_Met := Aux_Met + ' ';
 
    // Temperatura
    Aux_Temp := IntToStr(StrToInt(Copy(Aux_METAR[0], PosEx('/', Aux_METAR[0], 18)-2, 2)));
    if Copy(Aux_METAR[0], PosEx('/', Aux_METAR[0], 18)-3, 1) = 'M' then Aux_Temp := '-'+Aux_Temp;
    Aux_Met  := Aux_Met + Aux_Temp + ' ºC  ';
 
    // Humedad Relativa
    Aux_Val  := StrToInt(Aux_Temp);
    if Copy(Aux_METAR[0], PosEx('/', Aux_METAR[0], 18)+1, 1) = 'M' then
      Aux_Temp := '-' + IntToStr(StrToInt(Copy(Aux_METAR[0], PosEx('/', Aux_METAR[0], 18)+2, 2)))
    else
      Aux_Temp := IntToStr(StrToInt(Copy(Aux_METAR[0], PosEx('/', Aux_METAR[0], 18)+1, 2)));
    Aux_Val3 := StrToInt(Aux_Temp);
    Aux_Val2 := 100 * Power((112 - (0.1 * Aux_Val) + Aux_Val3) / (112 + (0.9 * Aux_Val)),8);
    Aux_Temp := FormatFloat('0', Aux_Val2);
    Aux_Met  := Aux_Met + Aux_Temp + '%  ';
 
    // Presión atmosférica
    Aux_Temp := Copy(Aux_METAR[0], Pos('Q', Aux_METAR[0])+1, 4);
    Aux_Met  := Aux_Met + Aux_Temp + ' mb';
 
    MainForm.LabelPanelMet.Caption := Aux_Met;

    DeleteFile('C:\LEMG.Met');
    MainForm.Timer1.Tag := 0;
 
  end;
 
end;

Notas adicionales :

A. Para el cálculo de la humedad relativa es necesario elevar el número obtenido a una potencia, por lo que es necesario incluir en el Uses de nuestro programa la unidad 'Math'

B. El METAR obtenido del FTP indicado, incluye al comienzo la fecha y la hora del mismo, aunque esta venga después codificada dentro del propio código METAR. Por ello hago uso de la función PosEx y considero casi siempre el código de METAR a partir de la posición 28. Por ello también hay que incluir en el Uses de nuestro programa la unidad 'StrUtils'

C. La explicación completa de un METAR la podeis encontrar http://www.inm.es/web/sup/tiempo/infaero/pdf/Guia_MET.pdf

En este mismo documento, en el Anexo I vienen todos los códigos de los aeropuertos españoles.

Para obtener los códigos de cualquier otro aeropuerto mundial, yo utilizo http://www.ogimet.com/indicativos.phtml, que además contiene otros datos muy interesantes acerca de la meteorología obtenida de aeródromos. Su página principal es http://www.ogimet.com/

Espero os sirva este código.
Responder Con Cita