From 10816dd87a2305e6cba780efed127e936caf922f Mon Sep 17 00:00:00 2001 From: markus-m <> Date: Sun, 31 Jan 2016 14:02:40 +0000 Subject: [PATCH] 60_allergy: New module provides allergy forecast data for Germany git-svn-id: https://svn.fhem.de/fhem/trunk@10682 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 1 + fhem/FHEM/60_allergy.pm | 329 ++++++++++++++++++++++++++++++++++++++++ fhem/HISTORY | 2 + fhem/MAINTAINER.txt | 1 + 4 files changed, 333 insertions(+) create mode 100755 fhem/FHEM/60_allergy.pm diff --git a/fhem/CHANGED b/fhem/CHANGED index 204014238..c2ff8e86f 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,6 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - added: 60_allergy: Allergy forecast data for Germany - feature: FB_CALLLIST: new attribute number-cmd to execute a FHEM command when clicking on a external number within the calllist. Can be any valid FHEM command or Perl code. For details see commandref diff --git a/fhem/FHEM/60_allergy.pm b/fhem/FHEM/60_allergy.pm new file mode 100755 index 000000000..d94851ab2 --- /dev/null +++ b/fhem/FHEM/60_allergy.pm @@ -0,0 +1,329 @@ +############################################## +# $Id$$$ +# +# 60_allergy.pm +# +# 2015 Markus Moises < vorname at nachname . de > +# +# This module provides allergy forecast data +# +# +############################################################################## +# +# define allergy +# +############################################################################## + +package main; + +use strict; +use warnings; +use Time::Local; +use Encode; + +use XML::Simple; +use LWP::UserAgent; +use HTTP::Request; + + + +############################################################################## + + +sub allergy_Initialize($) { + my ($hash) = @_; + my $name = $hash->{NAME}; + + $hash->{DefFn} = "allergy_Define"; + $hash->{UndefFn} = "allergy_Undefine"; + $hash->{GetFn} = "allergy_Get"; + $hash->{AttrList} = "disable:0,1 ". + "ignoreList ". + "updateIgnored:1 ". + "updateEmpty:1 ". + "levelsFormat ". + "weekdaysFormat ". + $readingFnAttributes; + + +} + +sub allergy_Define($$$) { + my ($hash, $def) = @_; + my @a = split("[ \t][ \t]*", $def); + my ($found, $dummy); + + return "syntax: define allergy " if(int(@a) != 3 ); + my $name = $hash->{NAME}; + + $hash->{helper}{ZIPCODE} = $a[2]; + $hash->{helper}{INTERVAL} = 10800; + + my $req = eval + { + require XML::Simple; + XML::Simple->import(); + 1; + }; + + if($req) + { + InternalTimer( gettimeofday() + 60, "allergy_GetUpdate", $hash, 0); + if (!defined($attr{$name}{stateFormat})) + { + $attr{$name}{stateFormat} = 'fc1_maximum'; + } + } + else + { + $hash->{STATE} = "XML::Simple is required!"; + $attr{$name}{disable} = "1"; + return undef; + } + + $hash->{STATE} = "Initialized"; + + return undef; +} + +sub allergy_Undefine($$) { + my ($hash, $arg) = @_; + my $name = $hash->{NAME}; + RemoveInternalTimer($hash); + fhem("deletereading $name fc.*", 1); + return undef; +} + + +sub allergy_Get($@) { + my ($hash, @a) = @_; + my $command = $a[1]; + my $parameter = $a[2] if(defined($a[2])); + my $name = $hash->{NAME}; + + + my $usage = "Unknown argument $command, choose one of data:noArg "; + + return $usage if $command eq '?'; + + RemoveInternalTimer($hash); + + if(AttrVal($name, "disable", 0) eq 1) { + $hash->{STATE} = "disabled"; + return "allergy $name is disabled. Aborting..."; + } + + allergy_GetUpdate($hash); + + return undef; +} + + +sub allergy_GetUpdate($) { + my ($hash) = @_; + my $name = $hash->{NAME}; + + if(AttrVal($name, "disable", 0) eq 1) { + $hash->{STATE} = "disabled"; + Log3 ($name, 2, "allergy $name is disabled, data update cancelled."); + return undef; + } + + + + + my $url="http://www.allergie.hexal.de/pollenflug/xml-interface-neu/pollen_de_7tage.php?plz=".$hash->{helper}{ZIPCODE}; + + + HttpUtils_NonblockingGet({ + url => $url, + noshutdown => 1, + hash => $hash, + type => 'allergydata', + callback => \&allergy_Parse, + }); + + + + return undef; + + +} + + +sub allergy_Parse($$$) +{ + my ($param, $err, $data) = @_; + my $hash = $param->{hash}; + my $name = $hash->{NAME}; + + if( $err ) + { + Log3 $name, 1, "$name: URL error: ".$err; + $hash->{STATE} = "error"; + return undef; + } + + Log3 $name, 5, "Received XML data ".$data; + + my $xml = new XML::Simple(); + #my $xmldata = $xml->XMLin($data); + my $xmldata = $xml->XMLin($data,forcearray => [qw( pollenbelastungen pollen )],keyattr => {pollen => 'name'}); + + my @wdays = split(',',AttrVal($hash->{NAME}, "weekdaysFormat", "Sun,Mon,Tue,Wed,Thu,Fri,Sat" )); + my @levels = split(',',AttrVal($hash->{NAME}, "levelsFormat", "-,low,moderate,high,extreme" )); + + readingsBeginUpdate($hash); # Start update readings + + my $city = Encode::encode('UTF-8',$xmldata->{'pollendaten'}->{'ort'}); + readingsBulkUpdate($hash, "city", $city); + Log3 $name, 4, "Received data for postcode ".$xmldata->{'pollendaten'}->{'plz'}; + + my %umlaute = ( '�' => 'Ae', '�' => 'Oe', '�' => 'Ue', '�' => 'ae', '�' => 'oe', '�' => 'ue', '�' => 'ss' ); + my $umlautkeys = join ("|", keys(%umlaute)); + + foreach my $day (@{$xmldata->{'pollendaten'}{'pollenbelastungen'}}) + { + my $daycode = $day->{'tag'}+1; + my @daydata = $day->{'pollen'}; + my $daymax = 0; + my $pollenkey=''; + my $pollenvalue=''; + my $pollenname=''; + my $pollendata=0; + + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time+($day->{'tag'}*86400)); + + readingsBulkUpdate($hash, "fc".$daycode."_day_of_week", $wdays[$wday]); + + foreach my $pollenhash (@daydata) + { + while(($pollenkey, $pollenvalue) = each(%$pollenhash)) + { + # $pollenname = Encode::encode('UTF-8',$pollenkey); + $pollenkey =~ s/($umlautkeys)/$umlaute{$1}/g; + $pollendata = $pollenvalue->{'belastung'}; + + if (( AttrVal($hash->{NAME}, "updateEmpty", 0 ) gt 0 or $pollendata gt 0) and ( AttrVal($hash->{NAME}, "updateIgnored", 0 ) gt 0 or ( index(AttrVal($hash->{NAME}, "ignoreList", ""), $pollenname ) == -1 ))) + { + readingsBulkUpdate($hash, "fc".$daycode."_".$pollenkey, $levels[$pollendata]); + $daymax = $pollendata if($pollendata gt $daymax); + Log3 $name, 4, "Received pollen level for ".$pollenkey.": day".$daycode." level ".$pollendata; + } + else + { + fhem( "deletereading $name fc".$daycode."_".$pollenkey, 1 ); + Log3 $name, 5, "Received pollen level for ".$pollenkey.": day".$daycode." level ".$pollendata." (ignored)"; + } + + } + + + } + readingsBulkUpdate($hash, "fc".$daycode."_maximum", $levels[$daymax]); + + + } + + readingsEndUpdate($hash, 1); + + + $hash->{UPDATED} = FmtDateTime(time()); + + my $nextupdate = gettimeofday()+$hash->{helper}{INTERVAL}; + InternalTimer($nextupdate, "allergy_GetUpdate", $hash, 1); + + return undef; +} + + + + +########################## + +1; + +=pod +=begin html + + +

allergy

+(en | de) +
+
    + This modul provides allergy forecast data for Germany.
    + It requires the Perl module XML::Simple to be installed +

    + + Define +
      + define <name> allergy <zipcode> +
      + Example: define allergydata allergy 12345 +
        +
    • zipcode +
      + German zipcode +

    • +
    + +
    + Get +
      +
    • data +
      + Manually trigger data update +

    • +
    + +
    + Readings +
      +
    • city +
      + Name of the city the forecast is read for +

    • +
    • fcn_total +
      + Daily maximum levels for all allergens that are not being ignored due to ignoreList
      +

    • +
    • fcn_day_of_week +
      + Weekday, can be localized through weekdaysFormat
      +

    • +
    • fcn_allergen +
      + Daily levels for all allergens that are not being ignored due to ignoreList +

    • +
    + + +
    + Attributes +
      +
    • ignoreList +
      + Comma-separated list of allergen names that are to be ignored during updates and for cumulated day levels calculation +

    • +
    • updateEmpty +
      + Also update (and keep) level readings for inactive allergens that are otherwise removed +

    • +
    • updateIgnored +
      + Also update (and keep) level readings for ignored allergens that are otherwise removed +

    • +
    • levelsFormat +
      + Localize levels by adding them comma separated (default: -,low,moderate,high) +

    • +
    • weekdaysFormat +
      + Localize Weekdays by adding them comma separated (default: Sun,Mon,Tue,Wed,Thu,Fr,Sat) +

    • +
    +
+
+=end html + +=cut diff --git a/fhem/HISTORY b/fhem/HISTORY index 36cadbeba..7bf488e0d 100644 --- a/fhem/HISTORY +++ b/fhem/HISTORY @@ -667,3 +667,5 @@ - Wed Dec 23 2015 (risiko) - added new module 98_weekprofile to manage week profiles +- Sun Jan 31 2016 (markus-m) + - added new module 60_allergy to provide allergy forecast data for Germany diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt index b72b55a48..c8ba06866 100644 --- a/fhem/MAINTAINER.txt +++ b/fhem/MAINTAINER.txt @@ -208,6 +208,7 @@ FHEM/59_Twilight.pm dietmar63 http://forum.fhem.de Unterstue FHEM/59_PROPLANTA.pm tupol http://forum.fhem.de Unterstuetzende Dienste (Link als PM an tupol) FHEM/59_WWO.pm baumrasen http://forum.fhem.de Sonstiges FHEM/59_Weather.pm borisneubert http://forum.fhem.de Unterstuetzende Dienste +FHEM/60_allergy.pm markus-m http://forum.fhem.de Unterstuetzende Dienste FHEM/60_EM.pm rudolfkoenig http://forum.fhem.de SlowRF FHEM/61_EMWZ.pm rudolfkoenig http://forum.fhem.de SlowRF FHEM/62_EMEM.pm rudolfkoenig http://forum.fhem.de SlowRF