From 8b3bed8d6caea9a9c55b6704d755a89a8c9f0b0c Mon Sep 17 00:00:00 2001
From: borisneubert <>
Date: Sun, 16 Sep 2012 16:31:41 +0000
Subject: [PATCH] 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/fhem@1853 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
FHEM/02_RSS.pm | 56 ++++++---
FHEM/59_Weather.pm | 264 ++++++++++++++++++++++++++++++-------------
docs/commandref.html | 14 ++-
3 files changed, 234 insertions(+), 100 deletions(-)
diff --git a/FHEM/02_RSS.pm b/FHEM/02_RSS.pm
index 334bd2b15..dd92bbcdf 100644
--- a/FHEM/02_RSS.pm
+++ b/FHEM/02_RSS.pm
@@ -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.";
}
diff --git a/FHEM/59_Weather.pm b/FHEM/59_Weather.pm
index 58a001047..a6de4ce44 100755
--- a/FHEM/59_Weather.pm
+++ b/FHEM/59_Weather.pm
@@ -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 "";
- 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 "
";
-
}
#####################################
@@ -357,24 +468,23 @@ WeatherAsHtml($)
return "$d is not a Weather instance
"
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 = "
%s | %s temp %s, hum %s, %s |
%s | %s %s°C %s%% %s |
%s | %s: %s min %s max %s |
%s | %s: %s min %s°C max %s°C |