# $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 FHEM::WUup; ## no critic ( RequireFilenameMatchesPackage )
use strict;
use warnings;
use 5.010;
use Time::HiRes qw(gettimeofday);
use POSIX qw(strftime);
use UConv;
use FHEM::Meta;
use GPUtils qw(GP_Import GP_Export);
## Import der FHEM Funktionen
#-- Run before package compilation
BEGIN {
# Import from main context
GP_Import(
qw( attr
AttrVal
CommandDeleteReading
defs
HttpUtils_NonblockingGet
init_done
InternalTimer
IsDisabled
Log3
readingFnAttributes
readingsBeginUpdate
readingsBulkUpdate
readingsEndUpdate
readingsSingleUpdate
ReadingsVal
RemoveInternalTimer )
);
}
#-- Export to main context with different name
GP_Export(qw( Initialize ));
################################################################################
#
# Main routines
#
################################################################################
sub Initialize {
my ($hash) = @_;
$hash->{DefFn} = \&Define;
$hash->{UndefFn} = \&Undef;
$hash->{SetFn} = \&Set;
$hash->{AttrFn} = \&Attr;
$hash->{AttrList} =
'disable:1,0 '
. '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;
return FHEM::Meta::InitMod( __FILE__, $hash );
}
sub Define {
my $hash = shift;
my $def = shift;
return $@ unless ( FHEM::Meta::SetInternals($hash) );
## no critic ( ProhibitComplexVersion )
use version 0.77; our $VERSION = version->new( FHEM::Meta::Get( $hash, 'version' ) )->normal;
## use critic
my @param = split( "[ \t][ \t]*", $def );
return q{syntax: define WUup }
if ( int(@param) != 4 );
my $name = $hash->{NAME};
$hash->{VERSION} = $VERSION;
$hash->{INTERVAL} = 300;
$hash->{helper}{stationid} = $param[2];
$hash->{helper}{password} = $param[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 );
RemoveInternalTimer($hash);
$init_done
? &stateRequestTimer($hash)
: InternalTimer( gettimeofday(), \&stateRequestTimer, $hash, 0 );
Log3( $name, 3, qq{WUup ($name): defined} );
return;
}
sub Undef {
my $hash = shift;
RemoveInternalTimer($hash);
return;
}
sub Set {
my $hash = shift;
my $name = shift;
my $cmd = shift // return qq{set $name needs at least one argument};
return &stateRequestTimer($hash) if ( $cmd eq 'update' );
return qq{Unknown argument $cmd, choose one of update:noArg};
}
sub Attr {
my $cmd = shift;
my $name = shift;
my $attrName = shift;
my $attrVal = shift;
my $hash = $defs{$name};
if ( $attrName eq 'disable' ) {
if ( $cmd eq 'set' and $attrVal == 1 ) {
readingsSingleUpdate( $hash, 'state', 'disabled', 1 );
Log3( $name, 3, qq{WUup ($name) - disabled} );
}
elsif ( $cmd eq 'del' ) {
readingsSingleUpdate( $hash, 'state', 'active', 1 );
Log3( $name, 3, qq{WUup ($name) - enabled} );
}
}
if ( $attrName eq 'disabledForIntervals' ) {
if ( $cmd eq 'set' ) {
readingsSingleUpdate( $hash, 'state', 'unknown', 1 );
Log3( $name, 3, qq{WUup ($name) - disabledForIntervals} );
}
elsif ( $cmd eq 'del' ) {
readingsSingleUpdate( $hash, 'state', 'active', 1 );
Log3( $name, 3, qq{WUup ($name) - enabled} );
}
}
if ( $attrName eq 'interval' ) {
if ( $cmd eq 'set' ) {
if ( $attrVal < 3 ) {
Log3( $name, 1,
qq{WUup ($name) - interval too small, please use something >= 3 (sec), default is 300 (sec).}
);
return
qq{interval too small, please use something >= 3 (sec), default is 300 (sec)};
}
else {
$hash->{INTERVAL} = $attrVal;
Log3( $name, 4, qq{WUup ($name) - set interval to $attrVal} );
}
}
elsif ( $cmd eq 'del' ) {
$hash->{INTERVAL} = 300;
Log3( $name, 4, qq{WUup ($name) - set interval to default} );
}
}
return;
}
sub 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'
)
);
sendtowu($hash);
}
else {
readingsSingleUpdate( $hash, 'state', 'disabled', 1 );
}
InternalTimer( gettimeofday() + $hash->{INTERVAL},
\&stateRequestTimer, $hash, 1 );
Log3( $name, 5,
qq{Sub stateRequestTimer ($name) - Request Timer is called} );
return;
}
sub sendtowu {
my ($hash) = @_;
my $name = $hash->{NAME};
my $ver = $hash->{VERSION};
my $url = $hash->{INTERVAL} < 300
? $hash->{helper}{url_rf}
: $hash->{helper}{url};
$url .= "?ID=$hash->{helper}{stationid}";
$url .= "&PASSWORD=$hash->{helper}{password}";
my $datestring = strftime "%F+%T", gmtime;
$datestring =~ s{:}{%3A}gxms;
$url .= "&dateutc=$datestring";
my ( $data, $d, $r, $o );
my $a = $attr{$name};
my $unit_windspeed = AttrVal( $name, 'unit_windspeed', 'km/h' );
my $unit_solarradiation = AttrVal( $name, 'unit_solarradiation', 'lux' );
my $rnd = AttrVal( $name, 'round', 4 );
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 //= 0;
$value = ReadingsVal( $d, $r, 0 ) + $o;
}
my $mph_metric =
$key =~ m{\w+mph [^\n]*}xms && $unit_windspeed eq 'm/s';
my $lux_radiation =
$key eq 'solarradiation' && $unit_solarradiation eq 'lux';
$value = $key =~ m{\w+f \z}xms ? UConv::c2f( $value, $rnd )
: $key =~ m{\w+mph [^\n]*}xms ? UConv::kph2mph( $value, $rnd )
: $key eq 'baromin' ? UConv::hpa2inhg( $value, $rnd )
: $key =~ m{rainin \z}xms ? UConv::mm2in( $value, $rnd )
: $mph_metric ? UConv::kph2mph( ( UConv::mps2kph( $value, $rnd ) ), $rnd )
: $lux_radiation ? UConv::lux2wpsm( $value, $rnd )
: $value;
$data .= "&$key=$value";
}
readingsBeginUpdate($hash);
if ( defined($data) ) {
readingsBulkUpdate( $hash, 'data', $data );
Log3( $name, 4, qq{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/$ver\r\nUser-Agent: FHEM-WUup/$ver",
callback => \&receive
};
Log3( $name, 5, qq{WUup ($name) - full URL: $url} );
HttpUtils_NonblockingGet($param);
}
else {
CommandDeleteReading( undef, "$name data" );
CommandDeleteReading( undef, "$name response" );
Log3( $name, 3, qq{WUup ($name) - no data} );
readingsBulkUpdate( $hash, 'state', 'defined' );
}
readingsEndUpdate( $hash, 1 );
return;
}
sub receive {
my $param = shift;
my $err = shift;
my $data = shift;
my $hash = $param->{hash};
my $name = $hash->{NAME};
if ( $err ne q{} ) {
Log3( $name, 3,
qq{WUup ($name) - error while requesting $param->{url} - $err} );
readingsSingleUpdate( $hash, 'state', 'ERROR', undef );
readingsSingleUpdate( $hash, 'response', $err, undef );
}
elsif ( $data ne q{} ) {
Log3( $name, 4, qq{WUup ($name) - server response: $data} );
readingsSingleUpdate( $hash, 'state', 'active', undef );
readingsSingleUpdate( $hash, 'response', $data, undef );
}
return;
}
1;
################################################################################
#
# Documentation
#
################################################################################
=pod
=encoding utf8
=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
=for :application/json;q=META.json 59_WUup.pm
{
"abstract": "sends weather data to Weather Underground",
"description": "This module provides connection to Weather Underground to send data from your own weather station.",
"x_lang": {
"de": {
"abstract": "sendet Wetterdaten zu Weather Underground",
"description": "Dieses Modul stellt eine Verbindung zu Weather Underground her, um Daten einer eigenen Wetterstation zu versenden"
}
},
"license": [
"gpl_2"
],
"version": "v0.10.1",
"release_status": "stable",
"author": [
"Manfred Winter "
],
"x_fhem_maintainer": [
"mahowi"
],
"x_fhem_maintainer_github": [
"mahowi"
],
"keywords": [
"fhem-mod",
"wunderground",
"pws",
"weather"
],
"prereqs": {
"runtime": {
"requires": {
"FHEM": 0,
"FHEM::Meta": 0,
"UConv": 0,
"POSIX": 0,
"Time::HiRes": 0,
"perl": 5.010
},
"recommends": {
},
"suggests": {
}
}
},
"resources": {
"x_wiki" : {
"title" : "Wetter und Wettervorhersagen - Eigene Wetterdaten hochladen",
"web" : "https://wiki.fhem.de/wiki/Wetter_und_Wettervorhersagen#Eigene_Wetterdaten_hochladen"
},
"repository": {
"type": "git",
"url": "https://github.com/fhem/WUup.git",
"web": "https://github.com/mahowi/WUup/blob/master/FHEM/59_WUup.pm",
"x_branch": "master",
"x_filepath": "FHEM/",
"x_raw": "https://raw.githubusercontent.com/mahowi/WUup/master/FHEM/59_WUup.pm"
}
},
"x_support_status": "supported"
}
=end :application/json;q=META.json
=cut