#!/usr/bin/perl -w # NAME: geo_metar02.pl # AIM: Get the METAR for a particular ICAO # 18/11/2014 - Revisit - Had to install Geo::METAR - Added use batch : metar ICAO # CPAN install: Open MSVC x64 prompt; perl -MCPAN -e shell;, then install Geo::METAR # 22/07/2011 - First cut use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use Cwd; use Socket; use LWP::Simple; use Geo::METAR; use Date::Parse; use Data::Dumper; my $perl_dir = 'C:\GTools\perl'; unshift(@INC, $perl_dir); require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl ...\n"; # log file stuff our ($LF); my $pgmname = $0; if ($pgmname =~ /(\\|\/)/) { my @tmpsp = split(/(\\|\/)/,$pgmname); $pgmname = $tmpsp[-1]; } my $outfile = $perl_dir."\\temp.$pgmname.txt"; open_log($outfile); # user variables my $vers = "0.0.2 2014-11-18"; ###my $vers = "0.0.1 2011-07-22"; my $load_log = 0; my $in_file = ''; my $out_file = ''; my $verbosity = 0; my $fetch_new = 0; # program variables my $TAFBASE = 'http://weather.noaa.gov/pub/data/forecasts/taf/stations/'; my $METARBASE = 'http://weather.noaa.gov/pub/data/observations/metar/stations/'; # 1 hPa = 0.0 295 300 586 467 inHg (0.02953) my $HP2INCHES = 0.0295300586467; # 1 Knot = 1.15077845 Miles Per Hour. my $KNOT2MPH = 1.15077845; # 1 Miles Per Hour = 0.86897699264 Knot. my $MPH2KNOT = 0.86897699264; my $debug_on = 0; my $def_file = 'YSDU'; sub VERB1() { return $verbosity >= 1; } sub VERB2() { return $verbosity >= 2; } sub VERB5() { return $verbosity >= 5; } sub VERB9() { return $verbosity >= 9; } my @geo_metar = qw( pressure visibility slp DATE HOURLY_TEMP_C date_time modifier VISIBILITY DEW_F windvar TEMP_F debug HOURLY_DEW_C SITE SKY WIND_VAR_1 WIND_DIR_ENG WIND_GUST_KTS REMARKS RUNWAY HOURLY_PRECIP runway type WIND_VAR_2 WIND_VAR WIND_DIR_ABB HOURLY_DEW_F WIND_MPH wind WIND_KTS unknown weather windtype remarks WEATHER_LOG TEMP_C WIND_GUST_MPH DEW_C WIND_DIR_DEG sky HOURLY_TEMP_F SLP alt TIME tokens MOD TYPE WEATHER METAR site temp_dew VERSION UNKNOWN ALT ); my %geo_arrays = ( 'SKY' => 1, 'RUNWAY' => 1, 'unknown' => 1, 'weather' => 1, 'remarks' => 1, 'WEATHER_LOG' => 1, 'sky' => 1, 'tokens' => 1, 'WEATHER' => 1, 'UNKNOWN' => 1 ); ### program variables my @warnings = (); my $cwd = cwd(); my $os = $^O; my @ICAO_LIST = (); sub show_warnings($) { my ($val) = @_; if (@warnings) { prt( "\nGot ".scalar @warnings." WARNINGS...\n" ); foreach my $itm (@warnings) { prt("$itm\n"); } prt("\n"); } else { ###prt( "\nNo warnings issued.\n\n" ); } } sub pgm_exit($$) { my ($val,$msg) = @_; if (length($msg)) { $msg .= "\n" if (!($msg =~ /\n$/)); prt($msg); } show_warnings($val); close_log($outfile,$load_log); exit($val); } sub prtw($) { my ($tx) = shift; $tx =~ s/\n$//; prt("$tx\n"); push(@warnings,$tx); } # 9.C = 5.F - 160 sub celcius_to_fahrenheight($) { my ($dc) = shift; my $df = (($dc * 9) + 160) / 5; return $df; } sub fahrenheight_to_celcius($) { my ($df) = @_; my $dc = (($df - 32) * 100) / 180; return $dc; } sub trim_metar_txt($) { my $met = shift; $met =~ s/\n/ /gm; $met =~ s/\r/ /gm; $met =~ s/\t/ /gm; $met = trim_all($met); return $met; } sub fetch_url { # see gettaf01.pl my ($url) = shift; prt( "Fetching: $url\n" ); my $txt = get($url); my $met = ''; if ($txt && length($txt)) { $met = trim_all($txt); if (length($met)) { prt( "$met\n" ); } else { prt( "FAILED to get URL $url ...\n" ); } } else { prt( "FAILED to get URL $url ...\n" ); } return $met; } sub process_in_list() { my ($inf,$url,$met,$file,@arr,$key,$val); my ($min,$len,$cnt,$lckey,$uckey); my ($line,$msg,$tmp); my $m = new Geo::METAR; my %dupes = (); my %list = (); foreach $inf (@ICAO_LIST) { $file = $perl_dir."\\temp.$inf.TXT"; $url = $METARBASE.$inf.".TXT"; $met = ''; if (-f $file && !$fetch_new ) { if (open FIL, "<$file") { @arr = ; close FIL; $met = join(" ",@arr); $met = trim_all($met); if (length($met)) { prt("Loaded metar from [$file]\n"); } } } else { $met = fetch_url($url); if (length($met)) { $met = trim_metar_txt($met); if (length($met)) { write2file($met,$file); prt("Metar written to [$file]\n"); } } } if (length($met)) { prt( "METAR: [$met]\n" ) if (VERB1()); $m->metar($met); #prt( $m->dump ); #prt(Dumper($m)); @arr = sort keys(%{$m}); $line = ''; $msg = 'Keys: '; #prt("Keys: ".join(" ",@arr)."\n"); foreach $key (@arr) { $line .= ' ' if (length($line)); $line .= $key; if (length($line) > 80) { $msg .= "$line\n"; $line = ''; } } $msg .= $line if (length($line)); prt("$msg\n") if (VERB5()); $min = 0; $cnt = 0; foreach $key (sort @geo_metar) { next if ($key eq 'VERSION'); $uckey = uc($key); $lckey = lc($key); if (defined ${$m}{$key}) { $val = ${$m}{$key}; if (defined $geo_arrays{$key}) { # we have an array ref } else { $val = trim_all($val); if (length($val)) { if (!defined $dupes{$uckey} && !defined $dupes{$lckey}) { $len = length($key); $min = $len if ($len > $min); $dupes{$uckey} = 1; $dupes{$lckey} = 1; $list{$key} = $val; $cnt++; } } } } } prt("\nGot $cnt different items...\n"); $msg = ''; my ($epoch); foreach $key (sort keys %list) { $val = ${$m}{$key}; if ($key eq "METAR") { @arr = split(/\s+/,$val); $tmp = $arr[0].' '.$arr[1]; $epoch = str2time($tmp); } $key .= ' ' while (length($key) < $min); if ($key =~ /^pressure/) { $tmp = $val * $HP2INCHES; $tmp = int(($tmp * 100) + 0.5) / 100; $msg .= "$key = $val hPa $tmp inHg\n"; } elsif ($key =~ /^TEMP_C\s*/) { $tmp = celcius_to_fahrenheight($val); $msg .= "$key = $val C $tmp F\n"; } elsif ($key =~ /^TEMP_F\s*/) { $tmp = fahrenheight_to_celcius($val); $msg .= "$key = $val F $tmp C\n"; } elsif ($key =~ /^WIND_KTS\b/) { $tmp = $val * $KNOT2MPH; $tmp = int(($tmp * 10) + 0.5) / 10; $msg .= "$key = $val kt $tmp mph\n"; } elsif ($key =~ /^WIND_MPH\b/) { $tmp = $val * $MPH2KNOT; $tmp = int(($tmp * 10) + 0.5) / 10; $msg .= "$key = $val mph $tmp kt\n"; } else { $msg .= "$key = $val\n"; } } if (length($out_file)) { write2file($msg,$out_file); prt("Results written to $out_file\n"); } else { prt($msg); prt("Results written to stdout since no -o out_file given\n"); } if ($epoch) { my $tm = time(); my $diff = $tm - $epoch; prt("Age: "); prt("Metar epoch $epoch, now $tm, diff $diff ") if (VERB5()); prt(" Appears ".secs_HHMMSS($diff)." old\n"); } } } } ######################################### ### MAIN ### ##prt(str2time("02/25/2011 11:50AM")."\n"); ##pgm_exit(1,"TEMP EXIT"); parse_args(@ARGV); process_in_list(); pgm_exit(0,""); ######################################## sub give_help { prt("$pgmname: version $vers\n"); prt("Usage: $pgmname [options] ICAO [ICAO2 [ICAO3]]\n"); prt("Options:\n"); prt(" --help (-h or -?) = This help, and exit 0.\n"); prt(" --verb[n] (-v) = Bump [or set] verbosity. def=$verbosity\n"); prt(" --load (-l) = Load LOG at end. ($outfile)\n"); prt(" --out (-o) = Write output to this file.\n"); prt(" --new (-n) = Fetch 'new' metar even if an existing file.\n"); prt(" If no existing metar file, or -n specified, will fetch the metar\n"); prt(" from : $METARBASE\n"); prt(" THe metar string is decoded using Get::METAR, and the items found displayed,\n"); prt(" or written to a file is and -o file given.\n"); } sub need_arg { my ($arg,@av) = @_; pgm_exit(1,"ERROR: [$arg] must have following argument!\n") if (!@av); } sub parse_args { my (@av) = @_; my ($arg,$sarg,$verb); $verb = VERB2(); while (@av) { $arg = $av[0]; if ($arg =~ /^-/) { $sarg = substr($arg,1); $sarg = substr($sarg,1) while ($sarg =~ /^-/); if (($sarg =~ /^h/i)||($sarg eq '?')) { give_help(); pgm_exit(0,"Help exit(0)"); } elsif ($sarg =~ /^v/) { if ($sarg =~ /^v.*(\d+)$/) { $verbosity = $1; } else { while ($sarg =~ /^v/) { $verbosity++; $sarg = substr($sarg,1); } } $verb = VERB2(); prt("Verbosity = $verbosity\n") if ($verb); } elsif ($sarg =~ /^l/) { if ($sarg =~ /^ll/) { $load_log = 2; } else { $load_log = 1; } prt("Set to load log at end. ($load_log)\n") if ($verb); } elsif ($sarg =~ /^n/) { $fetch_new = 1; prt("Set to fetch new METAR...\n") if ($verb); } elsif ($sarg =~ /^o/) { need_arg(@av); shift @av; $sarg = $av[0]; $out_file = $sarg; prt("Set out file to [$out_file].\n") if ($verb); } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n"); } } else { $in_file = uc($arg); push(@ICAO_LIST,$in_file); prt("Set input to [$in_file]\n") if ($verb); } shift @av; } if ($debug_on) { prtw("WARNING: DEBUG is ON!\n"); if (length($in_file) == 0) { $in_file = uc($def_file); push(@ICAO_LIST,$in_file); prt("Set DEFAULT input to [$in_file]\n"); } } if (length($in_file) == 0) { pgm_exit(1,"ERROR: No ICAO found in command!\n"); } } # eof - geo_metar.pl