# $Id$ ################################################################################ # 59_WUup.pm # # Copyright: mahowi # e-mail: mahowi@gmx.net # # Based on 55_weco.pm by betateilchen # # This file is part of fhem. # # Fhem 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. # # Fhem 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. # # You should have received a copy of the GNU General Public License # along with fhem. If not, see . # ################################################################################ package main; use strict; use warnings; use Time::HiRes qw(gettimeofday); use HttpUtils; use UConv; my $version = "0.9.9"; # Declare functions sub WUup_Initialize($); sub WUup_Define($$$); sub WUup_Undef($$); sub WUup_Set($@); sub WUup_Attr(@); sub WUup_stateRequestTimer($); sub WUup_send($); sub WUup_receive($); ################################################################################ # # Main routines # ################################################################################ sub WUup_Initialize($) { my ($hash) = @_; $hash->{DefFn} = "WUup_Define"; $hash->{UndefFn} = "WUup_Undef"; $hash->{SetFn} = "WUup_Set"; $hash->{AttrFn} = "WUup_Attr"; $hash->{AttrList} = "disable:1 " . "disabledForIntervals " . "interval " . "unit_windspeed:km/h,m/s " . "unit_solarradiation:W/m²,lux " . "round " . "wubaromin wudailyrainin wudewptf wuhumidity wurainin wusoilmoisture " . "wusoiltempf wusolarradiation wutempf wuUV wuwinddir wuwinddir_avg2m " . "wuwindgustdir wuwindgustdir_10m wuwindgustmph wuwindgustmph_10m " . "wuwindspdmph_avg2m wuwindspeedmph wuAqPM2.5 wuAqPM10 " . $readingFnAttributes; $hash->{VERSION} = $version; } sub WUup_Define($$$) { my ( $hash, $def ) = @_; my @a = split( "[ \t][ \t]*", $def ); return "syntax: define WUup " if ( int(@a) != 4 ); my $name = $hash->{NAME}; $hash->{VERSION} = $version; $hash->{INTERVAL} = 300; $hash->{helper}{stationid} = $a[2]; $hash->{helper}{password} = $a[3]; $hash->{helper}{softwaretype} = 'FHEM'; $hash->{helper}{url} = "https://weatherstation.wunderground.com/weatherstation/updateweatherstation.php"; $hash->{helper}{url_rf} = "https://rtupdate.wunderground.com/weatherstation/updateweatherstation.php"; readingsSingleUpdate( $hash, "state", "defined", 1 ); $attr{$name}{room} = "Weather" if ( !defined( $attr{$name}{room} ) ); $attr{$name}{unit_windspeed} = "km/h" if ( !defined( $attr{$name}{unit_windspeed} ) ); $attr{$name}{unit_solarradiation} = "lux" if ( !defined( $attr{$name}{unit_solarradiation} ) ); $attr{$name}{round} = 4 if ( !defined( $attr{$name}{round} ) ); RemoveInternalTimer($hash); if ($init_done) { WUup_stateRequestTimer($hash); } else { InternalTimer( gettimeofday(), "WUup_stateRequestTimer", $hash, 0 ); } Log3 $name, 3, "WUup ($name): defined"; return undef; } sub WUup_Undef($$) { my ( $hash, $arg ) = @_; RemoveInternalTimer($hash); return undef; } sub WUup_Set($@) { my ( $hash, $name, $cmd, @args ) = @_; return "\"set $name\" needs at least one argument" unless ( defined($cmd) ); if ( $cmd eq "update" ) { WUup_stateRequestTimer($hash); } else { return "Unknown argument $cmd, choose one of update:noArg"; } } sub WUup_Attr(@) { my ( $cmd, $name, $attrName, $attrVal ) = @_; my $hash = $defs{$name}; if ( $attrName eq "disable" ) { if ( $cmd eq "set" and $attrVal eq "1" ) { readingsSingleUpdate( $hash, "state", "disabled", 1 ); Log3 $name, 3, "WUup ($name) - disabled"; } elsif ( $cmd eq "del" ) { readingsSingleUpdate( $hash, "state", "active", 1 ); Log3 $name, 3, "WUup ($name) - enabled"; } } if ( $attrName eq "disabledForIntervals" ) { if ( $cmd eq "set" ) { readingsSingleUpdate( $hash, "state", "unknown", 1 ); Log3 $name, 3, "WUup ($name) - disabledForIntervals"; } elsif ( $cmd eq "del" ) { readingsSingleUpdate( $hash, "state", "active", 1 ); Log3 $name, 3, "WUup ($name) - enabled"; } } if ( $attrName eq "interval" ) { if ( $cmd eq "set" ) { if ( $attrVal < 3 ) { Log3 $name, 1, "WUup ($name) - interval too small, please use something >= 3 (sec), default is 300 (sec)."; return "interval too small, please use something >= 3 (sec), default is 300 (sec)"; } else { $hash->{INTERVAL} = $attrVal; Log3 $name, 4, "WUup ($name) - set interval to $attrVal"; } } elsif ( $cmd eq "del" ) { $hash->{INTERVAL} = 300; Log3 $name, 4, "WUup ($name) - set interval to default"; } } return undef; } sub WUup_stateRequestTimer($) { my ($hash) = @_; my $name = $hash->{NAME}; if ( !IsDisabled($name) ) { readingsSingleUpdate( $hash, "state", "active", 1 ) if ( ( ReadingsVal( $name, "state", 0 ) eq "defined" or ReadingsVal( $name, "state", 0 ) eq "disabled" or ReadingsVal( $name, "state", 0 ) eq "Unknown" ) ); WUup_send($hash); } else { readingsSingleUpdate( $hash, "state", "disabled", 1 ); } InternalTimer( gettimeofday() + $hash->{INTERVAL}, "WUup_stateRequestTimer", $hash, 1 ); Log3 $name, 5, "Sub WUup_stateRequestTimer ($name) - Request Timer is called"; } sub WUup_send($) { my ($hash) = @_; my $name = $hash->{NAME}; my $version = $hash->{VERSION}; my $url = ""; if ( $hash->{INTERVAL} < 300 ) { $url = $hash->{helper}{url_rf}; } else { $url = $hash->{helper}{url}; } $url .= "?ID=" . $hash->{helper}{stationid}; $url .= "&PASSWORD=" . $hash->{helper}{password}; my $datestring = strftime "%F+%T", gmtime; $datestring =~ s/:/%3A/g; $url .= "&dateutc=" . $datestring; $attr{$name}{unit_windspeed} = "km/h" if ( !defined( $attr{$name}{unit_windspeed} ) ); $attr{$name}{unit_solarradiation} = "lux" if ( !defined( $attr{$name}{unit_solarradiation} ) ); $attr{$name}{round} = 4 if ( !defined( $attr{$name}{round} ) ); my ( $data, $d, $r, $o ); my $a = $attr{$name}; my $rnd = $attr{$name}{round}; while ( my ( $key, $value ) = each(%$a) ) { next if substr( $key, 0, 2 ) ne 'wu'; $key = substr( $key, 2, length($key) - 2 ); ( $d, $r, $o ) = split( ":", $value ); if ( defined($r) ) { $o = ( defined($o) ) ? $o : 0; $value = ReadingsVal( $d, $r, 0 ) + $o; } if ( $key =~ /\w+f$/ ) { $value = UConv::c2f( $value, $rnd ); } elsif ( $key =~ /\w+mph.*/ ) { if ( $attr{$name}{unit_windspeed} eq "m/s" ) { Log3 $name, 5, "WUup ($name) - windspeed unit is m/s"; $value = UConv::kph2mph( ( UConv::mps2kph( $value, $rnd ) ), $rnd ); } else { Log3 $name, 5, "WUup ($name) - windspeed unit is km/h"; $value = UConv::kph2mph( $value, $rnd ); } } elsif ( $key eq "baromin" ) { $value = UConv::hpa2inhg( $value, $rnd ); } elsif ( $key =~ /.*rainin$/ ) { $value = UConv::mm2in( $value, $rnd ); } elsif ( $key eq "solarradiation" ) { if ( $attr{$name}{unit_solarradiation} eq "lux" ) { Log3 $name, 5, "WUup ($name) - solarradiation unit is lux"; $value = ( $value / 126.7 ); } else { Log3 $name, 5, "WUup ($name) - solarradiation unit is W/m²"; } } $data .= "&$key=$value"; } readingsBeginUpdate($hash); if ( defined($data) ) { readingsBulkUpdate( $hash, "data", $data ); Log3 $name, 4, "WUup ($name) - data sent: $data"; $url .= $data; $url .= "&softwaretype=" . $hash->{helper}{softwaretype}; $url .= "&action=updateraw"; if ( $hash->{INTERVAL} < 300 ) { $url .= "&realtime=1&rtfreq=" . $hash->{INTERVAL}; } my $param = { url => $url, timeout => 6, hash => $hash, method => "GET", header => "agent: FHEM-WUup/$version\r\nUser-Agent: FHEM-WUup/$version", callback => \&WUup_receive }; Log3 $name, 5, "WUup ($name) - full URL: $url"; HttpUtils_NonblockingGet($param); # my $response = GetFileFromURL($url); # readingsBulkUpdate( $hash, "response", $response ); # Log3 $name, 4, "WUup ($name) - server response: $response"; } else { CommandDeleteReading( undef, "$name data" ); CommandDeleteReading( undef, "$name response" ); Log3 $name, 3, "WUup ($name) - no data"; readingsBulkUpdate( $hash, "state", "defined" ); } readingsEndUpdate( $hash, 1 ); return; } sub WUup_receive($) { my ( $param, $err, $data ) = @_; my $hash = $param->{hash}; my $name = $hash->{NAME}; if ( $err ne "" ) { Log3 $name, 3, "WUup ($name) - error while requesting " . $param->{url} . " - $err"; readingsSingleUpdate( $hash, "state", "ERROR", undef ); readingsSingleUpdate( $hash, "response", $err, undef ); } elsif ( $data ne "" ) { Log3 $name, 4, "WUup ($name) - server response: $data"; readingsSingleUpdate( $hash, "state", "active", undef ); readingsSingleUpdate( $hash, "response", $data, undef ); } } 1; ################################################################################ # # Documentation # ################################################################################ # # Changelog: # # 2017-01-23 initial release # 2017-02-10 added german docu # 2017-02-22 fixed bug when module cannot get reenabled after disabling # added disabledForIntervals # changed attribute WUInterval to interval # default interval 300 # 2017-02-23 added attribute unit_windspeed # converted units rounded to 4 decimal places # 2017-03-16 implemented non-blocking mode # 2017-08-16 integrated RapidFire mode (thanks to Scooty66) # 2017-10-10 added windspdmph_avg2m, winddir_avg2m, windgustmph_10m, # windgustdir_10m (thanks to Aeroschmelz for reminding me) # timeout raised to 6s, fixed state error (thanks to mumpitzstuff) # 2017-10-16 fixed attributes # 2017-10-19 added set-command "update" # 2018-03-19 solarradiation calculated from lux to W/m² (thanks to dieter114) # 2018-04-10 added attribute round # 2018-04-13 added AqPM2.5 and AqPM10 # 2018-08-15 added attribute unit_solarradiation # ################################################################################ =pod =item helper =item summary sends weather data to Weather Underground =item summary_DE sendet Wetterdaten zu Weather Underground =begin html

WUup

    Define

      define <name> WUup <stationId> <password>

      This module provides connection to www.wunderground.com
      to send data from your own weather station.


    Set-Commands
    • update - send data to Weather Underground


    Get-Commands

      - not implemented -


    Attributes

    • readingFnAttributes
    • interval - Interval (seconds) to send data to www.wunderground.com. Will be adjusted to 300 (which is the default) if set to a value lower than 3.
      If lower than 300, RapidFire mode will be used.
    • disable - disables the module
    • disabledForIntervals
    • unit_windspeed - change the units of your windspeed readings (m/s or km/h)
    • unit_solarradiation - change the units of your solarradiation readings (lux or W/m²)
    • round - round values to this number of decimals for calculation (default 4)
    • wu.... - Attribute name corresponding to parameter name from api. Each of these attributes contains information about weather data to be sent in format sensorName:readingName
      Example: attr WUup wutempf outside:temperature will define the attribute wutempf and
      reading "temperature" from device "outside" will be sent to network as parameter "tempf" (which indicates current temperature)
      Units get converted to angloamerican system automatically (°C -> °F; km/h(m/s) -> mph; mm -> in; hPa -> inHg)

      The following information is supported:
      • winddir - instantaneous wind direction (0-360) [°]
      • windspeedmph - instantaneous wind speed ·[mph]
      • windgustmph - current wind gust, using software specific time period [mph]
      • windgustdir - current wind direction, using software specific time period [°]
      • windspdmph_avg2m - 2 minute average wind speed [mph]
      • winddir_avg2m - 2 minute average wind direction [°]
      • windgustmph_10m - past 10 minutes wind gust [mph]
      • windgustdir_10m - past 10 minutes wind gust direction [°]
      • humidity - outdoor humidity (0-100) [%]
      • dewptf- outdoor dewpoint [F]
      • tempf - outdoor temperature [F]
      • rainin - rain over the past hour -- the accumulated rainfall in the past 60 min [in]
      • dailyrainin - rain so far today in local time [in]
      • baromin - barometric pressure [inHg]
      • soiltempf - soil temperature [F]
      • soilmoisture - soil moisture [%]
      • solarradiation - solar radiation[W/m²]
      • UV - [index]
      • AqPM2.5 - PM2.5 mass [µg/m³]
      • AqPM10 - PM10 mass [µg/m³]


    Readings/Events:

    • data - data string transmitted to www.wunderground.com
    • response - response string received from server


    Notes

    • Find complete api description here
    • Have fun!

=end html =begin html_DE

WUup

    Define

      define <name> WUup <stationId> <password>

      Dieses Modul stellt eine Verbindung zu www.wunderground.com
      her, um Daten einer eigenen Wetterstation zu versenden..


    Set-Befehle
    • update - sende Daten an Weather Underground


    Get-Befehle

      - keine -


    Attribute

    • readingFnAttributes
    • interval - Sendeinterval in Sekunden. Wird auf 300 (Default-Wert) eingestellt, wenn der Wert kleiner als 3 ist.
      Wenn der Wert kleiner als 300 ist, wird der RapidFire Modus verwendet.
    • disable - deaktiviert das Modul
    • disabledForIntervals
    • unit_windspeed - gibt die Einheit der Readings für die Windgeschwindigkeiten an (m/s oder km/h)
    • unit_solarradiation - gibt die Einheit der Readings für die Sonneneinstrahlung an (lux oder W/m²)
    • round - Anzahl der Nachkommastellen zur Berechnung (Standard 4)
    • wu.... - Attributname entsprechend dem Parameternamen aus der API.
      Jedes dieser Attribute enthält Informationen über zu sendende Wetterdaten im Format sensorName:readingName.
      Beispiel: attr WUup wutempf outside:temperature definiert das Attribut wutempf und sendet das Reading "temperature" vom Gerät "outside" als Parameter "tempf" (welches die aktuelle Temperatur angibt).
      Einheiten werden automatisch ins anglo-amerikanische System umgerechnet. (°C -> °F; km/h(m/s) -> mph; mm -> in; hPa -> inHg)

      Unterstützte Angaben
      • winddir - momentane Windrichtung (0-360) [°]
      • windspeedmph - momentane Windgeschwindigkeit [mph]
      • windgustmph - aktuelle Böe, mit Software-spezifischem Zeitraum [mph]
      • windgustdir - aktuelle Böenrichtung, mit Software-spezifischer Zeitraum [°]
      • windspdmph_avg2m - durchschnittliche Windgeschwindigkeit innerhalb 2 Minuten [mph]
      • winddir_avg2m - durchschnittliche Windrichtung innerhalb 2 Minuten [°]
      • windgustmph_10m - Böen der vergangenen 10 Minuten [mph]
      • windgustdir_10m - Richtung der Böen der letzten 10 Minuten [°]
      • humidity - Luftfeuchtigkeit im Freien (0-100) [%]
      • dewptf- Taupunkt im Freien [F]
      • tempf - Außentemperatur [F]
      • rainin - Regen in der vergangenen Stunde [in]
      • dailyrainin - Regenmenge bisher heute [in]
      • baromin - barometrischer Druck [inHg]
      • soiltempf - Bodentemperatur [F]
      • soilmoisture - Bodenfeuchtigkeit [%]
      • solarradiation - Sonneneinstrahlung [W/m²]
      • UV - [Index]
      • AqPM2.5 - Feinstaub PM2,5 [µg/m³]
      • AqPM10 - Feinstaub PM10 [µg/m³]


    Readings/Events:

    • data - Daten, die zu www.wunderground.com gesendet werden
    • response - Antwort, die vom Server empfangen wird


    Notizen

    • Die komplette API-Beschreibung findet sich hier
    • Viel Spaß!

=end html_DE =cut