mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-07 16:59:18 +00:00
contrib/55_GDS.2015: updated
added forecast retrieval (by jensb) added weblink generator (by jensb) git-svn-id: https://svn.fhem.de/fhem/trunk@9408 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
0b97c25be0
commit
b14ef567c7
@ -6,9 +6,10 @@
|
||||
# An FHEM Perl module to retrieve data from "Deutscher Wetterdienst"
|
||||
#
|
||||
# Copyright: betateilchen ®
|
||||
# some patches provided by jensb@FHEM_Forum
|
||||
# - forecasts as readings or text
|
||||
# - weather weblinks
|
||||
#
|
||||
# some patches provided by jensb
|
||||
# forecasts provided by jensb
|
||||
# weblinks provided by jensb
|
||||
#
|
||||
# This file is part of fhem.
|
||||
#
|
||||
@ -44,7 +45,7 @@ my ($bulaList, $cmapList, %rmapList, $fmapList, %bula2bulaShort, %bulaShort2dwd,
|
||||
|
||||
####################################################################################################
|
||||
#
|
||||
# Main routines
|
||||
# Main routines
|
||||
#
|
||||
####################################################################################################
|
||||
|
||||
@ -145,9 +146,9 @@ sub GDS_Set($@) {
|
||||
given($command) {
|
||||
when("clear"){
|
||||
CommandDeleteReading(undef, "$name a_.*");
|
||||
CommandDeleteReading(undef, "$name c_.*") if(defined($parameter) && $parameter eq "all");
|
||||
CommandDeleteReading(undef, "$name f_.*") if(defined($parameter) && $parameter eq "all");
|
||||
CommandDeleteReading(undef, "$name g_.*") if(defined($parameter) && $parameter eq "all");
|
||||
CommandDeleteReading(undef, "$name c_.*") if(defined($parameter) && $parameter eq "all");
|
||||
CommandDeleteReading(undef, "$name fc.?_.*") if(defined($parameter) && $parameter eq "all");
|
||||
CommandDeleteReading(undef, "$name g_.*") if(defined($parameter) && $parameter eq "all");
|
||||
}
|
||||
|
||||
when("help"){
|
||||
@ -164,9 +165,9 @@ sub GDS_Set($@) {
|
||||
retrieveFile($hash,"alerts");
|
||||
($aList, undef) = buildCAPList($hash);
|
||||
};
|
||||
# eval {
|
||||
# $fList = getListForecastStationsDropdown($hash);
|
||||
# };
|
||||
eval {
|
||||
$fList = getListForecastStationsDropdown($hash);
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
@ -187,11 +188,14 @@ sub GDS_Set($@) {
|
||||
break;
|
||||
}
|
||||
|
||||
# when("forecasts"){
|
||||
# retrieveForecasts($hash, "f", @a);
|
||||
# $attr{$name}{gdsSetForecast} = ReadingsVal($name,'f_stationName',undef);
|
||||
# break;
|
||||
# }
|
||||
when("forecasts"){
|
||||
retrieveForecasts($hash, "fc", @a);
|
||||
my $station = ReadingsVal($name, 'fc_stationName', undef);
|
||||
if (defined($station)) {
|
||||
$attr{$name}{gdsSetForecast} = $station;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default { return $usage; };
|
||||
}
|
||||
@ -291,6 +295,9 @@ sub GDS_Get($@) {
|
||||
} else {
|
||||
$result = "Keine Warnmeldung für die gesuchte Region vorhanden.";
|
||||
}
|
||||
my $_gdsAll = AttrVal($name,"gdsAll", 0);
|
||||
my $_gdsDebug = AttrVal($name,"gdsDebug", 0);
|
||||
readingsSingleUpdate($hash,'_lastAlertCheck','see timestamp ->',1) if($_gdsAll || $_gdsDebug);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -312,9 +319,9 @@ sub GDS_Get($@) {
|
||||
retrieveFile($hash,"conditions");
|
||||
};
|
||||
initDropdownLists($hash);
|
||||
# eval {
|
||||
# $fList = getListForecastStationsDropdown($hash);
|
||||
# };
|
||||
eval {
|
||||
$fList = getListForecastStationsDropdown($hash);
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
@ -402,21 +409,53 @@ sub GDS_GetUpdate($) {
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my (@a, $next);
|
||||
|
||||
my $interval = $hash->{helper}{INTERVAL};
|
||||
my $forcastsStationName = ReadingsVal($name, "fc_stationName", undef);
|
||||
|
||||
if(IsDisabled($name)) {
|
||||
readingsSingleUpdate($hash, 'state', 'disabled', 0);
|
||||
Log3 ($name, 2, "GDS $name is disabled, data update cancelled.");
|
||||
} else {
|
||||
readingsSingleUpdate($hash, 'state', 'active', 0);
|
||||
push @a, undef;
|
||||
push @a, undef;
|
||||
push @a, ReadingsVal($name, "c_stationName", "");
|
||||
retrieveConditions($hash, "c", @a);
|
||||
}
|
||||
if(IsDisabled($name)) {
|
||||
readingsSingleUpdate($hash, 'state', 'disabled', 0);
|
||||
Log3 ($name, 2, "GDS $name is disabled, data update cancelled.");
|
||||
} else {
|
||||
readingsSingleUpdate($hash, 'state', 'active', 0);
|
||||
|
||||
$next = gettimeofday()+$hash->{helper}{INTERVAL};
|
||||
readingsSingleUpdate($hash, "c_nextUpdate", localtime($next), 1);
|
||||
InternalTimer($next, "GDS_GetUpdate", $hash, 1);
|
||||
# schedule only one ftp fetch per update call to avoid blocking FHEM for extended periods
|
||||
if (!defined($hash->{helper}{UPDATE_CYCLE}) || !defined($forcastsStationName)) {
|
||||
$hash->{helper}{UPDATE_CYCLE} = 0;
|
||||
} else {
|
||||
$hash->{helper}{UPDATE_CYCLE} = ++$hash->{helper}{UPDATE_CYCLE}%11;
|
||||
}
|
||||
|
||||
# perform one ftp fetch
|
||||
if ($hash->{helper}{UPDATE_CYCLE} == 0) {
|
||||
push @a, undef;
|
||||
push @a, undef;
|
||||
push @a, ReadingsVal($name, "c_stationName", "");
|
||||
retrieveConditions($hash, "c", @a);
|
||||
} else {
|
||||
push @a, undef;
|
||||
push @a, undef;
|
||||
push @a, $forcastsStationName;
|
||||
push @a, $hash->{helper}{UPDATE_CYCLE};
|
||||
retrieveForecasts($hash, "fc", @a);
|
||||
}
|
||||
|
||||
# vary interval for staggered fetching and waiting
|
||||
if (defined($forcastsStationName)) {
|
||||
if ($hash->{helper}{UPDATE_CYCLE} < 10) {
|
||||
$interval = 1; # use short interval to get next forecast
|
||||
} else {
|
||||
$interval -= 16; # cut back approximate staggered retrieval time from interval
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# schedule next update
|
||||
$next = gettimeofday() + $interval;
|
||||
if ($interval > 1) {
|
||||
readingsSingleUpdate($hash, "c_nextUpdate", localtime($next), 1);
|
||||
}
|
||||
InternalTimer($next, "GDS_GetUpdate", $hash, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -561,7 +600,7 @@ sub getListStationsText($){
|
||||
sub getListCapStations($$){
|
||||
my ($hash, $command) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my (%capHash, $file, $csv, @columns, $err, $key, $cList);
|
||||
my (%capHash, $file, $csv, @columns, $err, $key, $cList, $found);
|
||||
|
||||
$file = $tempDir.'capstations.csv';
|
||||
$csv = Text::CSV->new( { binary => 1 } );
|
||||
@ -570,27 +609,37 @@ sub getListCapStations($$){
|
||||
# prüfen, ob CSV schon vorhanden,
|
||||
# falls nicht: vom Server holen
|
||||
if (!-e $tempDir."caplist.csv"){
|
||||
retrieveFile($hash, $command);
|
||||
}
|
||||
|
||||
# CSV öffnen und parsen
|
||||
open (CSV, "<", $file) or die $!;
|
||||
while (<CSV>) {
|
||||
next if ($. == 1);
|
||||
if ($csv->parse($_)) {
|
||||
@columns = $csv->fields();
|
||||
$capHash{latin1ToUtf8($columns[4])} = $columns[0];
|
||||
} else {
|
||||
$err = $csv->error_input;
|
||||
print "Failed to parse line: $err";
|
||||
(undef, $found) = retrieveFile($hash, $command);
|
||||
if(!$found){
|
||||
$cList = "Error: Unable to retrieve capstation list!";
|
||||
Log3($name, 2, "GDS $name: $cList");
|
||||
}
|
||||
}
|
||||
close CSV;
|
||||
|
||||
# Ausgabe sortieren und zusammenstellen
|
||||
foreach $key (sort keys %capHash) {
|
||||
$cList .= $capHash{$key}."\t".$key."\n";
|
||||
if (!defined($cList)) {
|
||||
# CSV öffnen und parsen
|
||||
if (open (CSV, "<", $file)) {
|
||||
while (<CSV>) {
|
||||
next if ($. == 1);
|
||||
if ($csv->parse($_)) {
|
||||
@columns = $csv->fields();
|
||||
$capHash{latin1ToUtf8($columns[4])} = $columns[0];
|
||||
} else {
|
||||
$err = $csv->error_input;
|
||||
print "Failed to parse line: $err";
|
||||
}
|
||||
}
|
||||
close CSV;
|
||||
} else {
|
||||
Log3($name, 4, "GDS $name: Error: unable to open capstations file: $!!");
|
||||
}
|
||||
|
||||
# Ausgabe sortieren und zusammenstellen
|
||||
foreach $key (sort keys %capHash) {
|
||||
$cList .= $capHash{$key}."\t".$key."\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $cList;
|
||||
}
|
||||
|
||||
@ -612,7 +661,7 @@ sub buildCAPList($){
|
||||
%capCityHash = ();
|
||||
%capCellHash = ();
|
||||
$alertsXml = undef;
|
||||
$aList = "please_use_rereadcfg_first";
|
||||
$aList = "please_use_rereadcfg_first";
|
||||
|
||||
my $xml = new XML::Simple;
|
||||
my $area = 0;
|
||||
@ -622,11 +671,7 @@ sub buildCAPList($){
|
||||
my $destinationDirectory = $tempDir.$name."_alerts.dir";
|
||||
|
||||
# make XML array and analyze data
|
||||
my ($err,$cF,$countInfo) = mergeCapFile($hash);
|
||||
if (defined($err) && $err) {
|
||||
Log3($name,1,"GDS: merge error: $err - aborting...");
|
||||
return(undef,undef);
|
||||
}
|
||||
my ($countInfo,$cF) = mergeCapFile($hash);
|
||||
eval {
|
||||
$alertsXml = $xml->XMLin($cF, KeyAttr => {}, ForceArray => [ 'info', 'eventCode', 'area', 'geocode' ]);
|
||||
};
|
||||
@ -1092,24 +1137,6 @@ sub _rgbd2h($) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
sub createIndexFile($){
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
if($name){
|
||||
my $text = "<html><head></head><body>".
|
||||
"<a href=\"./".$name."/".$name."_conditionsmap.jpg\" target=\"blank\">Aktuelle Wetterkarte: Wetterlage</a><br/>".
|
||||
"<a href=\"./".$name."/".$name."_forecastsmap.jpg\" target=\"blank\">Aktuelle Wetterkarte: Vorhersage</a><br/>".
|
||||
"<a href=\"./".$name."/".$name."_warningsmap.jpg\" target=\"blank\">Aktuelle Wetterkarte: Warnungen</a><br/>".
|
||||
"<a href=\"./".$name."/".$name."_radarmap.jpg\" target=\"blank\">Aktuelle Radarkarte</a><br/>".
|
||||
"</body></html>";
|
||||
open (DATEI, ">".$tempDir.$name.".html") or die $!;
|
||||
print DATEI $text;
|
||||
close (DATEI);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub fillMappingTables($){
|
||||
|
||||
$tempDir = "/tmp/";
|
||||
@ -1389,18 +1416,582 @@ sub mergeCapFile($) {
|
||||
}
|
||||
push (@alertsArray,"</alert>");
|
||||
|
||||
# write the big XML file
|
||||
my $cF = $destinationDirectory."/gds_alerts";
|
||||
unlink $cF if -e $cF;
|
||||
my $err = FileWrite({ FileName=>$cF,ForceType=>"file" },@alertsArray);
|
||||
return ($err,$cF,$countInfo);
|
||||
# write the big XML file if needed
|
||||
if(AttrVal($name,"gdsDebug", 0)) {
|
||||
my $cF = $destinationDirectory."/gds_alerts";
|
||||
unlink $cF if -e $cF;
|
||||
FileWrite({ FileName=>$cF,ForceType=>"file" },@alertsArray);
|
||||
}
|
||||
|
||||
my $xmlContent = join('',@alertsArray);
|
||||
return ($countInfo,$xmlContent);
|
||||
}
|
||||
|
||||
####################################################################################################
|
||||
#
|
||||
# forecast retrieval
|
||||
# provided by jensb
|
||||
#
|
||||
####################################################################################################
|
||||
|
||||
sub retrieveForecasts($$@){
|
||||
#
|
||||
# parameter: hash, prefix, region/station, forecast index (0 .. 10)
|
||||
#
|
||||
my ($hash, $prefix, @a) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $user = $hash->{helper}{USER};
|
||||
my $pass = $hash->{helper}{PASS};
|
||||
|
||||
# extract region and station name
|
||||
if (!defined($a[2])) {
|
||||
return;
|
||||
}
|
||||
my $i = index($a[2], '/');
|
||||
if ($i <= 0 ) {
|
||||
return;
|
||||
}
|
||||
my $area = utf8ToLatin1(substr($a[2], 0, $i));
|
||||
my $station = utf8ToLatin1(substr($a[2], $i+1));
|
||||
$station =~ s/_/ /g; # replace underscore in station name by space
|
||||
my $searchLen = length($station);
|
||||
|
||||
my ($dataFile, $found, $line, %fread, $k, $v);
|
||||
|
||||
# define fetch scope (all forecasts or single forecast)
|
||||
my $fc = 0;
|
||||
my $fcStep = 1;
|
||||
if (defined($a[3]) && $a[3] > 0) {
|
||||
# single forecast
|
||||
$fc = $a[3] - 1;
|
||||
$fcStep = 10;
|
||||
}
|
||||
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
|
||||
|
||||
%fread = ();
|
||||
|
||||
# fetch up to 10 forecasts for today and the next 3 days
|
||||
do {
|
||||
my $day;
|
||||
my $early;
|
||||
if ($fc < 4) {
|
||||
$day = 0;
|
||||
$early = 0;
|
||||
} else {
|
||||
$day = int(($fc - 2)/2);
|
||||
$early = $fc%2 == 0;
|
||||
}
|
||||
my $areaAndTime = $area;
|
||||
if ($day == 1) {
|
||||
$areaAndTime .= "_morgen";
|
||||
} elsif ($day == 2) {
|
||||
$areaAndTime .= "_uebermorgen";
|
||||
} elsif ($day == 3) {
|
||||
$areaAndTime .= "_Tag4";
|
||||
}
|
||||
my $timeLabel = undef;
|
||||
my $tempLabel = '_tAvgAir';
|
||||
my $copyDay = undef;
|
||||
my $copyTimeLabel = undef;
|
||||
if ($day == 0) {
|
||||
if ($fc == 0) {
|
||||
$areaAndTime .= "_frueh"; # .. 6 h
|
||||
$timeLabel = '06';
|
||||
$tempLabel ='_tMinAir';
|
||||
$copyDay = 1;
|
||||
$copyTimeLabel = '12';
|
||||
} elsif ($fc == 1) {
|
||||
$areaAndTime .= "_mittag"; # .. 12 h
|
||||
$timeLabel = '12';
|
||||
$tempLabel .= $timeLabel;
|
||||
} elsif ($fc == 2) {
|
||||
$areaAndTime .= "_spaet"; # .. 18 h
|
||||
$timeLabel = '18';
|
||||
$tempLabel ='_tMaxAir';
|
||||
$copyDay = 1;
|
||||
$copyTimeLabel = '24';
|
||||
} elsif ($fc == 3) {
|
||||
$areaAndTime .= "_nacht"; # .. 24 h
|
||||
$timeLabel = '24';
|
||||
$tempLabel .= $timeLabel;
|
||||
}
|
||||
} else {
|
||||
if ($early) {
|
||||
$areaAndTime .= "_frueh"; # .. 12 h
|
||||
$timeLabel = '12';
|
||||
$tempLabel ='_tMinAir';
|
||||
if ($day < 3) {
|
||||
$copyDay = $day + 1;
|
||||
$copyTimeLabel = '12';
|
||||
}
|
||||
} else {
|
||||
$areaAndTime .= "_spaet"; # .. 24 h
|
||||
$timeLabel .= '24';
|
||||
$tempLabel ='_tMaxAir';
|
||||
if ($day < 3) {
|
||||
$copyDay = $day + 1;
|
||||
$copyTimeLabel = '24';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# define forecast date (based on "now" + day)
|
||||
my $fcEpoch = time() + $day*24*60*60;
|
||||
if ($fc == 3) {
|
||||
# night continues at next day
|
||||
$fcEpoch += 24*60*60;
|
||||
}
|
||||
my ($fcSec,$fcMin,$fcHour,$fcMday,$fcMon,$fcYear,$fcWday,$fcYday,$fcIsdst) = localtime($fcEpoch);
|
||||
my $fcWeekday = $weekdays[$fcWday];
|
||||
my $fcDate = sprintf("%02d.%02d.%04d", $fcMday, 1+$fcMon, 1900+$fcYear);
|
||||
my $fcDateFound = 0;
|
||||
|
||||
# FTP retrieve
|
||||
my $noDataFound = 1;
|
||||
Log3($name, 4, "GDS $name: Retrieving forecasts data for day $day: $areaAndTime");
|
||||
($dataFile, $found) = retrieveFile($hash, "forecasts", $areaAndTime, undef);
|
||||
if (open WXDATA, $tempDir.$name."_forecasts") {
|
||||
while (!eof(WXDATA) && chomp($line = <WXDATA>)) {
|
||||
if (index($line, $fcDate) > 0) {
|
||||
# forecast date found
|
||||
$fcDateFound = 1;
|
||||
}
|
||||
if (index(substr(lc($line),0,$searchLen), substr(lc($station),0,$searchLen)) != -1) {
|
||||
# station found
|
||||
last;
|
||||
}
|
||||
}
|
||||
close WXDATA;
|
||||
|
||||
# parse file
|
||||
if ($fcDateFound && length($line) > 0) {
|
||||
if (index(substr(lc($line),0,$searchLen), substr(lc($station),0,$searchLen)) != -1) {
|
||||
# station found but there is no header line and column width varies:
|
||||
$line =~ s/---/ ---/g; # column distance may drop to zero between station name and invalid temp "---" -> prepend 3 spaces
|
||||
$line =~ s/ /;/g; # now min. column distance is 3 spaces -> convert to semicolon
|
||||
$line =~ s/;+/;/g; # replace multiple consecutive semicolons by one semicolon
|
||||
my @b = split(';', $line); # split columns by semicolon
|
||||
$b[0] =~ s/^\s+|\s+$//g; # trim station name
|
||||
$b[1] =~ s/^\s+|\s+$//g; # trim temperature
|
||||
$b[2] =~ s/^\s+|\s+$//g; # trim weather
|
||||
if (scalar(@b) > 3) {
|
||||
$b[3] =~ s/^\s+|\s+$//g; # trim wind gust
|
||||
} else {
|
||||
$b[3] = ' ';
|
||||
}
|
||||
$fread{$prefix."_stationName"} = $area.'/'.$b[0];
|
||||
$fread{$prefix.$day.$tempLabel} = $b[1];
|
||||
$fread{$prefix.$day."_weather".$timeLabel} = $b[2];
|
||||
$fread{$prefix.$day."_windGust".$timeLabel} = $b[3];
|
||||
if ($fc != 3) {
|
||||
$fread{$prefix.$day."_weekday"} = $fcWeekday;
|
||||
}
|
||||
$noDataFound = 0;
|
||||
} else {
|
||||
# station not found, abort
|
||||
$fread{$prefix."_stationName"} = "unknown: $station in $area";
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($noDataFound) {
|
||||
# forecast period already passed or no data available
|
||||
$fread{$prefix.$day.$tempLabel} = "---";
|
||||
$fread{$prefix.$day."_weather".$timeLabel} = "---";
|
||||
$fread{$prefix.$day."_windGust".$timeLabel} = "---";
|
||||
if ($fc != 3) {
|
||||
$fread{$prefix.$day."_weekday"} = $fcWeekday;
|
||||
}
|
||||
}
|
||||
|
||||
# day change preset by rotation
|
||||
my $ltime = ReadingsTimestamp($name, $prefix.$day."_weather".$timeLabel, undef);
|
||||
my ($lsec,$lmin,$lhour,$lmday,$lmon,$lyear,$lwday,$lyday,$lisdst);
|
||||
if (defined($ltime)) {
|
||||
($lsec,$lmin,$lhour,$lmday,$lmon,$lyear,$lwday,$lyday,$lisdst) = localtime(time_str2num($ltime));
|
||||
}
|
||||
if (!defined($ltime) || $mday != $lmday) {
|
||||
# day has changed, rotate old forecast forward by one day because new forecast is not immediately available
|
||||
my $temp = $fread{$prefix.$day.$tempLabel};
|
||||
if (defined($temp) && substr($temp, 0, 1) eq '-') {
|
||||
if (defined($copyTimeLabel)) {
|
||||
$fread{$prefix.$day.$tempLabel} = utf8ToLatin1(ReadingsVal($name, $prefix.$copyDay.$tempLabel, '---'));
|
||||
} else {
|
||||
# today noon/night and 3rd day is undefined
|
||||
$fread{$prefix.$day.$tempLabel} = ' ';
|
||||
}
|
||||
}
|
||||
my $weather = $fread{$prefix.$day."_weather".$timeLabel};
|
||||
if (defined($weather) && substr($weather, 0, 1) eq '-') {
|
||||
if (defined($copyTimeLabel)) {
|
||||
$fread{$prefix.$day."_weather".$timeLabel} = utf8ToLatin1(ReadingsVal($name, $prefix.$copyDay."_weather".$copyTimeLabel, '---'));
|
||||
} else {
|
||||
# today noon/night and 3rd day is undefined
|
||||
$fread{$prefix.$day."_weather".$timeLabel} = ' ';
|
||||
}
|
||||
}
|
||||
my $windGust = $fread{$prefix.$day."_windGust".$timeLabel};
|
||||
if (defined($windGust) && substr($windGust, 0, 1) eq '-') {
|
||||
if (defined($copyTimeLabel)) {
|
||||
$fread{$prefix.$day."_windGust".$timeLabel} = utf8ToLatin1(ReadingsVal($name, $prefix.$copyDay."_windGust".$copyTimeLabel, '---'));
|
||||
} else {
|
||||
# today noon/night and 3rd day is undefined
|
||||
$fread{$prefix.$day."_windGust".$timeLabel} = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$fc += $fcStep;
|
||||
} while ($fc < 10);
|
||||
|
||||
readingsBeginUpdate($hash);
|
||||
while (($k, $v) = each %fread) {
|
||||
# skip update if no valid data is available
|
||||
if (defined($v) && substr($v, 0, 1) ne '-') {
|
||||
readingsBulkUpdate($hash, $k, latin1ToUtf8($v));
|
||||
}
|
||||
}
|
||||
readingsEndUpdate($hash, 1);
|
||||
}
|
||||
|
||||
sub getListForecastStationsDropdown($) {
|
||||
my ($hash) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
my @a;
|
||||
my @regions = keys(%rmapList);
|
||||
foreach (@regions) {
|
||||
my $areaAndTime = $_.'_morgen_spaet';
|
||||
my ($dataFile, $found) = retrieveFile($hash, "forecasts", $areaAndTime, undef);
|
||||
if (open WXDATA, $tempDir.$name."_forecasts") {
|
||||
my $lineCount = 0;
|
||||
while (chomp(my $line = <WXDATA>)) {
|
||||
# skip header lines
|
||||
$lineCount++;
|
||||
if ($lineCount > 2) {
|
||||
if (length($line) == 0 || substr($line, 0, 3) eq ' ') {
|
||||
# empty line, done
|
||||
last;
|
||||
} else {
|
||||
# line with station name found
|
||||
$line = latin1ToUtf8($line);
|
||||
$line =~ s/---/ ---/g; # column distance may drop to zero between station name and invalid temp "---" -> prepend 3 spaces
|
||||
$line =~ s/ /;/g; # now min. column distance is 3 spaces -> convert to semicolon
|
||||
$line =~ s/;+/;/g; # replace multiple consecutive semicolons by one semicolon
|
||||
my @b = split(';', $line); # split columns by semicolon
|
||||
push @a, $_.'/'.$b[0]; # concat region name and station name (1st column)
|
||||
}
|
||||
}
|
||||
}
|
||||
close WXDATA;
|
||||
}
|
||||
}
|
||||
|
||||
if (!@a) {
|
||||
Log3($name, 4, "GDS $name: Error: unable to open forecast file!");
|
||||
}
|
||||
|
||||
@a = sort(@a);
|
||||
my $liste = join(",", @a);
|
||||
$liste =~ s/\s+,/,/g; # replace multiple spaces followed by comma with comma
|
||||
$liste =~ s/\s/_/g; # replace spaces in stationName with underscore for list in frontend
|
||||
|
||||
return $liste;
|
||||
}
|
||||
|
||||
####################################################################################################
|
||||
#
|
||||
# create weblinks
|
||||
# provided by jensb
|
||||
#
|
||||
####################################################################################################
|
||||
|
||||
# weather description to icon name mapping
|
||||
my %GDSDayWeatherIconMap = (
|
||||
'bedeckt' => 'overcast',
|
||||
'bewölkt' => 'mostlycloudy',
|
||||
'Dunst oder flacher Nebel' => 'haze',
|
||||
'gefrierender Nebel' => 'icy',
|
||||
'gering bewölkt' => 'partlycloudy',
|
||||
'Gewitter' => 'thunderstorm',
|
||||
'Glatteisbildung' => 'icy',
|
||||
'Graupelschauer' => 'snow',
|
||||
'Hagelschauer' => 'snow',
|
||||
'heiter' => 'partlycloudy',
|
||||
'in Wolken' => 'mostlycloudy',
|
||||
'kein signifikantes Wetter' => 'na',
|
||||
'kräftiger Graupelschauer' => 'heavysnow',
|
||||
'kräftiger Hagelschauer' => 'heavysnow',
|
||||
'kräftiger Regen' => 'heavyrain',
|
||||
'kräftiger Regenschauer' => 'scatteredshowers',
|
||||
'kräftiger Schneefall' => 'heavysnow',
|
||||
'kräftiger Schneeregen' => 'rainsnow',
|
||||
'kräftiger Schneeregenschauer' => 'rainsnow',
|
||||
'kräftiger Schneeschauer' => 'heavysnow',
|
||||
'leicht bewölkt' => 'partlycloudy',
|
||||
'leichter Regen' => 'mist',
|
||||
'leichter Schneefall' => 'snow',
|
||||
'leichter Schneeregen' => 'rainsnow',
|
||||
'Nebel' => 'fog',
|
||||
'Regen' => 'rain',
|
||||
'Regenschauer' => 'scatteredshowers',
|
||||
'Sandsturm' => 'dust',
|
||||
'Schneefall' => 'snow',
|
||||
'Schneefegen' => 'snow',
|
||||
'Schneeregen' => 'rainsnow',
|
||||
'Schneeregenschauer' => 'rainsnow',
|
||||
'Schneeschauer' => 'snow',
|
||||
'schweres Gewitter' => 'thunderstorm',
|
||||
'stark bewölkt' => 'mostlycloudy',
|
||||
'starkes Gewitter' => 'thunderstorm',
|
||||
'wolkenlos' => 'sunny',
|
||||
'---' => 'mostlycloudy',
|
||||
);
|
||||
|
||||
my %GDSNightWeatherIconMap = (
|
||||
'bedeckt' => 'overcast',
|
||||
'bewölkt' => 'mostlycloudy_night',
|
||||
'Dunst oder flacher Nebel' => 'haze_night',
|
||||
'gefrierender Nebel' => 'icy',
|
||||
'gering bewölkt' => 'partlycloudy_night',
|
||||
'Gewitter' => 'thunderstorm',
|
||||
'Glatteisbildung' => 'icy',
|
||||
'Graupelschauer' => 'snow',
|
||||
'Hagelschauer' => 'snow',
|
||||
'heiter' => 'partlycloudy_night',
|
||||
'in Wolken' => 'mostlycloudy_night',
|
||||
'kein signifikantes Wetter' => 'na',
|
||||
'kräftiger Graupelschauer' => 'heavysnow',
|
||||
'kräftiger Hagelschauer' => 'heavysnow',
|
||||
'kräftiger Regen' => 'heavyrain',
|
||||
'kräftiger Regenschauer' => 'scatteredshowers_night',
|
||||
'kräftiger Schneefall' => 'heavysnow',
|
||||
'kräftiger Schneeregen' => 'rainsnow',
|
||||
'kräftiger Schneeregenschauer' => 'rainsnow',
|
||||
'kräftiger Schneeschauer' => 'heavysnow',
|
||||
'leicht bewölkt' => 'partlycloudy_night',
|
||||
'leichter Regen' => 'mist',
|
||||
'leichter Schneefall' => 'snow',
|
||||
'leichter Schneeregen' => 'rainsnow',
|
||||
'Nebel' => 'fog',
|
||||
'Regen' => 'rain',
|
||||
'Regenschauer' => 'scatteredshowers_night',
|
||||
'Sandsturm' => 'dust',
|
||||
'Schneefall' => 'snow',
|
||||
'Schneefegen' => 'snow',
|
||||
'Schneeregen' => 'rainsnow',
|
||||
'Schneeregenschauer' => 'rainsnow',
|
||||
'Schneeschauer' => 'snow',
|
||||
'schweres Gewitter' => 'thunderstorm',
|
||||
'stark bewölkt' => 'mostlycloudy_night',
|
||||
'starkes Gewitter' => 'thunderstorm',
|
||||
'wolkenlos' => 'sunny_night',
|
||||
'---' => 'mostlycloudy_night',
|
||||
);
|
||||
|
||||
# icon parameters
|
||||
use constant ICONHIGHT => 120;
|
||||
use constant ICONWIDTH => 175;
|
||||
use constant ICONSCALE => 0.5;
|
||||
|
||||
sub GDSIsDay($$) {
|
||||
# check if it is day at given time
|
||||
#
|
||||
# @param: time
|
||||
# @param: altitude, see documentation of module SUNRISE_EL
|
||||
my ($time, $altitude) = @_;
|
||||
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time);
|
||||
my $t = ($hour*60 + $min) + $sec;
|
||||
|
||||
my (undef, $srHour, $srMin, $srSec, undef) = GetTimeSpec(sunrise_abs_dat($time, $altitude));
|
||||
my $sunrise = ($srHour*60 + $srMin) + $srSec;
|
||||
|
||||
my (undef, $ssHour, $ssMin, $ssSec, undef) = GetTimeSpec(sunset_abs_dat($time, $altitude));
|
||||
my $sunset = ($ssHour*60 + $ssMin) + $ssSec;
|
||||
|
||||
return $t >= $sunrise && $t <= $sunset;
|
||||
}
|
||||
|
||||
sub GDSIconIMGTag($;$) {
|
||||
# get FHEM weather icon
|
||||
#
|
||||
# @param: weather description
|
||||
# @param: time of weather description or 1 for night, optional, defaults to daytime icons
|
||||
my $width = int(ICONSCALE*ICONWIDTH);
|
||||
my ($weather, $time) = @_;
|
||||
my $icon;
|
||||
if (!defined($time) || (defined($time) && $time > 1 && GDSIsDay($time, "REAL"))) {
|
||||
$icon = $GDSDayWeatherIconMap{$weather};
|
||||
} else {
|
||||
$icon = $GDSNightWeatherIconMap{$weather};
|
||||
}
|
||||
if (defined($icon)) {
|
||||
my $url= FW_IconURL("weather/$icon");
|
||||
my $style= " width=$width";
|
||||
return "<img src=\"$url\"$style alt=\"$icon\">";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
sub GDSAsHtmlV($;$) {
|
||||
# create forecast in a vertical HTML table
|
||||
#
|
||||
# @param: device name
|
||||
# @param: number of icons, optional, default 8
|
||||
my ($d,$items) = @_;
|
||||
$d = "<none>" if(!$d);
|
||||
$items = $items? $items - 1 : 7;
|
||||
return "$d is not a GDS instance<br>"
|
||||
if(!$defs{$d} || $defs{$d}{TYPE} ne "GDS");
|
||||
|
||||
my $width = int(ICONSCALE*ICONWIDTH);
|
||||
|
||||
my $ret = sprintf('<table class="weather"><tr><th width=%d></th><th></th></tr>', $width);
|
||||
$ret .= sprintf('<tr><td class="weatherIcon" width=%d>%s</td><td class="weatherValue"><span class="weatherDay">Aktuell: </span><span class="weatherCondition">%s</span><br><span class="weatherValue">%s°C</span><br><span class="weatherWind">Wind %s km/h %s</span></td></tr>',
|
||||
$width,
|
||||
GDSIconIMGTag(ReadingsVal($d, "c_weather", "?"), time_str2num(ReadingsTimestamp($d, "c_weather", TimeNow()))),
|
||||
ReadingsVal($d, "c_weather", "?"),
|
||||
ReadingsVal($d, "c_temperature", "?"),
|
||||
ReadingsVal($d, "c_windSpeed", "?"), ReadingsVal($d, "c_windDir", "?"));
|
||||
|
||||
# get time of last forecast
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time_str2num(ReadingsTimestamp($d, "fc3_weather24", TimeNow())));
|
||||
|
||||
for(my $i=0; $i<$items; $i++) {
|
||||
my $day = int(($i + 1)/2);
|
||||
my $timeLabel = $i == 0? ($hour < 17? '18' : '24') : ($i - 1)%2 == 0? '12' : '24';
|
||||
my $weekday = $i == 0? ($hour < 17? 'Spät' : 'Nachts') : ($i - 1)%2 == 0? ReadingsVal($d, "fc".$day."_weekday", "?").' früh' : ReadingsVal($d, "fc".$day."_weekday", "?").' spät';
|
||||
|
||||
if (($i - 1)%2 == 0) {
|
||||
$ret .= sprintf('<tr><td class="weatherIcon" width=%d>%s</td><td class="weatherValue"><span class="weatherDay">%s: </span><span class="weatherCondition">%s</span><br><span class="weatherMin">min %s°C</span><br><span class="weatherWind">%s</span></span></td></tr>',
|
||||
$width,
|
||||
GDSIconIMGTag(ReadingsVal($d, "fc".$day."_weather".$timeLabel, "?")),
|
||||
$weekday,
|
||||
ReadingsVal($d, "fc".$day."_weather".$timeLabel, "?"),
|
||||
ReadingsVal($d, "fc".$day."_tMinAir", "?"),
|
||||
ReadingsVal($d, "fc".$day."_windGust".$timeLabel, ""));
|
||||
} else {
|
||||
if ($i == 0 && $hour >= 17) {
|
||||
$ret .= sprintf('<tr><td class="weatherIcon" width=%d>%s</td><td class="weatherValue"><span class="weatherDay">%s: </span><span class="weatherCondition">%s</span><br><span class="weatherValue">%s°C</span><br><span class="weatherWind">%s</span></td></tr>',
|
||||
$width,
|
||||
GDSIconIMGTag(ReadingsVal($d, "fc".$day."_weather".$timeLabel, "?"), 1),
|
||||
$weekday,
|
||||
ReadingsVal($d, "fc".$day."_weather".$timeLabel, "?"),
|
||||
ReadingsVal($d, "fc".$day."_tAvgAir".$timeLabel, "?"),
|
||||
ReadingsVal($d, "fc".$day."_windGust".$timeLabel, ""));
|
||||
} else {
|
||||
$ret .= sprintf('<tr><td class="weatherIcon" width=%d>%s</td><td class="weatherValue"><span class="weatherDay">%s: </span><span class="weatherCondition">%s</span><br><span class="weatherMax">max %s°C</span><br><span class="weatherWind">%s</span></td></tr>',
|
||||
$width,
|
||||
GDSIconIMGTag(ReadingsVal($d, "fc".$day."_weather".$timeLabel, "?")),
|
||||
$weekday,
|
||||
ReadingsVal($d, "fc".$day."_weather".$timeLabel, "?"),
|
||||
ReadingsVal($d, "fc".$day."_tMaxAir", "?"),
|
||||
ReadingsVal($d, "fc".$day."_windGust".$timeLabel, ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ret .= "</table>";
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub GDSAsHtmlH($;$) {
|
||||
# create forecast in a horizontal HTML table
|
||||
#
|
||||
# @param: device name
|
||||
# @param: number of icons, optional, default 8
|
||||
my ($d, $items) = @_;
|
||||
$d = "<none>" if(!$d);
|
||||
$items = $items? $items - 1 : 7;
|
||||
return "$d is not a GDS instance<br>"
|
||||
if(!$defs{$d} || $defs{$d}{TYPE} ne "GDS");
|
||||
|
||||
my $width = 110;
|
||||
|
||||
my $ret = '<table class="weather">';
|
||||
|
||||
# get time of last forecast
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time_str2num(ReadingsTimestamp($d, "fc3_weather24", TimeNow())));
|
||||
|
||||
# weekday / time
|
||||
$ret .= sprintf('<tr><td align="center" class="weatherDay">Aktuell</td>');
|
||||
for(my $i=0; $i<$items; $i++) {
|
||||
my $day = int(($i + 1)/2);
|
||||
my $timeLabel = $i == 0? ($hour < 17? '18' : '24') : ($i - 1)%2 == 0? '12' : '24';
|
||||
my $weekday = $i == 0? ($hour < 17? 'Spät' : 'Nachts') : ($i - 1)%2 == 0? ReadingsVal($d, "fc".$day."_weekday", "?").' früh' : ReadingsVal($d, "fc".$day."_weekday", "?").' spät';
|
||||
$ret .= sprintf('<td align="center" class="weatherDay">%s</td>', $weekday);
|
||||
}
|
||||
$ret .= '</tr>';
|
||||
|
||||
# condition icon
|
||||
$ret .= sprintf('<tr><td align="center" class="weatherIcon" width=%d>%s</td>', $width, GDSIconIMGTag(ReadingsVal($d, "c_weather", "?"), time_str2num(ReadingsTimestamp($d, "c_weather", TimeNow()))));
|
||||
for(my $i=0; $i<$items; $i++) {
|
||||
my $day = int(($i + 1)/2);
|
||||
my $timeLabel = $i == 0? ($hour < 17? '18' : '24') : ($i - 1)%2 == 0? '12' : '24';
|
||||
$ret .= sprintf('<td align="center" class="weatherIcon" width=%d>%s</td>', $width, GDSIconIMGTag(ReadingsVal($d, "fc".$day."_weather".$timeLabel, "?"), $i==0 && $hour >= 17? 1 : undef));
|
||||
}
|
||||
$ret .= '</tr>';
|
||||
|
||||
# condition text
|
||||
$ret .= sprintf('<tr><td align="center" class="weatherCondition">%s</td>', ReadingsVal($d, "c_weather", "?"));
|
||||
for(my $i=0; $i<$items; $i++) {
|
||||
my $day = int(($i + 1)/2);
|
||||
my $timeLabel = $i == 0? ($hour < 17? '18' : '24') : ($i - 1)%2 == 0? '12' : '24';
|
||||
$ret .= sprintf('<td align="center" class="weatherCondition">%s</td>', ReadingsVal($d, "fc".$day."_weather".$timeLabel, "?"));
|
||||
}
|
||||
$ret .= '</tr>';
|
||||
|
||||
# temperature / min temperature
|
||||
$ret .= sprintf('<tr><td align="center" class="weatherValue">%s°C</td>', ReadingsVal($d, "c_temperature", "?"));
|
||||
for(my $i=0; $i<$items; $i++) {
|
||||
my $day = int(($i + 1)/2);
|
||||
my $timeLabel = $i == 0? ($hour < 17? '18' : '24') : ($i - 1)%2 == 0? '12' : '24';
|
||||
if (($i - 1)%2 == 0) {
|
||||
$ret .= sprintf('<td align="center" class="weatherMin">min %s°C</td>', ReadingsVal($d, "fc".$day."_tMinAir", "?"));
|
||||
} else {
|
||||
if ($i == 0 && $hour >= 17) {
|
||||
$ret .= sprintf('<td align="center" class="weatherValue">%s°C</td>', ReadingsVal($d, "fc".$day."_tAvgAir".$timeLabel, "?"));
|
||||
} else {
|
||||
$ret .= sprintf('<td align="center" class="weatherMax">max %s°C</td>', ReadingsVal($d, "fc".$day."_tMaxAir", "?"));
|
||||
}
|
||||
}
|
||||
}
|
||||
$ret .= '</tr>';
|
||||
|
||||
# wind
|
||||
$ret .= sprintf('<tr><td align="center" class="weatherWind">%s km/h %s</td>', ReadingsVal($d, "c_windSpeed", "?"), ReadingsVal($d, "c_windDir", "?"));
|
||||
for(my $i=0; $i<$items; $i++) {
|
||||
my $day = int(($i + 1)/2);
|
||||
my $timeLabel = $i == 0? ($hour < 17? '18' : '24') : ($i - 1)%2 == 0? '12' : '24';
|
||||
$ret .= sprintf('<td align="center" class="weatherWind">%s</td>', ReadingsVal($d, "fc".$day."_windGust".$timeLabel, ""));
|
||||
}
|
||||
$ret .= "</tr></table>";
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub GDSAsHtmlD($;$) {
|
||||
# create forecast in a horizontal or vertical HTML table depending on the display orientation
|
||||
#
|
||||
# @param: device name
|
||||
# @param: number of icons, optional, default 8
|
||||
my ($d,$i) = @_;
|
||||
if($FW_ss) {
|
||||
GDSAsHtmlV($d,$i);
|
||||
} else {
|
||||
GDSAsHtmlH($d,$i);
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
####################################################################################################
|
||||
#
|
||||
# Documentation
|
||||
# Documentation
|
||||
#
|
||||
####################################################################################################
|
||||
#
|
||||
@ -1476,10 +2067,15 @@ sub mergeCapFile($) {
|
||||
# 2015-10-08 changed added mergeCapFile()
|
||||
# code cleanup in buildCAPList()
|
||||
# use system call "unzip" instead of Archive::Zip
|
||||
# added NotifyFn for rereadcfg after INITIALIZED|REREADCFG
|
||||
# added NotifyFn for rereadcfg after INITIALIZED
|
||||
# improved startup data retrieval
|
||||
# improved attribute handling
|
||||
#
|
||||
# 2015-10-09 changed removed createIndexFile(), no longer needed since 2015-01-30
|
||||
# added forecast retrieval
|
||||
# added weblink generator
|
||||
# done a lot of code cleanup
|
||||
#
|
||||
####################################################################################################
|
||||
#
|
||||
# Further informations
|
||||
@ -1513,22 +2109,6 @@ sub mergeCapFile($) {
|
||||
# --- : Wert nicht vorhanden
|
||||
#
|
||||
####################################################################################################
|
||||
#
|
||||
# sub
|
||||
# _calctz($@)
|
||||
# {
|
||||
# my ($nt,@lt) = @_;
|
||||
|
||||
# my $off = $lt[2]*3600+$lt[1]*60+$lt[0];
|
||||
# $off = 12*3600-$off;
|
||||
# $nt += $off; # This is noon, localtime
|
||||
|
||||
# my @gt = gmtime($nt);
|
||||
|
||||
# return (12-$gt[2]);
|
||||
# }
|
||||
#
|
||||
####################################################################################################
|
||||
|
||||
=pod
|
||||
=begin html
|
||||
@ -1552,11 +2132,20 @@ sub mergeCapFile($) {
|
||||
<b>Define</b>
|
||||
<ul>
|
||||
|
||||
<br/>
|
||||
<code>define <name> GDS <username> <password></code>
|
||||
<br/><br/>
|
||||
This module provides connection to <a href="http://www.dwd.de/grundversorgung">GDS service</a> generated by <a href="http://www.dwd.de">DWD</a><br/>
|
||||
|
||||
<br>
|
||||
<code>define <name> GDS <username> <password></code><br>
|
||||
<br>
|
||||
This module provides connection to <a href="http://www.dwd.de/grundversorgung">GDS service</a> generated by <a href="http://www.dwd.de">DWD</a><br>
|
||||
<br>
|
||||
It also provides three additional functions <code>GDSAsHtmlV</code>, <code>GDSAsHtmlH</code> and <code>GDSAsHtmlD</code>.
|
||||
The first function returns the HTML code for a vertically arranged weather forecast.
|
||||
The second function returns the HTML code for a horizontally arranged weather forecast.
|
||||
The third function dynamically picks the orientation depending on whether a smallscreen style is set (vertical layout) or not (horizontal layout).
|
||||
The attributes gdsSetCond and gdsSetForecast must be configured for the functions to work.
|
||||
Each of these functions accepts an additional parameter to limit the number of icons to display (1...8).
|
||||
If the attribute gdsSetForecast is not configured this parameter should be set to 1.<br>
|
||||
<br>
|
||||
Example: <code>define MyForecastWeblink weblink htmlCode { GDSAsHtml("MyWeather") }</code> where "MyWeather" is the name of your GDS device.
|
||||
</ul>
|
||||
<br/><br/>
|
||||
|
||||
@ -1569,7 +2158,7 @@ sub mergeCapFile($) {
|
||||
<br/><br/>
|
||||
<ul>
|
||||
<li>alerts: Delete all a_* readings</li>
|
||||
<li>all: Delete all a_*, c_* and g_* readings</li>
|
||||
<li>all: Delete all a_*, c_*, g_* and fc_* readings</li>
|
||||
</ul>
|
||||
<br/>
|
||||
|
||||
@ -1578,6 +2167,11 @@ sub mergeCapFile($) {
|
||||
<ul>Retrieve current conditions at selected station. Data will be updated periodically.</ul>
|
||||
<br/>
|
||||
|
||||
<code>set <name> forecasts <region>/<stationName></code>
|
||||
<br/><br/>
|
||||
<ul>Retrieve forecasts for today and the following 3 days for selected station. Data will be updated periodically.</ul>
|
||||
<br/>
|
||||
|
||||
<code>set <name> help</code>
|
||||
<br/><br/>
|
||||
<ul>Show a help text with available commands</ul>
|
||||
@ -1585,16 +2179,17 @@ sub mergeCapFile($) {
|
||||
|
||||
<code>set <name> rereadcfg</code>
|
||||
<br/><br/>
|
||||
<ul>Reread all required data from DWD Server manually: station list and CAP data</ul>
|
||||
<ul>Reread all required data from DWD Server manually: station lists and CAP data</ul>
|
||||
<br/>
|
||||
|
||||
<code>set <name> update</code>
|
||||
<br/><br/>
|
||||
<ul>Update conditions readings at selected station and restart update-timer</ul>
|
||||
<ul>Update conditions and forecasts readings at selected station and restart update-timer</ul>
|
||||
<br/>
|
||||
|
||||
<li>condition readings generated by SET use prefix "c_"</li>
|
||||
<li>readings generated by SET will be updated automatically every 60 minutes</li>
|
||||
<li>forecast readings generated by SET use prefix "fcd_" and a postfix of "hh" with d=relative day (0=today) and hh=last hour of forecast (exclusive)</li>
|
||||
<li>readings generated by SET will be updated automatically every 20 minutes</li>
|
||||
|
||||
</ul>
|
||||
<br/><br/>
|
||||
@ -1614,6 +2209,11 @@ sub mergeCapFile($) {
|
||||
<ul>Retrieve current conditions at selected station</ul>
|
||||
<br/>
|
||||
|
||||
<code>get <name> forecasts <region></code>
|
||||
<br/><br/>
|
||||
<ul>Retrieve forecasts for today and the following 3 days for selected region as text</ul>
|
||||
<br/>
|
||||
|
||||
<code>get <name> conditionsmap <region></code>
|
||||
<br/><br/>
|
||||
<ul>Retrieve map (imagefile) showing current conditions at selected station</ul>
|
||||
@ -1685,8 +2285,10 @@ sub mergeCapFile($) {
|
||||
<li><b>gdsAll</b> - defines filter for "all data" from alert message</li>
|
||||
<li><b>gdsDebug</b> - defines filter for debug informations</li>
|
||||
<li><b>gdsSetCond</b> - defines conditions area to be used after system restart</li>
|
||||
<li><b>gdsSetForecast</b> - defines forecasts region/station to be used after system restart</li>
|
||||
<li><b>gdsLong</b> - show long text fields "description" and "instruction" from alert message in readings</li>
|
||||
<li><b>gdsPolygon</b> - show polygon data from alert message in a reading</li>
|
||||
<li><b>gdsShowMapFilesMenu</b> - if set to 0, the "GDS Files" menu in the left navigation bar will not be shown</li>
|
||||
<br/>
|
||||
<li><b>gdsPassiveFtp</b> - set to 1 to use passive FTP transfer</li>
|
||||
<li><b>gdsFwName</b> - define firewall hostname in format <hostname>:<port></li>
|
||||
@ -1703,7 +2305,23 @@ sub mergeCapFile($) {
|
||||
that will be increased for every valid alert message in selected area<br/></li>
|
||||
<li><b>a_count</b> - number of currently valid alert messages, can be used for own loop iterations on alert messages</li>
|
||||
<li><b>a_valid</b> - returns 1 if at least one of decoded alert messages is valid</li>
|
||||
<li><b>c_<readingName></b> - weather data from SET weather conditions. Readings will be updated every 20 minutes</li>
|
||||
<li><b>c_<readingName></b> - weather data from SET weather conditions. Readings will be updated every 20 minutes.</li>
|
||||
<li><b>fc?_<readingName>??</b> - weather data from SET weather forecasts, prefix by relative day and postfixed by last hour. Readings will be updated every 20 minutes.<br>
|
||||
<i><ul>
|
||||
<li>0_weather06 and ?_weather12 (with ? greater 0) is the weather in the morning</li>
|
||||
<li>0_weather12 is the weather at noon</li>
|
||||
<li>0_weather18 and ?_weather24 (with ? greater 0) is the weather in the afternoon</li>
|
||||
<li>0_weather24 is the weather at midnight</li>
|
||||
<li>0_windGust06 and ?_windGust12 (with ? greater 0) is the wind in the morning</li>
|
||||
<li>0_windGust12 is the wind at noon</li>
|
||||
<li>0_windGust18 and ?_windGust24 (with ? greater 0) is the wind in the afternoon</li>
|
||||
<li>0_windGust24 is the wind at midnight</li>
|
||||
<li>?_tMinAir is minimum temperature in the morning</li>
|
||||
<li>0_tAvgAir12 is the average temperature at noon</li>
|
||||
<li>?_tMaxAir is the maximum temperature in the afternoon</li>
|
||||
<li>0_tAvgAir24 is the average temperature at midnight</li>
|
||||
</ul></i>
|
||||
</li>
|
||||
<li><b>g_<readingName></b> - weather data from GET weather conditions. Readings will NOT be updated automatically</li>
|
||||
</ul>
|
||||
<br/><br/>
|
||||
|
Loading…
x
Reference in New Issue
Block a user