diff --git a/fhem/FHEM/59_OPENWEATHER.pm b/fhem/FHEM/59_OPENWEATHER.pm new file mode 100644 index 000000000..524c9e6a1 --- /dev/null +++ b/fhem/FHEM/59_OPENWEATHER.pm @@ -0,0 +1,595 @@ +############################################################### +# $Id: $ +# +# 59_OPENWEATHER.pm +# +# (c) 2014 Torsten Poitzsch < torsten . poitzsch at gmx . de > +# +# This module reads weather forecast data via the openweather-api of www.wetter.com +# +# Copyright notice +# +# This script is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# The GNU General Public License can be found at +# http://www.gnu.org/copyleft/gpl.html. +# A copy is found in the text file GPL.txt and important notices to the license +# from the author is found in LICENSE.txt distributed with these scripts. +# +# This script is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# This copyright notice MUST APPEAR in all copies of the script! +# +############################################################################## +# +# define OPENWEATHER +# +############################################################################## + +############################################### +# parser for the weather data +package MyOPENWEATHERParser; +use base qw(HTML::Parser); +our %fcReadings = (); +my $curTag = ""; +my $day = -1; +my $time = ""; +# here HTML::text/start/end are overridden + +%knownTags = ( tn => "tempMin" + , tx => "tempMax" + , w => "weatherCode" + , w_txt => "weather" + , ws => "wind" + , wd => "windDir" + , wd_txt => "windDirTxt" + , pc => "presChange" + , p => "valHours" +); + +sub text +{ + my ( $self, $text ) = @_; + + if ($curTag eq "name") + { + $fcReadings{"city"} = $text ; + } + elsif ($curTag eq "post_code") + { + $fcReadings{"postCode"} = $text ; + } + else + { + my $rName = $knownTags{$curTag}; + if (defined $rName && $day >= 0) + { + #Umlaute entfernen + if ($curTag eq "w_txt") {$text =~ s/ö/oe/; $text =~ s/ä/ae/; $text =~ s/ü/ue/; $text =~ s/ß/ss/;} + $fcReadings{"fc".$day."_".$rName.$time} = $text ; + } + } +} + +sub start +{ + my ( $self, $tagname, $attr, $attrseq, $origtext ) = @_; + $curTag = $tagname; + + if ($tagname eq "forecast") + { + $day=-1; + } + if ($tagname eq "date") + { + $day++; + $time = ""; + } + if ($tagname eq "time") + { + $time = substr($attr->{value}, 0, 2); + } +} + +sub end +{ + my ( $self, $tagname, $attr, $attrseq, $origtext ) = @_; + $curTag = ""; + if ($tagname eq "time") + { + $time = ""; + } +} + +####################################################################### +package main; + +use strict; +use warnings; +use Blocking; +use MIME::Base64; +use Digest::MD5 qw(md5_hex); +use LWP::UserAgent; +use HTTP::Request; +use HTML::Parser; + +# Modul Version for remote debugging + my $MODUL = "OPENWEATHER"; + my $modulVersion = '$Id $'; + +sub OPENWEATHER_Log($$$); +sub OPENWEATHER_Start($); +sub OPENWEATHER_Run($); +sub OPENWEATHER_Done($); +sub OPENWEATHER_UpdateAborted($); + +sub ########################################## +OPENWEATHER_Log($$$) +{ + my ( $hash, $loglevel, $text ) = @_; + my $xline = ( caller(0) )[2]; + + my $xsubroutine = ( caller(1) )[3]; + my $sub = ( split( ':', $xsubroutine ) )[2]; + $sub =~ s/OPENWEATHER_//; + + my $instName = ( ref($hash) eq "HASH" ) ? $hash->{NAME} : $hash; + Log3 $hash, $loglevel, "$MODUL $instName: $sub.$xline " . $text; +} + +sub ########################################## +OPENWEATHER_Initialize($) +{ + my ($hash) = @_; + + $hash->{DefFn} = "OPENWEATHER_Define"; + $hash->{UndefFn} = "OPENWEATHER_Undefine"; + + $hash->{SetFn} = "OPENWEATHER_Set"; + $hash->{GetFn} = "OPENWEATHER_Get"; + $hash->{AttrFn} = "OPENWEATHER_Attr"; + $hash->{AttrList} = "disable:0,1 " + .$readingFnAttributes; + +} # end OPENWEATHER_Initialize + + +sub ########################################## +OPENWEATHER_Define($$) +{ + my ($hash, $def) = @_; + my @args = split("[ \t][ \t]*", $def); + + return "Usage: define OPENWEATHER " if(@args <5 || @args >5); + + my $name = $args[0]; + my $interval = 3600; + + $hash->{NAME} = $name; + + $hash->{STATE} = "Initializing" if $interval > 0; + $hash->{STATE} = "Manual mode" if $interval == 0; + $hash->{INTERVAL} = $interval; + $hash->{PROJECT} = $args[2]; + $hash->{CITYCODE} = $args[3]; + $hash->{APIKEY} = $args[4]; + $hash->{CREDIT} = "Powered by wetter.com"; + RemoveInternalTimer($hash); + #Get first data after 13 seconds + InternalTimer(gettimeofday() + 13, "OPENWEATHER_Start", $hash, 0) if $interval > 0; + + $hash->{fhem}{modulVersion} = '$ID $'; + OPENWEATHER_Log $hash, 5, "OPENWEATHER.pm version is " . $hash->{fhem}{modulVersion}; + + return undef; +} #end OPENWEATHER_Define + + +sub ########################################## +OPENWEATHER_Undefine($$) +{ + my ($hash, $args) = @_; + + RemoveInternalTimer($hash); + + BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID})); + + return undef; +} # end OPENWEATHER_Undefine + + +sub ########################################## +OPENWEATHER_Attr($@) +{ + my ($cmd,$name,$aName,$aVal) = @_; + # $cmd can be "del" or "set" + # $name is device name + # aName and aVal are Attribute name and value + if ($cmd eq "set") + { + if ($aName eq "1allowSetParameter") + { + eval { qr/$aVal/ }; + if ($@) + { + OPENWEATHER_Log $name, 3, "Invalid allowSetParameter in attr $name $aName $aVal: $@"; + return "Invalid allowSetParameter $aVal"; + } + } + } + + return undef; +} # OPENWEATHER_Attr ende + + +sub ########################################## +OPENWEATHER_Set($$@) +{ + my ($hash, $name, $cmd, $val) = @_; + my $resultStr = ""; + + if($cmd eq 'update') + { + $hash->{LOCAL} = 1; + OPENWEATHER_Start($hash); + $hash->{LOCAL} = 0; + return undef; + } + my $list = "update:noArg"; + return "Unknown argument $cmd, choose one of $list"; + +} # end OPENWEATHER_Set + + +sub ########################################## +OPENWEATHER_Get($@) +{ + my ($hash, $name, $cmd) = @_; + my $result; + my $message; + + if ($cmd eq "apiResponse") + { + my $time = gettimeofday(); + $result = OPENWEATHER_Run $name; + my @a = split /\|/, $result; + if ($a[1]==0) + { + $message = $a[2]; + } + else + { + $message = decode_base64($a[2]); + } + $time = gettimeofday() - $time; + if ($time > AttrVal($name, "timeOut", 10)) { + $message = sprintf( "Runtime: %.2f s (!!! Increase attribute 'timeOut' !!!)\n_________________\n\n", $time) . $message; + } else { + $message = sprintf( "Runtime: %.2f s\n_________________\n\n", $time) . $message; + } + return $message; + + } + # elsif ($cmd eq "jsonAnalysis") { + # my $time = gettimeofday(); + # $hash->{fhem}{jsonInterpreter} = ""; + # $result = OPENWEATHER_Run $name; + # my @a = split /\|/, $result; + # if ($a[1]==0) { return $a[2]; } + + # $result = OPENWEATHER_Done $result; + # my @a = split /\|/, $result; + # $time = gettimeofday() - $time; + # $message = sprintf( "Runtime: %.2f s\n_________________\n\n", $time); + # $message .= decode_base64($result); #$a[2]); + # return $message; + # } + + my $list = "apiResponse:noArg"; + return "Unknown argument $cmd, choose one of $list"; + +} # end OPENWEATHER_Get + + +# Starts the data capturing and sets the new timer +sub ########################################## +OPENWEATHER_Start($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + + + if(!$hash->{LOCAL} && $hash->{INTERVAL} > 0) { + RemoveInternalTimer($hash); + InternalTimer(gettimeofday()+$hash->{INTERVAL}, "OPENWEATHER_Start", $hash, 1); + return undef if( AttrVal($name, "disable", 0 ) == 1 ); + } + + my $timeOut = AttrVal($name, "timeOut", 10); + $hash->{helper}{RUNNING_PID} = BlockingCall("OPENWEATHER_Run", $name, + "OPENWEATHER_Done", $timeOut, + "OPENWEATHER_UpdateAborted", $hash) + unless(exists($hash->{helper}{RUNNING_PID})); +} + + +sub ########################################## +OPENWEATHER_Run ($) +{ + my ($name) = @_; + my $returnStr; + my $hash = $defs{$name}; + my $projectName = $hash->{PROJECT}; + my $apiKey = $hash->{APIKEY}; + my $cityCode = $hash->{CITYCODE}; + + my $checkSum = md5_hex( $projectName . $apiKey . $cityCode ); + + my $URL = 'http://api.wetter.com/forecast/weather'; + $URL .= '/city/' . $cityCode; + $URL .= '/project/' . $projectName; + $URL .= '/cs/' . $checkSum; + + $hash->{URL} = $URL; + + OPENWEATHER_Log $hash, 5, "Start capturing data from $URL"; + + my $err_log = ""; + my $agent = LWP::UserAgent->new( env_proxy => 1, keep_alive => 1, protocols_allowed => ['http'], timeout => 10 ); + my $request = HTTP::Request->new( GET => $URL ); + my $response = $agent->request($request); + $err_log = "Can't get $URL -- " . $response->status_line + unless $response->is_success; + + if ( $err_log ne "" ) + { + return "$name|0|" . $response->status_line; + } + + OPENWEATHER_Log $hash, 5, length($response->content)." characters captured"; + + my $message = encode_base64($response->content,""); + return "$name|1|$message" ; + +} # end OPENWEATHER_Run + + +sub ########################### +OPENWEATHER_Done($) +{ + my ($string) = @_; + return unless defined $string; + + my ($name, $success, $result) = split("\\|", $string); + my $hash = $defs{$name}; + my $returnStr =""; + + delete($hash->{helper}{RUNNING_PID}); + + readingsBeginUpdate($hash); + + if ( $success == 1 ){ + my $message = decode_base64($result); + + OPENWEATHER_Log $hash, 5, "Start parsing of XML data."; + my $parser = MyOPENWEATHERParser->new; + %MyOPENWEATHERParser::fcReadings = (); + $MyOPENWEATHERParser::day = -1; + $MyOPENWEATHERParser::time = ""; + $parser->parse($message); + + OPENWEATHER_Log $hash, 4, "Captured values: " . keys (%MyOPENWEATHERParser::fcReadings); + + readingsBulkUpdate($hash, "lastConnection", keys (%MyOPENWEATHERParser::fcReadings) . " values captured"); + + while (my ($rName, $rValue) = each(%MyOPENWEATHERParser::fcReadings) ) + { + readingsBulkUpdate( $hash, $rName, $rValue ); + OPENWEATHER_Log $hash, 5, "reading:$rName value:$rValue"; + } + + my $state = "Tmin: ".$MyOPENWEATHERParser::fcReadings{fc0_tempMin}; + $state .= " Tmax: ".$MyOPENWEATHERParser::fcReadings{fc0_tempMax}; + readingsBulkUpdate ($hash, "state", $state); + + } + else + { + readingsBulkUpdate($hash, "lastConnection", $result); + readingsBulkUpdate($hash, "state", $result); + OPENWEATHER_Log $hash, 1, $result; + } + + readingsEndUpdate( $hash, 1 ); + +} # end OPENWEATHER_Done + +sub ############################ +OPENWEATHER_UpdateAborted($) +{ + my ($hash) = @_; + delete($hash->{helper}{RUNNING_PID}); + OPENWEATHER_Log $hash, 1, "Timeout when connecting to wetter.com"; + +} # end OPENWEATHER_UpdateAborted + +1; + +=pod +=begin html + + +

OPENWEATHER

+
+
    + The module extracts weather data via the openweather API of www.wetter.com. +
    + It requires a registration on this website to obtain the necessary parameters. +
    + It requires the perl moduls HTTP::Request, LWP::UserAgent, HTML::Parse and Digest::MD5. +

    + + Define +
      +
      + define <name> OPENWEATHER <project> <cityCode> <apiKey> +
      + Example: define wetter OPENWEATHER beispielprojekt DE0001020 3c551bc20819c19ee88c9ec94280a61d +
        + To obtain the below parameter a requistration of a personal project is necessary on www.wetter.com. +
      +
    • <project> +
      + Name of the users 'openweather' project (create with a user account on the website). +

    • +
    • <cityCode> +
      + Code of the location for which the forecast is requested. Can be obtained from the URL of the weather forecast page of the concerned city. +

    • +
    • <apiKey> +
      + Secret key the can be obtain after the users 'openweather' project is created on the web site. +

    • +
    +
    + + + Set +
      +
      +
    • set <name> update +
      + The weather data are immediately polled from the website. +

    • +
    + + + Get +
      +
      +
    • set <name> apiResponse +
      + Shows the response of the web site. +

    • +
    + + + Attributes + +
    + + + Forecast readings +
      +
      +
    • fc0|1|2_... - forecast values for today|tommorrow|in 2 days
    • +
    • fc0_...06|11|17|23 - forecast values for today at 06|11|17|23 o'clock
    • +
    • fc1_tempMin|Max - minimal|maximal temperature tommorrow in °C
    • +
    • fc0_tempMin06 - minimal temperatur today at 06:00 o'clock in °C
    • +
    • fc0_presChange - atmospheric pressure change today
    • +
    • fc0_valHours06 - validity period of the forecast values in hours
    • +
    • fc0_weather - weather situation today
    • +
    • fc0_wind - wind speed today in km/h
    • +
    • fc0_windDir - wind direction today in °
    • +
    • fc0_windDirTxt - wind direction today in text form
    • +
    • etc.
    • +
    +
    +
+
+ +=end html + +=begin html_DE + + +

OPENWEATHER

+
+
    + + Das Modul extrahiert Wetterdaten über die "openweather"-Schnittstelle von www.wetter.com. + Zuvor ist eine Registrierung auf der Webseite notwendig. +
    + Das Modul benötigt die Perlmodule HTTP::Request, LWP::UserAgent, HTML::Parse und Digest::MD5. +

    + Define +
      +
      + define <name> OPENWEATHER <Projekt> <Ortscode> <apiSchlüssel> +
      + Beispiel: define wetter OPENWEATHER beispielprojekt DE0001020 3c551bc20819c19ee88c9ec94280a61d +
      + Um die unteren Paramter zu erhalten, ist die Registrierung eines eigenen Projektes auf www.wetter.com notwendig. +
    • <Projekt> +
      + Name des benutzerspezifischen 'Openweather'-Projektes (erzeugt über ein Benutzerkonto auf der Website). +

    • +
    • <Ortscode> +
      + Code des Ortes für den die Wettervorhersage benötigt wird. Er kann direkt aus der Adresszeile der jeweiligen Vorhersageseite genommen werden. +

    • +
    • <apiSchlüssel> +
      + Geheimer Schlüssel, den man erhält, nachdem man ein neues 'Openweather'-Projekt auf der Website registriert hat. +

    • +
    + + + Set +
      +
      +
    • set <name> update +
      + Startet sofort ein neues Auslesen der Wetterdaten. +

    • +
    + + + Get +
      +
      +
    • set <name> apiResponse +
      + Zeigt die Rückgabewerte der Website an. +

    • +
    + + + Attribute + +
    + + + Vorhersagewerte +
      +
      +
    • fc0|1|2_... - Vorhersagewerte für heute|morgen|übermorgen
    • +
    • fc0_...06|11|17|23 - Vorhersagewerte für heute um 06|11|17|23 Uhr
    • +
    • fc0_tempMin|Max - Mindest|Maximaltemperatur heute in °C
    • +
    • fc0_tempMin06 - Mindesttemperatur heute um 06:00 Uhr in °C
    • +
    • fc0_presChange - heutige Änderung des Luftdruckes
    • +
    • fc0_valHours06 - Gültigkeitszeitraum der Prognose von heute 6:00 Uhr in Stunden
    • +
    • fc0_weather - Wetterzustand heute
    • +
    • fc0_wind - Windgeschwindigkeit heute in km/h
    • +
    • fc0_windDir - Windrichtung heute in °
    • +
    • fc0_windDirTxt - Windrichtung heute in Textform
    • +
    • etc.
    • +
    +

    +
+
+ +=end html_DE +=cut \ No newline at end of file diff --git a/fhem/FHEM/59_PROPLANTA.pm b/fhem/FHEM/59_PROPLANTA.pm index cf2c30fc3..e96cbdfde 100644 --- a/fhem/FHEM/59_PROPLANTA.pm +++ b/fhem/FHEM/59_PROPLANTA.pm @@ -64,8 +64,8 @@ my $curReadingType = 0; # 1 = Tag-ID, 2 = readingName, 3 = Tag-Type (see above) my @knownIDs = ( - ["TMAX", "tempMaxC", 2] - ,["TMIN", "tempMinC", 2] + ["TMAX", "tempMax", 2] + ,["TMIN", "tempMin", 2] ,["NW", "chOfRainDay", 2] ,["NW_Nacht", "chOfRainNight", 2] ,["BF", "frost", 4] @@ -78,14 +78,14 @@ my $curReadingType = 0; ,["WETTER_ID_TAGSUEBER", "weatherDay", 7] ,["WETTER_ID_ABENDS", "weatherEvening", 7] ,["WETTER_ID_NACHT", "weatherNight", 7] - ,["T_0", "temp00C", 2] - ,["T_3", "temp03C", 2] - ,["T_6", "temp06C", 2] - ,["T_9", "temp09C", 2] - ,["T_12", "temp12C", 2] - ,["T_15", "temp15C", 2] - ,["T_18", "temp18C", 2] - ,["T_21", "temp21C", 2] + ,["T_0", "temp00", 2] + ,["T_3", "temp03", 2] + ,["T_6", "temp06", 2] + ,["T_9", "temp09", 2] + ,["T_12", "temp12", 2] + ,["T_15", "temp15", 2] + ,["T_18", "temp18", 2] + ,["T_21", "temp21", 2] ,["NW_0", "chOfRain00", 2] ,["NW_3", "chOfRain03", 2] ,["NW_6", "chOfRain06", 2] @@ -304,6 +304,7 @@ sub start sub end { + my ( $self, $tagname, $attr, $attrseq, $origtext ) = @_; $curTag = ""; if ( $tagname eq "tr" ) @@ -588,7 +589,7 @@ sub PROPLANTA_Done($) if (keys %values > 0) { # Achtung! Um Mitternacht fehlen die aktuellen Werte - readingsBulkUpdate($hash, "state", "Tmin: " . $values{fc0_tempMinC} . " Tmax: " . $values{fc0_tempMaxC} . " T: " . $values{temperature} . " H: " . $values{humidity} . " W: " . $values{wind} . " P: " . $values{pressure} ); + readingsBulkUpdate($hash, "state", "Tmin: " . $values{fc0_tempMin} . " Tmax: " . $values{fc0_tempMax} . " T: " . $values{temperature} . " H: " . $values{humidity} . " W: " . $values{wind} . " P: " . $values{pressure} ); readingsBulkUpdate( $hash, "lastConnection", keys( %values )." values captured" ); } else @@ -661,7 +662,7 @@ PROPLANTA_Html($)
    The module extracts weather data from www.proplanta.de.
    - It requires the perl moduls HTTP::Request and LWP::UserAgent. + It requires the perl moduls HTTP::Request, LWP::UserAgent and HTML::Parse.

    Define @@ -721,6 +722,7 @@ PROPLANTA_Html($)

    • fc0|1|2|3_... - forecast values for today|tommorrow|in 2|3 days
    • +
    • fc0_...06|11|17|23 - forecast values for today at 00|03|06|09|12|15|18|21 o'clock
    • fc0_chOfRainDay|Night - chance of rain today by day|night in %
    • fc0_chOfRain15 - chance of rain today at 15:00 in %
    • fc0_cloud15 - cloud coverage today at 15:00 in %
    • @@ -729,10 +731,10 @@ PROPLANTA_Html($)
    • fc0_frost - ground frost today (0=no, 1=yes)
    • fc0_moonRise|Set - moon rise|set today
    • fc0_rad - global radiation today
    • -
    • fc0_rain15 - amount of rainfall today at 15:00 in mm
    • +
    • fc0_rain15 - amount of rainfall today at 15:00 o'clock in mm
    • fc0_sun - relative sun shine duration today in % (between sun rise and set)
    • -
    • fc0_tempMin|MaxC - minimal|maximal temperature today in °C
    • -
    • fc0_temp15C - temperatur today at 15:00 in °C
    • +
    • fc0_tempMin|Max - minimal|maximal temperature today in °C
    • +
    • fc0_temp15 - temperatur today at 15:00 o'clock in °C
    • fc0_uv - UV-Index today
    • fc0_weatherMorning|Day|Evening|Night - weather situation today morning|during day|in the evening|during night
    • fc0_weatherDayIcon - icon of weather situation today by day
    • @@ -753,7 +755,7 @@ PROPLANTA_Html($) Das Modul extrahiert Wetterdaten von der website www.proplanta.de.
      - Es benötigt die Perlmodule HTTP::Request und LWP::UserAgent. + Es benötigt die Perlmodule HTTP::Request, LWP::UserAgent und HTML::Parse.

      Define
        @@ -812,6 +814,7 @@ PROPLANTA_Html($)

        • fc0|1|2|3_... - Vorhersagewerte für heute|morgen|übermorgen|in 3 Tagen
        • +
        • fc0_...06|11|17|23 - Vorhersagewerte für heute um 00|03|06|09|12|15|18|21 Uhr
        • fc0_chOfRainDay|Night - heutiges Niederschlagsrisiko tagsüber|nachts in %
        • fc1_chOfRain15 - morgiges Niederschlagsrisiko um 15:00 Uhr in %
        • fc2_cloud15 - Wolkenbedeckungsgrad übermorgen um 15:00 Uhr in %
        • @@ -822,8 +825,8 @@ PROPLANTA_Html($)
        • fc0_rad - Globalstrahlung heute
        • fc0_rain15 - Niederschlagsmenge heute um 15:00 Uhr in mm
        • fc0_sun - relative Sonnenscheindauer heute in % (zwischen Sonnenauf- und -untergang)
        • -
        • fc0_tempMin|MaxC - Minimal|Maximaltemperatur heute in °C
        • -
        • fc0_temp15C - Temperatur heute um 15:00 Uhr in °C
        • +
        • fc0_tempMin|Max - Minimal|Maximaltemperatur heute in °C
        • +
        • fc0_temp15 - Temperatur heute um 15:00 Uhr in °C
        • fc0_uv - UV-Index heute
        • fc0_weatherMorning|Day|Evening|Night - Wetterzustand heute morgen|tagsüber|abends|nachts
        • fc0_weatherDayIcon - Icon Wetterzustand heute tagsüber