Local metar server
Outline
This is a local server which handles calls to a weather server and communicates with flightgear through named pipes. This method overcomes the METAR not available problem. The nasal code reloads the local weather from the airport which is currently nearest during the flight.
Server Code written in Perl
This is an executable program which runs alongside flightgear. When a request is received on the in pipe the metar server is contacted and the requested data is then written to the out pipe.
#!/usr/bin/perl -w
use HTTP::Tiny;
my $infile = "/root/.fgfs/cache/metarpipein.txt";
my $outfile = "/root/.fgfs/cache/metarpipeout.txt";
my $types = "/root/.fgfs/cache/types.txt";
unlink $outfile;
unlink $infile;
`mkfifo $outfile`;
`mkfifo $infile`;
print "real METAR server initialised\n";
open(OUTFILE, ">", $outfile) or die "Could not open $outfile\n";
open(INFILE, "<", $infile) or die "Could not read $infile\n";
open(TYPES, ">", $types) or die "Could not open $types\n";
$| = 1;
my %planefixes;
my %planesLast;
my @interp;
my @prevInterp;
my $count = 0;
my $metar ="";
while(!eof(INFILE)){
$count = $count + 1;
my $row = INFILE->getline();
#print $row;
chomp $row;
@words = split(/ /, $row);
print "list $words[2]\n";
if ($words[3] =~ ".TXT"){
my $response = HTTP::Tiny->new(timeout => 2)->get('https://tgftp.nws.noaa.gov/data/observations/metar/stations/'.$words[3]);
if ($response->{status} == 200){
$metar = $response->{content};
$metar = (split(/\n/,$metar))[1];
print OUTFILE "end ".$metar. "\n";
OUTFILE->flush;
print TYPES "end ".$metar. "\n";
TYPES->flush;
}
}
}
Flightgear Code in Nasal Folder
This nasal routine first checks that the local server is active by examining the out pipe date. If the pipe was accessed within the last 60 seconds it assumes the server is active and starts the communications cycle. A screen message requests that the local server should be started .
The METAR is only requested on change of airport. This uses the local weather routines. I've stolen some of the code from the weather.xml dialog.
var path = "/root/.fgfs/cache/metarpipeout.txt"; # output from data server
var path2 = "/root/.fgfs/cache/testpipetest.txt"; # output from data server
var pathin = "/root/.fgfs/cache/metarpipein.txt"; # path input to data server
var pathin2 = "/root/.fgfs/cache/pipeintest.txt"; # path input to data server
var pathtimetest = "/root/.fgfs/cache/timetest.txt";
var rtpipe = nil;
var rtpipein = nil;
var metarinf="";
var airportname ="XXXX";
var lastairportname ="";
var icaoparam="NO";
setprop("/sim/presets/altitude-ft",getprop("/position/altitude-ft"));
setprop("/sim/presets/onground",1);
#setprop("/sim/presets/trim",1);
var metarserver = func(){
#
# open the pipes
#
if (call(io.readfile, [path2], nil, nil, var err=[]) != nil){
print("test path exists");
path = path2;
pathin = pathin2;
}
if(rtpipe == nil){
var file = io.open(pathtimetest, "w"); # open in write mode
var stat = io.stat(pathtimetest);
var testtime = stat[9];
print(testtime);
io.close(file);
var stat = io.stat(path);
if(stat != nil){
var pipetime = stat[9];
if ((testtime - pipetime) < 60){
printf("File time: %s ", pipetime); # prints file time
printf("opening rtpipe");
rtpipe = io.open(path,"r"); rtpipein = io.open(pathin,"w");
# start the cycle
rttimer.start();
}
else{
setprop("/sim/messages/ground","please start METAR server");
}
}
}
}
var metardata = func(){
var info = airportinfo(getprop("position/latitude-deg"),getprop("position/longitude-deg"));
if (info.id != airportname){
airportname = info.id;
icaoparam = airportname~".TXT";
print("reading tinymetar");
io.write(rtpipein,"read "~"dummy activeList "~icaoparam~"\n");
io.flush(rtpipein);
line = io.readln(rtpipe);
print(line);
setprop( "/environment/params/metar-updates-environment", 0 );
setprop( "/environment/realwx/enabled", 0 );
setprop( "/environment/config/enabled", 1 );
if(substr(line,0,3) == "end"){
updateOK = 1; #1
print("END");
var metarinfs = (split("end ",line));
metarinf = metarinfs[1];
metarinf = string.replace(metarinf,"/"," ");
print(metarinf);
setprop("/nasal/local_weather/enabled", "false");
if (getprop("/nasal/local_weather/loaded")) local_weather.clear_all();
setprop("/environment/metar[0]/data",metarinf);
setprop("/local-weather/tmp/tile-type", "manual");
setprop("/local-weather/tmp/tile-management", "METAR");
setprop("/nasal/local_weather/enabled", "true");
settimer( func {local_weather.set_tile();}, 0.2);
}
}
}
rttimer = maketimer(10,metardata);
var checktimer = maketimer(10,metarserver);
checktimer.start();
print("metar Monitor has loaded");