# $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
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
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