Weather METARs

Screenshots, descriptions and links to applications compiled with LB Booster, to illustrate how it is being used
User avatar
Posts: 63
Joined: Fri Apr 06, 2018 2:38 am
Location: Rome NY, USA

Weather METARs

Post by JackKelly »

Every hour or so, hundreds of weather stations throughout the world, mostly at airports, send data to a public server run by NOAA, an agency of the US government. Most of the stations are at least partially automated. Anyone can then access the current data from a station but the coding is bewildering. This program decodes the most commonly used codes and reports them in an understandable way.

Updated 11/9/23 for vertical visibility

Code: Select all

' Airport Weather Information, 11/11/23
WindowWidth = 1200: WindowHeight = 600
BackgroundColor$ = "191 191 255"

Statictext #1.Debug "", 0, 0, 500, 30
Textbox #1.AirportCode 50, 50, 200, 30
Statictext #1.Text "", 70, 85, 200, 30
TextEditor #1.Display 50, 150, 1100, 400
Button #1.Default "Enter", [ProcessAirport], UL, 280, 45, 70, 40
Button #1.Quit "Quit", Quit, UL, 380, 45, 70, 40
Statictext #1.Version "v. " + Version$, 1110, 552, 100, 15
open "AIRPORT WEATHER IFORMATION (USA & Canada Only)" for dialog as #1
#1 "Font ariel 14"
#1.Version "!Font ariel 10"
#1 "TrapClose Quit"


TestMETAR$="TEST 310325Z COR 05012G18KT 300V100 M1 3/4SM R30L/5000VP6000FT -SN XYFG VV007 M24/M30 A2993" 'maximum
'TestMETAR$="KRME 060953Z AUTO 00000KT 10SM OVC080 02/M01 A3019" 'normal
'TestMETAR$="PANC 090553Z 00000KT 1/2SM R07R/4500VP6000FT SN FG VV007 01/00 A2882" ' vertical visibility
'TestMETAR$="CYYZ 112100Z 14004KT 360V170 15SM FEW030 OVC038 03/M02 A3043" 'north wind direction

if Airport$="" then
        #1.Text " Enter Airport Code"
        #1.AirportCode Airport$
        goto [ProcessAirport]
end if
#1.AirportCode "!SetFocus"
#1.AirportCode "!SelectAll"

#1.Display "!cls"
#1.AirportCode "!Contents? AirportCode$"
for x=1 to len(AirportCode$)
    y$=mid$(AirportCode$, x, 1)
    if y$=>"A" and y$=<"Z" then z$=z$+y$
next x
if AirportCode$="TEST" then
    if TestMETAR$<>"" then Metar$=TestMETAR$: TestRun=1: goto [TestEntry] else goto [Top]
end if
if len(AirportCode$)=3 then AirportCode$="K"+AirportCode$
if len(AirportCode$)<3 then goto [Top]
CD$=left$(AirportCode$, 1) 'Weather Station Area Designator
if CD$<>"K" and CD$<>"C" and CD$<>"P" and CD$<>"T" then goto [Top]
#1.AirportCode AirportCode$

ReturnCode=DownloadToFile(URL$, FileName$)
if  ReturnCode<>0 then #1.Display "No METAR for Airport Code "; AirportCode$: goto [Bottom]
open FileName$ for input as #f
line input #f METAR$
close #f
MetarStart=instr(METAR$, AirportCode$)
MetarEnd=instr(METAR$, " RMK ")
Metar$=mid$(METAR$, MetarStart, MetarEnd-MetarStart)
#1.Display date$("mmmm d, yyyy"); " at "; left$(time$("hh:mm"), 5)

Year as short, Month as short,_
DayOfWeek as short, Day as short,_
Hour as short, Minute as short, Second as short,_
Milliseconds as short

CallDLL #kernel32, "GetSystemTime",_
SYSTEMTIME as struct,_
ret as void
UTC$=AddLeadingZeros$(UTC.hour, 2) + AddLeadingZeros$(UTC.min, 2)

MetarDate$=mid$(Metar$, 6, 2)
MetarTime$=mid$(Metar$, 8, 4)
#1.Display Metar$
#1.Display ""
#1.Display "Weather Information for "; AirportCode$; ", "; MetarDate$; " at "; MetarTime$; " zulu ";

MetarWord$=word$(Metar$, MetarWordNumber)
if MetarWord$="AUTO" then
    #1.Display "(automated reporting)"
    MetarWord$=word$(Metar$, MetarWordNumber)
    if MetarWord$="COR" then
        #1.Display "(corrected)"
        MetarWord$=word$(Metar$, MetarWordNumber)
        #1.Display ""
    end if
end if
if not(TestRun) then
    if MetarDate$<>TodaysDate$ and MetarDate$<>TomorrowsDate$ then
        #1.Display "*** WARNING - METAR not current ***"
    end if
    TD$=TimeDifference$(UTC$, MetarTime$)
    if val(TD$)<2 then TD$="2"
    #1.Display "     ["; TD$; " minutes ago]"
    #1.Display "*** TEST DATA ONLY ***"
end if

WW1$=MetarWord$ 'Metar Wind Word #1
WindSpeed$=mid$(WW1$, 4, 2)
WindDirection$=left$(WW1$, 3): WindDir=val(WindDirection$)
if WindSpeed$="00" then #1.Display "Wind calm": goto [Visibility]
WW2$=word$(Metar$, MetarWordNumber+1)
if mid$(WW2$, 4, 1)="V" then 'variable wind direction
    FromDir=val(left$(WW2$, 3)): ToDir=val(right$(WW2$, 3))
    #1.Display "Wind variable from "; FromDir; " to "; ToDir; " degrees ";
    if FromDir=360 then FromDir=000
    if FromDir>ToDir then ToDir+=360
    if WindDir<FromDir then WindDir+=360
    if WindDir>FromDir and WindDir<ToDir then
        #1.Display "(median "; WindDirection$; ") ";
    end if
    x=instr(Metar$, WW2$)
    Metar$="T "+right$(Metar$, len(Metar$)-x-len(WW2$))
    goto [WindSpeed]
end if
if WindDirection$="VRB" then
    #1.Display "Wind variable ";
    #1.Display "Wind from "; WindDirection$; " degrees (true) ";
end if

#1.Display "at "; WindSpeed$; " knots";
if Gusting then
    Gusting$=mid$(WW1$,Gusting+1, 2)
    #1.Display ", gusting to "; Gusting$;
end if
#1.Display ""

MetarVisibilityPosEnd=instr(Metar$, "SM ")-1
Visibility$="": x$=""
do until x$="T"
    x$=mid$(Metar$, MetarVisibilityPos, 1)
Visibility$=right$(Visibility$, len(Visibility$)-2)
if left$(Visibility$,1)="M" then Visibility$="Less than " + right$(Visibility$, len(Visibility$)-1)
#1.Display Visibility$; " mile visibility (statute miles)"

MetarSkyPos=instr(Metar$, "SM ")+3
SkyCondition$=right$(Metar$, len(Metar$)-MetarSkyPos+1)
for x=1 to 10
    if x=1 and left$(y$,1)="R" and instr(y$,"/")>0 and right$(y$,2)="FT" then
        Runway$=mid$(y$, 2, instr(y$,"/")-2)
        #1.Display "*** WARNING - Reduced visibility on runway "; Runway$; " ***   ["; y$; "]"
        goto [BumpFOR]
    end if
    CC$=left$(y$,2) 'Cloud Condition Code
    if CC$="CL" or CC$="SK" or CC$="FE" or CC$="SC" or CC$="BK" or CC$="OV" or CC$="VV" then
        FirstCC=x: exit for    
    end if
    select case y$
        case   "-DZ": #1.Display "light drizzle"
        case    "DZ": #1.Display "drizzle"
        case   "+DZ": #1.Display "heavy drizzle"
        case   "-RA": #1.Display "light rain"
        case    "RA": #1.Display "rain"
        case   "+RA": #1.Display "heavy rain"
        case "-SHRA": #1.Display "light rainshowers"
        case  "SHRA": #1.Display "rainshowers"
        case "+SHRA": #1.Display "heavy rainshowers"
        case "-FZRA": #1.Display "light freezing rain"
        case  "FZRA": #1.Display "freezing rain"
        case "+FZRA": #1.Display "heavy freezing rain"
        case   "-SN": #1.Display "light snow"
        case    "SN": #1.Display "snow"
        case   "+SN": #1.Display "heavy snow"
        case  "DRSN": #1.Display "drifting snow"
        case    "GR": #1.Display "hail"
        case    "GS": #1.Display "sleet"
        case    "UP": #1.Display "precipitation"
        case "-FZFG": #1.Display "light freezing fog"
        case  "FZFG": #1.Display "freezing fog"
        case "+FZFG": #1.Display "heavy freezing fog"
        case    "FG": #1.Display "fog"
        case  "BCFG": #1.Display "patches of fog"
        case    "BR": #1.Display "mist"
        case    "FU": #1.Display "smoke"
        case    "HZ": #1.Display "haze"
        case    "SQ": #1.Display "squalls"
        case    "TS": #1.Display "thunderstorm"
        case    "FC": #1.Display "funnel cloud"
        case    "VA": #1.Display "volcanic ash"
        case else   : #1.Display y$
    end select
next x

dim SkyCondition$(10): x=1: y=FirstCC
    SkyCondition$(x)=word$(SkyCondition$, y)
    if instr(word$(SkyCondition$, y), "/")=0 then
        x+=1: y+=1: goto [Loop1]
    end if
TemperatureDewpoint$=SkyCondition$(x) 'save for later

MinBroken=99999: MinOvercast=99999
#1.Display "Cloud Conditions: "; 
for y=1 to x-1
'#1.Debug SkyCondition$(y);wait
    Clouds$=left$(SkyCondition$(y), 2)
    Altitude$=trim$(using("##,### feet", Altitude))
    select case Clouds$
        case "CL": #1.Display "clear";
        case "SK": #1.Display "clear";
        case "FE": #1.Display "a few at "; Altitude$;
        case "SC": #1.Display "scattered at "; Altitude$;
        case "BK": #1.Display "broken at "; Altitude$;
            MinBroken=min(Altitude, MinBroken)
        case "OV": #1.Display "overcast at "; Altitude$;
            MinOvercast=min(Altitude, MinOvercast)
        case "VV" : #1.Display "vertical visibility "; Altitude$;
            MinOvercast=min(Altitude, MinOvercast)
    end select
    if y=1 and Altitude<10000 and Altitude<>0 then #1.Display " (agl)";
    if y<x-1 then #1.Display ", ";
next y
#1.Display ""

Ceiling=min(MinBroken, MinOvercast)
if Ceiling<MaxReportedCeiling then #1.Display "     [Ceiling is "; trim$(using("##,### feet", Ceiling)); "]"

[Temperature] 'TemperatureDewpoint$=SkyCondition$(x)    
Dewpoint$=mid$(TemperatureDewpoint$, instr(TemperatureDewpoint$, "/")+1)
Temperature$=left$(TemperatureDewpoint$, len(TemperatureDewpoint$)-len(Dewpoint$)-1)
if right$(Dewpoint$,2)="00" then Dewpoint$="zero"
if left$(Dewpoint$,1)="M" then left$(Dewpoint$,1)="-"
if right$(Temperature$,2)="00" then Temperature$="zero"
if left$(Temperature$,1)="M" then left$(Temperature$,1)="-"
#1.Display "Temperature "; Temperature$; " (celsius), dewpoint "; Dewpoint$
#1.Display "     ["; trim$(using("+###", (val(Temperature$)*9/5+32))); " farenheit]"

Pressure$=right$(Metar$, 5)
#1.Display "Altimeter "; right$(Pressure$, 4);
if left$(Pressure$, 1)="A" then #1.Display  " (in. hg)"
if left$(Pressure$, 1)="Q" then #1.Display  " (mm. hg)"

#1.Display "!Origin 0 0"
#1.AirportCode "!SetFocus"
#1.AirportCode "!SelectAll"

sub Quit
    close #1
end sub
function DownloadToFile(urlfile$, localfile$)
    open "URLmon" for dll as #url
        calldll #url, "URLDownloadToFileA",_
        0 as long,_         'null
        urlfile$ as ptr,_   'url to download
        localfile$ as ptr,_ 'save file name
        0 as long,_         'reserved, must be 0
        0 as long,_         'callback address, can be 0
        DownloadToFile as ulong  '0=success
    close #url
end function

function TimeDifference$(Time1$, Time2$)
    Hour1$=left$(Time1$,2): Hour1=val(Hour1$)
    Min1$= right$(Time1$,2): Min1=val(Min1$)
    Hour2$=left$(Time2$,2): Hour2=val(Hour2$)
    Min2$= right$(Time2$,2): Min2=val(Min2$)
    if Hour1<Hour2 then Hour1+=24
    if Min1<Min2 then Hour1-=1: Min1+=60

    HourDiff=Hour1-Hour2: MinDiff=Min1-Min2

end function

function AddLeadingZeros$(Number, Length)
    for x=1 to ZerosNeeded
    next x
end function
Posts: 2
Joined: Sat Jun 08, 2024 3:42 pm

Re: Weather METARs

Post by JackKellyUSA »

What do you think is happening here? This thread has been viewed nearly 10,000 times this year. How is that possible in a forum with only 92 members? Are there thousands of LBB users out there that we don't know about? Perhaps aviation enthusiasts Google "METARs" and investigate a hit on this thread? Is that possible? If so, I hope some of them download the compiler and run the program... LOL.
Posts: 2
Joined: Sat Jun 08, 2024 3:42 pm

Re: Weather METARs

Post by JackKellyUSA »

That is EXACTLY what is happening here. Aviation weather enthusiasts, use this link to download the compiler and use it to view the METAR program.

Email me if you have any questions, problems, or comments...
Posts: 12
Joined: Tue Nov 28, 2023 1:36 pm

Re: Weather METARs

Post by xxgeek »

Hi Jack,
Nice work.
Will come in handy for travelers I'm sure.

Hope you don't mind, I've added a Listbox with Canadian, American, and International Airports to choose from.
You can still enter a code into the textbox and hit {Enter] if you know a code......... or select an airport from the List.

Also added some extra text to the display to show the name for the chosen airport, or entered code.

There are more possible airports around the world, I have only added International, Canadian (Regional), and American (Regional)
As you will see, some airports do not have METAR info, just the more major ones.
Link -
2 files zipped
1 x .bas file
1 x .txt file