2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-01-31 12:49:34 +00:00

switched 59_Weather from Google to Yahoo API (thanks to Erwin Menschhorn)

tag img replaced tag gif in 02_RSS layout definition

git-svn-id: https://svn.fhem.de/fhem/trunk@1853 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
borisneubert 2012-09-16 16:31:41 +00:00
parent 689c29f684
commit fc6313af2a
3 changed files with 234 additions and 100 deletions

View File

@ -5,7 +5,7 @@
# e-mail: omega at online dot de
#
##############################################
# $Id: $
# $Id $
package main;
use strict;
@ -248,21 +248,41 @@ RSS_itemDate {
}
sub
RSS_itemGif {
my ($S,$x,$y,$host,$filename,%params)= @_;
return if($host eq "");
return if($filename eq "");
RSS_itemImg {
my ($S,$x,$y,$scale,$imgtype,$srctype,$arg,%params)= @_;
return if($arg eq "");
my $I;
if($srctype eq "url") {
my $data = GetFileFromURL($arg,3,undef,1);
if($imgtype eq "gif") {
$I= GD::Image->newFromGifData($data);
} elsif($imgtype eq "png") {
$I= GD::Image->newFromPngData($data);
} elsif($imgtype eq "jpeg") {
$I= GD::Image->newFromJpegData($data);
} else {
return;
}
} elsif($srctype eq "file") {
if($imgtype eq "gif") {
$I= GD::Image->newFromGif($arg);
} elsif($imgtype eq "png") {
$I= GD::Image->newFromPng($arg);
} elsif($imgtype eq "jpeg") {
$I= GD::Image->newFromJpeg($arg);
} else {
return;
}
} else {
return;
}
($x,$y)= RSS_xy($S,$x,$y);
my $data = GetFileFromURL("http://$host$filename");
return unless(defined($data));
my $I= GD::Image->newFromGifData($data);
my ($width,$height)= $I->getBounds();
Log 5, "RSS placing $host$filename ($width x $height) at ($x,$y)";
$S->copy($I,$x,$y,0,0,$width,$height);
my ($swidth,$sheight)= (int($scale*$width), int($scale*$height));
#Debug "RSS placing $arg ($swidth x $sheight) at ($x,$y)";
Log 5, "RSS placing $arg ($swidth x $sheight) at ($x,$y)";
$S->copyResampled($I,$x,$y,0,0,$swidth,$sheight,$width,$height);
}
@ -278,7 +298,7 @@ RSS_evalLayout($$@) {
$params{pt}= 12;
$params{rgb}= "ffffff";
my ($x,$y,$text,$host,$filename,$format);
my ($x,$y,$scale,$text,$imgtype,$srctype,$arg,$format);
my $cont= "";
foreach my $line (@layout) {
@ -315,10 +335,10 @@ RSS_evalLayout($$@) {
} elsif($cmd eq "date") {
($x,$y)= split("[ \t]+", $def, 2);
RSS_itemDate($S,$x,$y,%params);
} elsif($cmd eq "gif") {
($x,$y,$host,$filename)= split("[ \t]+", $def,4);
my $fn= AnalyzePerlCommand(undef, $filename);
RSS_itemGif($S,$x,$y,$host,$fn,%params);
} elsif($cmd eq "img") {
($x,$y,$scale,$imgtype,$srctype,$arg)= split("[ \t]+", $def,6);
my $arg= AnalyzePerlCommand(undef, $arg);
RSS_itemImg($S,$x,$y,$scale,$imgtype,$srctype,$arg,%params);
} else {
Log 1, "$name: Illegal command $cmd in layout definition.";
}

View File

@ -1,24 +1,23 @@
#
#
# 59_Weather.pm
# written by Dr. Boris Neubert 2009-06-01
# maintainer: Dr. Boris Neubert 2009-06-01
# e-mail: omega at online dot de
# Port to Yahoo by Erwin Menschhorn 2012-08-30
# e-mail emenschhorn at gmail dot com
#
##############################################
# $Id$
package main;
use strict;
use warnings;
use Time::HiRes qw(gettimeofday);
my $UseWeatherGoogle= 0; # if you want Weather:Google back please set this to 1 and uncomment below.
## use Weather::Google;
#
# uses the Yahoo! Weather API: http://developer.yahoo.com/weather/
#
# taken from Daniel "Possum" LeWarne's Google::Weather module
# http://cpansearch.perl.org/src/POSSUM/Weather-Google-0.05/lib/Weather/Google.pm
# Mapping of current supported encodings
my %DEFAULT_ENCODINGS = (
@ -40,15 +39,63 @@ my %DEFAULT_ENCODINGS = (
'zh-TW' => 'utf-8',
);
# Mapping / translation of current weather codes 0-47
my @YahooCodes_us = (
'tornado', 'tropical storm', 'hurricane', 'severe thunderstorms', 'thunderstorms', 'mixed rain and snow',
'mixed rain and sleet', 'mixed snow and sleet', 'freezing drizzle', 'drizzle', 'freezing rain' ,'showers',
'showers', 'snow flurries', 'light snow showers', 'blowing snow', 'snow', 'hail',
'sleet', 'dust', 'foggy', 'haze', 'smoky', 'blustery',
'windy', 'cold', 'cloudy',
'mostly cloudy', # night
'mostly cloudy', # day
'partly cloudy', # night
'partly cloudy', # day
'clear', #night
'sunny',
'fair', #night
'fair', #day
'mixed rain and hail',
'hot', 'isolated thunderstorms', 'scattered thunderstorms', 'scattered thunderstorms', 'scattered showers', 'heavy snow',
'scattered snow showers', 'heavy snow', 'partly cloudy', 'thundershowers', 'snow showers', 'isolated thundershowers');
my @YahooCodes_de = (
'Tornado', 'schwerer Sturm', 'Sturm', 'schwere Gewitter', 'Gewitter', 'Regen und Schnee',
'Regen und Schnee', 'Schnee und Regen', 'Eisregen', 'Graupelschauer', 'gefrierender Regen' ,'Regen',
'Regen', 'Schneegestöber', 'leichter Schneeschauer', 'Schneeverwehungen', 'Schnee', 'Hagel',
'Schnee und Regen', 'Dunst', 'neblig', 'Staub oder Rauch', 'Smog', 'blustery',
'windig', 'kalt', 'wolkig',
'überwiegend wolkig', # night
'überwiegend wolkig', # day
'teilweise wolkig', # night
'teilweise wolkig', # day
'klar', # night
'sonnig',
'bewölkt', # night
'bewölkt', # day
'Regen und Hagel',
'heiss', 'einzelne Gewitter', 'vereinzelt Gewitter', 'vereinzelt Gewitter', 'vereinzelt Regen', 'heftiger Schneefall',
'vereinzelt Schneeschauer', 'heftiger Schneefall', 'teilweise wolkig', 'Gewitterregen', 'Schneeschauer', 'vereinzelt Gewitter');
my @directions_de = ('N', 'NNO', 'NO', 'ONO', 'O', 'OSO', 'SO', 'SSO', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW');
my %wdayXlate = ('Mon' => 'Mo.', 'Tue' => 'Di.', 'Wed'=> 'Mi.', 'Thu' => 'Do.', 'Fri' => 'Fr.', 'Sat' => 'Sa.', 'Sun' => 'So.');
my @iconlist = (
'storm', 'storm', 'storm', 'thunderstorm', 'thunderstorm', 'rainsnow',
'sleet', 'snow', 'drizzle', 'drizzle', 'icy' ,'chance_of_rain',
'chance_of_rain', 'snowflurries', 'chance_of_snow', 'heavysnow', 'snow', 'heavyrain',
'sleet', 'dust', 'fog', 'haze', 'smoke', 'flurries',
'windy', 'icy', 'cloudy', 'mostlycloudy_night', 'mostlycloudy', 'partly_cloudy_night',
'partly_cloudy', 'clear', 'sunny', 'mostly_clear_night', 'overcast', 'heavyrain',
'clear', 'scatteredthunderstorms', 'scatteredthunderstorms', 'scatteredthunderstorms', 'scatteredshowers', 'heavysnow',
'chance_of_snow', 'heavysnow', 'partly_cloudy', 'heavyrain', 'chance_of_snow', 'scatteredshowers');
#####################################
sub Weather_Initialize($) {
my ($hash) = @_;
# Provider
# $hash->{Clients} = undef;
# Consumer
$hash->{DefFn} = "Weather_Define";
$hash->{UndefFn} = "Weather_Undef";
$hash->{GetFn} = "Weather_Get";
@ -68,16 +115,22 @@ sub latin1_to_utf8($) {
###################################
sub temperature_in_c {
sub temperature_in_c($$) {
my ($temperature, $unitsystem)= @_;
return $unitsystem ne "SI" ? int(($temperature-32)*5/9+0.5) : $temperature;
}
sub wind_in_km_per_h {
sub wind_in_km_per_h($$) {
my ($wind, $unitsystem)= @_;
return $unitsystem ne "SI" ? int(1.609344*$wind+0.5) : $wind;
}
sub degrees_to_direction($) {
my ($degrees) = @_;
my $mod = int((($degrees + 11.25) % 360) / 22.5);
return $directions_de[$mod];
}
###################################
sub Weather_UpdateReading($$$$) {
@ -112,36 +165,111 @@ sub Weather_UpdateReading($$$$) {
return 1;
}
###################################
sub Weather_RetrieveDataDirectly($)
###################################
sub Weather_RetrieveData($)
{
my ($hash)= @_;
my $location= $hash->{LOCATION};
#$location =~ s/([^\w()’*~!.-])/sprintf '%%%02x', ord $1/eg;
my $lang= $hash->{LANG};
my $location= $hash->{LOCATION}; # WOEID [WHERE-ON-EARTH-ID], go to http://weather.yahoo.com to find out
my $units= $hash->{UNITS};
my $fc = undef;
my $xml = GetFileFromURL("http://www.google.com/ig/api?weather=" . $location . "&hl=" . $lang);
my $xml = GetFileFromURL("http://weather.yahooapis.com/forecastrss?w=" . $location . "&u=" . $units, 3, undef, 1);
return 0 if( ! defined $xml || $xml eq "");
foreach my $l (split("<",$xml)) {
#Log 1, "DEBUG WEATHER: line=\"$l\"";
next if($l eq ""); # skip empty lines
$l =~ s/(\/|\?)?>$//; # strip off /> and >
my ($tag,$value)= split(" ", $l, 2); # split tag data=..... at the first blank
#Log 1, "DEBUG WEATHER: tag=\"$tag\" value=\"$value\"";
$fc= 0 if($tag eq "current_conditions");
$fc++ if($tag eq "forecast_conditions");
next if(!defined($value) || ($value !~ /^data=/));
next if(!defined($tag) || ($tag !~ /^yweather:/));
$fc= 0 if($tag eq "yweather:condition");
$fc++ if($tag eq "yweather:forecast");
my $prefix= $fc ? "fc" . $fc ."_" : "";
my $key= $tag;
$value=~ s/^data=\"(.*)\"$/$1/; # extract DATA from data="DATA"
if($DEFAULT_ENCODINGS{$lang} eq "latin1") {
$value= latin1_to_utf8($value); # latin1 -> UTF-8
### location
if ($tag eq "yweather:location" ) {
$value =~/city="(.*?)" .*country="(.*?)".*/;
my $loc = "";
$loc = $1 if (defined($1));
$loc .= ", $2" if (defined($2));
readingsUpdate($hash, "city", $loc);
}
#Log 1, "DEBUG WEATHER: prefix=\"$prefix\" tag=\"$tag\" value=\"$value\"";
Weather_UpdateReading($hash,$prefix,$key,$value);
### current condition and forecast
if (($tag eq "yweather:condition" ) || ($tag eq "yweather:forecast" )) {
my $code = (($value =~/code="([0-9]*?)".*/) ? $1 : undef);
if (defined($code)) {
readingsUpdate($hash, $prefix . "code", $code);
my $text = $YahooCodes_de[$code];
if ($text) { readingsUpdate($hash, $prefix . "condition", $text); }
#### add icon logic here - generate from code
$text = $iconlist[$code];
readingsUpdate($hash, $prefix . "icon", $text) if ($text);
}
}
### current condition
if ($tag eq "yweather:condition" ) {
my $temp = (($value =~/temp="([0-9.]*?)".*/) ? $1 : undef);
if ($temp) {
readingsUpdate($hash, "temperature", $temp);
readingsUpdate($hash, "temp_c", $temp); # compatibility
$temp = ( $temp * 9 / 5 ) + 32; # Celsius to Fahrenheit
readingsUpdate($hash, "temp_f", $temp); # compatibility
}
my $datum = (($value =~/date=".*? ([0-9].*)".*/) ? $1 : undef);
readingsUpdate($hash, "current_date_time", $datum) if (defined($1));
my $day = (($value =~/date="(.*?), .*/) ? $1 : undef);
if ($day) {
my $day_de = $wdayXlate{$day};
readingsUpdate($hash, "day_of_week", $day_de);
}
}
### forecast
if ($tag eq "yweather:forecast" ) {
my $low_c = (($value =~/low="([0-9.]*?)".*/) ? $1 : undef);
if ($low_c) { readingsUpdate($hash, $prefix . "low_c", $low_c); }
my $high_c = (($value =~/high="([0-9.]*?)".*/) ? $1 : undef);
if ($high_c) { readingsUpdate($hash, $prefix . "high_c", $high_c); }
my $day1 = (($value =~/day="(.*?)" .*/) ? $1 : undef); # forecast
if ($day1) {
my $day1_de = $wdayXlate{$day1};
readingsUpdate($hash, $prefix . "day_of_week", $day1_de);
}
}
### humidiy / Pressure
if ($tag eq "yweather:atmosphere" ) {
$value =~/humidity="([0-9.]*?)" .*visibility="([0-9.]*?|\s*?)" .*pressure="([0-9.]*?)" .*rising="([0-9.]*?)" .*/;
if ($1) { readingsUpdate($hash, "humidity", $1); }
my $vis = (($2 eq "") ? " " : $2); # clear visibility field
readingsUpdate($hash, "visibility", $vis);
if ($3) { readingsUpdate($hash, "pressure", $3); }
if ($4) { readingsUpdate($hash, "pressure-trend", $4); }
}
### wind
if ($tag eq "yweather:wind" ) {
$value =~/chill="([0-9.]*?)" .*direction="([0-9.]*?)" .*speed="([0-9.]*?)" .*/;
readingsUpdate($hash, "wind_chill", $1) if (defined($1));
readingsUpdate($hash, "wind_direction", $2) if (defined($2));
my $windspeed= defined($3) ? int($3) : "";
readingsUpdate($hash, "wind_speed", $windspeed);
readingsUpdate($hash, "wind", $windspeed); # duplicate for compatibility
if (defined($2) & defined($3)) {
my $wdir = degrees_to_direction($2);
readingsUpdate($hash, "wind_condition", "Wind: $wdir mit $windspeed km/h"); # compatibility
}
}
}
}
} #end sub
###################################
sub Weather_RetrieveDataViaWeatherGoogle($)
@ -201,14 +329,9 @@ sub Weather_GetUpdate($)
InternalTimer(gettimeofday()+$hash->{INTERVAL}, "Weather_GetUpdate", $hash, 1);
}
readingsBeginUpdate($hash);
if($UseWeatherGoogle) {
Weather_RetrieveDataViaWeatherGoogle($hash);
} else {
Weather_RetrieveDataDirectly($hash);
}
Weather_RetrieveData($hash);
my $temperature= $hash->{READINGS}{temperature}{VAL};
my $humidity= $hash->{READINGS}{humidity}{VAL};
@ -291,7 +414,8 @@ sub Weather_Define($$) {
$hash->{LOCATION} = $location;
$hash->{INTERVAL} = $interval;
$hash->{LANG} = $lang;
$hash->{LANG} = $lang;
$hash->{UNITS} = "c"; # hardcoded to use degrees centigrade (Celsius)
$hash->{READINGS}{current_date_time}{TIME}= TimeNow();
$hash->{READINGS}{current_date_time}{VAL}= "none";
@ -315,36 +439,23 @@ sub Weather_Undef($$) {
#####################################
# Icon Parameter
use constant ICONHIGHT => 120;
use constant ICONWIDTH => 175;
use constant ICONSCALE => 0.5;
#####################################
sub
WeatherIconIMGTag($$$) {
WeatherIconIMGTag($) {
use constant GOOGLEURL => "http://www.google.de";
use constant SIZE => "50%";
my ($icon,$uselocal,$isday)= @_;
my $url;
my $style= "";
my $width= int(ICONSCALE*ICONWIDTH);
my ($icon)= @_;
my $url= FW_IconURL("weather/$icon");
my $style= " width=$width";
return "<img src=\"$url\"$style alt=\"$icon\">";
if($uselocal) {
# strip off path and extension
$icon =~ s,^/ig/images/weather/(.*)\.gif$,$1,;
if($isday) {
$icon= "weather/${icon}"
} else {
$icon= "weather/${icon}_night"
}
$url= "fhem/icons/$icon";
$style= " height=".SIZE." width=".SIZE;
} else {
$url= GOOGLEURL . $icon;
}
return "<img src=\"$url\"$style>";
}
#####################################
@ -357,24 +468,23 @@ WeatherAsHtml($)
return "$d is not a Weather instance<br>"
if(!$defs{$d} || $defs{$d}{TYPE} ne "Weather");
my $uselocal= AttrVal($d,"localicons",0);
my $isday;
if(exists &isday) {
$isday = isday();
} else {
$isday = 1; #($hour>6 && $hour<19);
}
my $ret = "<table>";
$ret .= sprintf('<tr><td>%s</td><td>%s<br>temp %s, hum %s, %s</td></tr>',
WeatherIconIMGTag(ReadingsVal($d, "icon", ""),$uselocal,$isday),
my $width= int(ICONSCALE*ICONWIDTH);
my $ret = sprintf("<table><tr><th width=%d></th><th></th></tr>", $width);
$ret .= sprintf('<tr><td width=%d>%s</td><td>%s<br>%s°C %s%%<br>%s</td></tr>',
$width,
WeatherIconIMGTag(ReadingsVal($d, "icon", "")),
ReadingsVal($d, "condition", ""),
ReadingsVal($d, "temp_c", ""), ReadingsVal($d, "humidity", ""),
ReadingsVal($d, "wind_condition", ""));
for(my $i=1; $i<=4; $i++) {
$ret .= sprintf('<tr><td>%s</td><td>%s: %s<br>min %s max %s</td></tr>',
WeatherIconIMGTag(ReadingsVal($d, "fc${i}_icon", ""),$uselocal,$isday),
for(my $i=1; $i<=2; $i++) {
# Yahoo provides only 2 days.
#next if (ReadingsVal($d, "fc${i}_code", "") eq ""); # MH skip non existent entries
$ret .= sprintf('<tr><td width=%d>%s</td><td>%s: %s<br>min %s°C max %s°C</td></tr>',
$width,
WeatherIconIMGTag(ReadingsVal($d, "fc${i}_icon", "")),
ReadingsVal($d, "fc${i}_day_of_week", ""),
ReadingsVal($d, "fc${i}_condition", ""),
ReadingsVal($d, "fc${i}_low_c", ""), ReadingsVal($d, "fc${i}_high_c", ""));

View File

@ -6228,9 +6228,13 @@ Attributes:<br>
<li>time &lt;x&gt; &lt;y&gt;<br>Renders the current time in HH:MM format.</li><br>
<li>seconds &lt;x&gt; &lt;y&gt; &lt;format&gt<br>Renders the curent seconds. Maybe usefull for a RSS Clock. With option colon a : </li><br>
<li>date &lt;x&gt; &lt;y&gt;<br>Renders the current date in DD:MM:YYY format.</li><br>
<li>gif &lt;x&gt; &lt;y&gt; &lt;hostname&gt; &lt;filename&gt; <br>Renders the GIF picture
that is downloaded from the given host. You can use
<code>{ <a href="#perl">&lt;perl special&gt;</a> }</code> for &lt;filename&gt. See below for example.</li><br>
<li>img &lt;x&gt; &lt;y&gt; &lt;s&gt; &lt;imgtype&gt; &lt;srctype&gt; &lt;arg&gt; <br>Renders a picture at the
position (&lt;x&gt;, &lt;y&gt;). The &lt;imgtype&gt; is one of <code>gif</code>, <code>jpeg</code>, <code>png</code>.
The picture is scaled by the factor &lt;s&gt; (a decimal value). If &lt;srctype&gt; is <code>file</code>, the picture
is loaded from the filename &lt;arg&gt;, if &lt;srctype&gt; is <code>url</code>, the picture
is loaded from the URL &lt;arg&gt;. You can use
<code>{ <a href="#perl">&lt;perl special&gt;</a> }</code> for &lt;arg&gt. See below for example.
Notice: do not load the image from URL that is served by fhem as it leads to a deadlock.<br></li>
</li><br>
</ul>
@ -6241,8 +6245,8 @@ Attributes:<br>
pt 48 # font size in points<br>
time 0.10 0.90<br>
pt 24<br>
text 0.10 0.95 { ReadingsVal("MyWeather","temperature","?"). "°C" }<br>
gif 20 530 www.google.com:80 { ReadingsVal("e.ext.Weather","icon","") }<br>
text 0.10 0.95 { ReadingsVal("MyWeather","temperature","?"). "°C" }<br>
img 20 530 0.5 png file { "/usr/share/fhem/www/images/weather/" . ReadingsVal("MyWeather","icon","") . ".png" }<br>
</code>
</ul>