diff --git a/fhem/FHEM/50_HP1000.pm b/fhem/FHEM/50_HP1000.pm index 298a6e865..6330fedd4 100755 --- a/fhem/FHEM/50_HP1000.pm +++ b/fhem/FHEM/50_HP1000.pm @@ -38,7 +38,7 @@ no if $] >= 5.017011, warnings => 'experimental::smartmatch'; sub HP1000_Define($$); sub HP1000_Undefine($$); - + ######################### sub HP1000_addExtension($$$) { my ( $name, $func, $link ) = @_; @@ -68,7 +68,7 @@ sub HP1000_Initialize($) { $hash->{DefFn} = "HP1000_Define"; $hash->{UndefFn} = "HP1000_Undefine"; - $hash->{AttrList} = $readingFnAttributes; + $hash->{AttrList} = "wu_push:1,0 wu_id wu_password " . $readingFnAttributes; } ################################### @@ -80,12 +80,12 @@ sub HP1000_Define($$) { return "Usage: define HP1000 [ ]" if ( int(@a) < 2 ); - my $name = $a[0]; - $hash->{ID} = $a[2] if (defined($a[2])); - $hash->{PASSWORD} = $a[3] if (defined($a[3])); + my $name = $a[0]; + $hash->{ID} = $a[2] if ( defined( $a[2] ) ); + $hash->{PASSWORD} = $a[3] if ( defined( $a[3] ) ); return "Device already defined: " . $modules{HP1000}{defptr}{NAME} - if (defined($modules{HP1000}{defptr})); + if ( defined( $modules{HP1000}{defptr} ) ); $hash->{fhem}{infix} = "updateweatherstation"; @@ -122,7 +122,7 @@ sub HP1000_CGI() { my ($request) = @_; my $hash; - my $name = ""; + my $name = ""; my $link; my $URI; my $result = ""; @@ -130,11 +130,11 @@ sub HP1000_CGI() { # data received if ( $request =~ /^\/updateweatherstation\.\w{3}\?(.+=.+)/ ) { - $URI = $1; + $URI = $1; # get device name $name = $data{FWEXT}{"/updateweatherstation"}{deviceName} - if (defined($data{FWEXT}{"/updateweatherstation"})); + if ( defined( $data{FWEXT}{"/updateweatherstation"} ) ); # return error if no such device return ( "text/plain; charset=utf-8", @@ -150,9 +150,13 @@ sub HP1000_CGI() { $webArgs->{$p} = $v; } - - return ("text/plain; charset=utf-8", "Insufficient data") - if (!defined($webArgs->{softwaretype}) || !defined($webArgs->{dateutc}) || !defined($webArgs->{ID}) || !defined($webArgs->{PASSWORD}) || !defined($webArgs->{action})) + + return ( "text/plain; charset=utf-8", "Insufficient data" ) + if ( !defined( $webArgs->{softwaretype} ) + || !defined( $webArgs->{dateutc} ) + || !defined( $webArgs->{ID} ) + || !defined( $webArgs->{PASSWORD} ) + || !defined( $webArgs->{action} ) ); } # no data received @@ -162,94 +166,119 @@ sub HP1000_CGI() { $hash = $defs{$name}; - $hash->{SWVERSION} = $webArgs->{softwaretype}; + $hash->{SWVERSION} = $webArgs->{softwaretype}; $hash->{SYSTEMTIME_UTC} = $webArgs->{dateutc}; - if (defined($hash->{ID}) && defined($hash->{PASSWORD}) && ($hash->{ID} ne $webArgs->{ID} || $hash->{PASSWORD} ne $webArgs->{PASSWORD})) { - Log3 $name, 4, "HP1000: received data containing wrong credentials:"; - return ("text/plain; charset=utf-8", "Wrong credentials"); - } else { - Log3 $name, 5, "HP1000: received data:\n" . Dumper($webArgs); - delete $webArgs->{ID}; - delete $webArgs->{PASSWORD}; - delete $webArgs->{dateutc}; - delete $webArgs->{action}; - delete $webArgs->{softwaretype}; + if ( + defined( $hash->{ID} ) + && defined( $hash->{PASSWORD} ) + && ( $hash->{ID} ne $webArgs->{ID} + || $hash->{PASSWORD} ne $webArgs->{PASSWORD} ) + ) + { + Log3 $name, 4, "HP1000: received data containing wrong credentials:"; + return ( "text/plain; charset=utf-8", "Wrong credentials" ); + } + else { + Log3 $name, 5, "HP1000: received data:\n" . Dumper($webArgs); + + HP1000_PushWU( $hash, $webArgs ) + if AttrVal( $name, "wu_push", 0 ) eq "1"; + + delete $webArgs->{ID}; + delete $webArgs->{PASSWORD}; + delete $webArgs->{dateutc}; + delete $webArgs->{action}; + delete $webArgs->{softwaretype}; } readingsBeginUpdate($hash); # write general readings - while ( (my $p, my $v) = each %$webArgs ) { - # ignore those values - next if ($v eq ""); + while ( ( my $p, my $v ) = each %$webArgs ) { - # name translation - $p = "humidityIndoor" if ($p eq "inhumi"); - $p = "temperatureIndoor" if ($p eq "intemp"); - $p = "humidity" if ($p eq "outhumi"); - $p = "temperature" if ($p eq "outtemp"); - $p = "luminosity" if ($p eq "light"); - $p = "pressure" if ($p eq "relbaro"); - $p = "pressureAbs" if ($p eq "absbaro"); - $p = "rain" if ($p eq "rainrate"); - $p = "rainDay" if ($p eq "dailyrain"); - $p = "rainWeek" if ($p eq "weeklyrain"); - $p = "rainMonth" if ($p eq "monthlyrain"); - $p = "rainYear" if ($p eq "yearlyrain"); - $p = "uv" if ($p eq "UV"); - $p = "windChill" if ($p eq "windchill"); - $p = "windDir" if ($p eq "winddir"); - $p = "windGust" if ($p eq "windgust"); - $p = "windSpeed" if ($p eq "windspeed"); + # ignore those values + next if ( $v eq "" ); - readingsBulkUpdate( $hash, $p, $v ); + # name translation + $p = "humidityIndoor" if ( $p eq "inhumi" ); + $p = "temperatureIndoor" if ( $p eq "intemp" ); + $p = "humidity" if ( $p eq "outhumi" ); + $p = "temperature" if ( $p eq "outtemp" ); + $p = "luminosity" if ( $p eq "light" ); + $p = "pressure" if ( $p eq "relbaro" ); + $p = "pressureAbs" if ( $p eq "absbaro" ); + $p = "rain" if ( $p eq "rainrate" ); + $p = "rainDay" if ( $p eq "dailyrain" ); + $p = "rainWeek" if ( $p eq "weeklyrain" ); + $p = "rainMonth" if ( $p eq "monthlyrain" ); + $p = "rainYear" if ( $p eq "yearlyrain" ); + $p = "uv" if ( $p eq "UV" ); + $p = "windChill" if ( $p eq "windchill" ); + $p = "windDir" if ( $p eq "winddir" ); + $p = "windGust" if ( $p eq "windgust" ); + $p = "windSpeed" if ( $p eq "windspeed" ); + + readingsBulkUpdate( $hash, $p, $v ); } # calculated readings # # dewpointIndoor - if (defined($webArgs->{intemp}) && defined($webArgs->{inhumi})) { - my $v = int( dewpoint_dewpoint($webArgs->{intemp}, $webArgs->{inhumi}) + 0.5 ); - readingsBulkUpdate( $hash, "dewpointIndoor", $v ); + if ( defined( $webArgs->{intemp} ) && defined( $webArgs->{inhumi} ) ) { + my $v = int( + dewpoint_dewpoint( $webArgs->{intemp}, $webArgs->{inhumi} ) + 0.5 ); + readingsBulkUpdate( $hash, "dewpointIndoor", $v ); } # humidityAbs - if (defined($webArgs->{outtemp}) && defined($webArgs->{outhumi})) { - my $v = int( dewpoint_absFeuchte($webArgs->{outtemp}, $webArgs->{outhumi}) + 0.5 ); - readingsBulkUpdate( $hash, "humidityAbs", $v ); + if ( defined( $webArgs->{outtemp} ) && defined( $webArgs->{outhumi} ) ) { + my $v = + int( dewpoint_absFeuchte( $webArgs->{outtemp}, $webArgs->{outhumi} ) + + 0.5 ); + readingsBulkUpdate( $hash, "humidityAbs", $v ); } # humidityIndoorAbs - if (defined($webArgs->{intemp}) && defined($webArgs->{inhumi})) { - my $v = int( dewpoint_absFeuchte($webArgs->{intemp}, $webArgs->{inhumi}) + 0.5 ); - readingsBulkUpdate( $hash, "humidityIndoorAbs", $v ); + if ( defined( $webArgs->{intemp} ) && defined( $webArgs->{inhumi} ) ) { + my $v = + int( dewpoint_absFeuchte( $webArgs->{intemp}, $webArgs->{inhumi} ) + + 0.5 ); + readingsBulkUpdate( $hash, "humidityIndoorAbs", $v ); } - + # condition_forecast (based on pressure trendency) - + # day/night - + # isRaining # solarRadiation # soilTemperature # brightness in % ?? # uv_index, uv_risk - if (defined($webArgs->{UV})) { - my $wavelength = $webArgs->{UV}; + if ( defined( $webArgs->{UV} ) ) { + my $wavelength = $webArgs->{UV}; } - $result = "T: ".$webArgs->{outtemp} if (defined($webArgs->{outtemp})); - $result .= " H: ".$webArgs->{outhumi} if (defined($webArgs->{outhumi})); - $result .= " Ti: ".$webArgs->{intemp} if (defined($webArgs->{intemp})); - $result .= " Hi: ".$webArgs->{inhumi} if (defined($webArgs->{inhumi})); - $result .= " W: ".$webArgs->{windspeed} if (defined($webArgs->{windspeed})); - $result .= " R: ".$webArgs->{rainrate} if (defined($webArgs->{rainrate})); - $result .= " WD: ".$webArgs->{winddir} if (defined($webArgs->{winddir})); - $result .= " D: ".$webArgs->{dewpoint} if (defined($webArgs->{dewpoint})); - $result .= " P: ".$webArgs->{relbaro} if (defined($webArgs->{relbaro})); + $result = "T: " . $webArgs->{outtemp} if ( defined( $webArgs->{outtemp} ) ); + $result .= " H: " . $webArgs->{outhumi} + if ( defined( $webArgs->{outhumi} ) ); + $result .= " Ti: " . $webArgs->{intemp} + if ( defined( $webArgs->{intemp} ) ); + $result .= " Hi: " . $webArgs->{inhumi} + if ( defined( $webArgs->{inhumi} ) ); + $result .= " W: " . $webArgs->{windspeed} + if ( defined( $webArgs->{windspeed} ) ); + $result .= " R: " . $webArgs->{rainrate} + if ( defined( $webArgs->{rainrate} ) ); + $result .= " WD: " . $webArgs->{winddir} + if ( defined( $webArgs->{winddir} ) ); + $result .= " D: " . $webArgs->{dewpoint} + if ( defined( $webArgs->{dewpoint} ) ); + $result .= " P: " . $webArgs->{relbaro} + if ( defined( $webArgs->{relbaro} ) ); readingsBulkUpdate( $hash, "state", $result ); readingsEndUpdate( $hash, 1 ); @@ -257,6 +286,159 @@ sub HP1000_CGI() { return ( "text/plain; charset=utf-8", "success" ); } +################################### +sub HP1000_PushWU($$) { + + # + # See: http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol + # + + my ( $hash, $webArgs ) = @_; + my $name = $hash->{NAME}; + my $timeout = AttrVal( $name, "timeout", 7 ); + my $http_noshutdown = AttrVal( $name, "http-noshutdown", "1" ); + my $wu_user = AttrVal( $name, "wu_id", "" ); + my $wu_pass = AttrVal( $name, "wu_password", "" ); + + Log3 $name, 5, "HP1000 $name: called function HP1000_PushWU()"; + + if ( $wu_user eq "" && $wu_pass eq "" ) { + Log3 $name, 4, +"HP1000 $name: missing attributes for Weather Underground transfer: wu_user and wu_password"; + + my $return = "error: missing attributes wu_user and wu_password"; + readingsSingleUpdate( $hash, "wu_state", $return, 1 ) + if ( ReadingsVal( $name, "wu_state", "" ) ne $return ); + return; + } + + $webArgs->{ID} = $wu_user; + $webArgs->{PASSWORD} = $wu_pass; + + my $cmd; + + while ( my ( $key, $value ) = each %{$webArgs} ) { + $value = urlEncode($value) + if ( $key eq "softwaretype" || $key eq "dateutc" ); + + if ( $key eq "windspeed" ) { + $key = "windspeedmph"; + $value = $value / 1.609344; + } + + if ( $key eq "windgust" ) { + $key = "windgustmph"; + $value = $value / 1.609344; + } + + if ( $key eq "inhumi" ) { + $key = "indoorhumidity"; + } + + if ( $key eq "intemp" ) { + $key = "indoortempf"; + $value = $value * 9 / 5 + 32; + } + + if ( $key eq "intempf" ) { + $key = "indoortempf"; + } + + if ( $key eq "outhumi" ) { + $key = "humidity"; + } + + if ( $key eq "outtemp" ) { + $key = "tempf"; + $value = $value * 9 / 5 + 32; + } + + if ( $key eq "outtempf" ) { + $key = "tempf"; + } + + if ( $key eq "rain" ) { + $key = "rainin"; + $value = $value / 25.4; + } + + if ( $key eq "dailyrain" ) { + $key = "dailyrainin"; + $value = $value / 25.4; + } + + if ( $key eq "dewpoint" ) { + $key = "dewptf"; + $value = $value * 9 / 5 + 32; + } + + if ( $key eq "absbaro" ) { + $key = "baromin"; + $value = $value * 100 * 0.000295299830714; + } + + if ( $key eq "light" ) { + $key = "solarradiation"; + $value = $value; + } + + $cmd .= "$key=" . $value . "&"; + } + + Log3 $name, 4, "HP1000 $name: pushing data to WU: " . $cmd; + + HttpUtils_NonblockingGet( + { + url => +"http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php?" + . $cmd, + timeout => $timeout, + noshutdown => $http_noshutdown, + data => undef, + hash => $hash, + callback => \&HP1000_ReturnWU, + } + ); + + return; +} + +################################### +sub HP1000_ReturnWU($$$) { + my ( $param, $err, $data ) = @_; + my $hash = $param->{hash}; + my $name = $hash->{NAME}; + + # device not reachable + if ($err) { + my $return = "error: connection timeout"; + Log3 $name, 4, "HP1000 $name: WU HTTP " . $return; + + readingsSingleUpdate( $hash, "wu_state", $return, 1 ) + if ( ReadingsVal( $name, "wu_state", "" ) ne $return ); + } + + # data received + elsif ($data) { + my $logprio = 5; + my $return = "ok"; + + if ( $data !~ m/^success.*/ ) { + $logprio = 4; + $return = "error"; + $return .= " " . $param->{code} if ( $param->{code} ne "200" ); + $return .= ": $data"; + } + Log3 $name, $logprio, + "HP1000 $name: WU HTTP return: " . $param->{code} . " - $data"; + + readingsSingleUpdate( $hash, "wu_state", $return, 1 ) + if ( ReadingsVal( $name, "wu_state", "" ) ne $return ); + } + + return; +} + 1; =pod @@ -274,7 +456,7 @@ sub HP1000_CGI() {
define <WeatherStation> HP1000 [<ID> <PASSWORD>]

- Provides webhook receiver for weather station HP1000 and WH2600 of Fine Offset Electronics.
+ Provides webhook receiver for weather station HP1000 and WH2600 of Fine Offset Electronics (e.g. also known as Ambient Weather WS-1001-WIFI).
There needs to be a dedicated FHEMWEB instance with attribute webname set to "weatherstation".
No other name will work as it's hardcoded in the HP1000/WH2600 device itself!

@@ -289,9 +471,30 @@ sub HP1000_CGI() { # to send this ID and PASSWORD for data to be accepted
define WeatherStation HP1000 MyHouse SecretPassword

- IMPORTANT: In your HP1000/WH2600 device, make sure you use a DNS name as most revisions cannot handle IP addresses correctly.
+ IMPORTANT: In your HP1000/WH2600 hardware device, make sure you use a DNS name as most revisions cannot handle IP addresses correctly.

+
+ + Attributes +
+
    + +
  • wu_id
    + Weather Underground (Wunderground) station ID +
  • +
    + +
  • wu_password
    + Weather Underground (Wunderground) password +
  • +
    + +
  • wu_push
    + Enable or disable to push data forward to Weather Underground (defaults to 0=no) +

  • +
+
=end html @@ -308,9 +511,9 @@ sub HP1000_CGI() {
define <WeatherStation> HP1000 [<ID> <PASSWORD>]

- Stellt einen Webhook für die HP1000 oder WH2600 Wetterstation von Fine Offset Electronics bereit.
+ Stellt einen Webhook für die HP1000 oder WH2600 Wetterstation von Fine Offset Electronics bereit (z.B. auch bekannt als Ambient Weather WS-1001-WIFI).
Es muss noch eine dedizierte FHEMWEB Instanz angelegt werden, wo das Attribut webname auf "weatherstation" gesetzt wurde.
- Kein anderer Name funktioniert, da dieser hard im HP1000/WH2600 Ger%auml;t hinterlegt ist!
+ Kein anderer Name funktioniert, da dieser hard im HP1000/WH2600 Gerät hinterlegt ist!

Da die URI ebenfalls fest kodiert ist, kann mit einer einzelnen FHEM Installation maximal eine HP1000/WH2600 Station gleichzeitig verwendet werden.

@@ -323,10 +526,30 @@ sub HP1000_CGI() { # diese ID und PASSWORD sendet, damit Daten akzeptiert werden
define WeatherStation HP1000 MyHouse SecretPassword

- WICHTIG: Im HP1000/WH2600 Gerä muss sichergestellt sein, dass ein DNS Name statt einer IP Adresse verwendet wird, da einige Revisionen damit nicht umgehen können.
+ WICHTIG: Im HP1000/WH2600 Gerät selbst muss sichergestellt sein, dass ein DNS Name statt einer IP Adresse verwendet wird, da einige Revisionen damit nicht umgehen können.

+ Attributes +
+
    + +
  • wu_id
    + Weather Underground (Wunderground) Stations ID +
  • +
    + +
  • wu_password
    + Weather Underground (Wunderground) Passwort +
  • +
    + +
  • wu_push
    + Pushen der Daten zu Weather Underground aktivieren oder deaktivieren (Standard ist 0=aus) +

  • +
+
+ =end html_DE =cut