diff --git a/fhem/CHANGED b/fhem/CHANGED
index 74aa5c9a3..955f5bcf3 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,6 @@
# Add changes at the top of the list. Keep it in ASCII
- SVN
+ - feature: new module 98_openweathermap.pm added (betateilchen)
- feature: WeatherAsHtmlH() added to 59_Weather.pm (Boris)
- feature: new module I2C_BMP180 for reading I2C digital pressure sensor BMP180
or BMP085 connected to Raspberry Pi (Dirk)
diff --git a/fhem/FHEM/98_openweathermap.pm b/fhem/FHEM/98_openweathermap.pm
new file mode 100644
index 000000000..b14e76dbe
--- /dev/null
+++ b/fhem/FHEM/98_openweathermap.pm
@@ -0,0 +1,591 @@
+# $Id: $
+##############################################################################
+#
+# 98_openweathermap.pm
+# An FHEM Perl module connecting to www.openweathermap.org (owo)
+# providing the following tasks:
+#
+# 1. send weather data from your own weather station to owo network
+#
+# 2. set a wheater station as datasource inside your fhem installation
+#
+# 3. retrieve wheather date via owo APII from any weather station
+# inside owo network
+#
+# All tasks can be accessed single or in any desired combination.
+# Copyright: betateilchen ®
+# e-mail : fhem.development@betateilchen.de
+#
+# 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 .
+#
+##############################################################################
+# Changelog:
+
+package main;
+
+use strict;
+use warnings;
+use POSIX;
+use HttpUtils;
+use JSON qw/decode_json/;
+use Try::Tiny;
+use feature qw/say switch/;
+
+sub OWO_Set($@);
+sub OWO_Get($@);
+sub OWO_Attr(@);
+sub OWO_Define($$);
+sub OWO_GetStatus($;$);
+sub OWO_Undefine($$);
+
+sub OWO_abs2rel($$$);
+sub OWO_isday($$);
+
+###################################
+sub
+openweathermap_Initialize($)
+{
+ my ($hash) = @_;
+ $hash->{SetFn} = "OWO_Set";
+ $hash->{GetFn} = "OWO_Get";
+ $hash->{DefFn} = "OWO_Define";
+ $hash->{UndefFn} = "OWO_Undefine";
+ $hash->{AttrFn} = "OWO_Attr";
+
+ $hash->{AttrList} = "do_not_notify:0,1 loglevel:0,1,2,3,4,5 ".
+ "owoApiKey owoDebug:0,1 owoGetUrl owoInterval ".
+ "owoStation owoUser owoRaw:0,1 owoTimestamp:0,1 ".
+ "owoSrc00 owoSrc01 owoSrc02 owoSrc03 owoSrc04 ".
+ "owoSrc05 owoSrc06 owoSrc07 owoSrc08 owoSrc09 ".
+ "owoSrc10 owoSrc11 owoSrc12 owoSrc13 owoSrc14 ".
+ "owoSrc15 owoSrc16 owoSrc17 owoSrc18 owoSrc19 ".
+ $readingFnAttributes;
+}
+
+###################################
+
+sub
+OWO_Set($@){
+ my ($hash, @a) = @_;
+ my $name = $hash->{NAME};
+ my $usage = "Unknown argument, choose one of stationById stationByGeo stationByName";
+ my $response;
+
+ return "No Argument given" if(!defined($a[1]));
+
+ my $urlString = AttrVal($name, "owoGetUrl", undef);
+ return "Please set attribute owoGetUrl!" if(!defined($urlString));
+
+ my $cmd = $a[1];
+
+ given($cmd){
+ when("?") { return $usage; }
+
+ when("stationByName"){
+ $urlString = $urlString."?q=";
+ my $count;
+ my $element = @a;
+ for ($count = 2; $count < $element; $count++) {
+ $urlString = $urlString."%20".$a[$count];
+ }
+ }
+
+ when("stationById"){
+ $urlString = $urlString."?id=".$a[2];
+ }
+
+ when("stationByGeo"){
+ $a[2] = AttrVal("global", "latitude", 0) unless(defined($a[2]));
+ $a[3] = AttrVal("global", "longitude", 0) unless(defined($a[3]));
+ $urlString = $urlString."?lat=$a[2]&lon=$a[3]";
+ }
+
+ default: { return $usage; }
+ }
+
+ UpdateReadings($hash, $urlString, "c_");
+
+
+ return;
+}
+
+sub
+OWO_Get($@){
+ my ($hash, @a) = @_;
+ my $name = $hash->{NAME};
+ my $usage = "Unknown argument, choose one of stationById stationByGeo stationByName";
+ my $response;
+
+ return "No Argument given" if(!defined($a[1]));
+
+ my $urlString = AttrVal($name, "owoGetUrl", undef);
+ return "Please set attribute owoGetUrl!" if(!defined($urlString));
+
+ my $cmd = $a[1];
+
+ given($cmd){
+ when("?") { return $usage; }
+
+ when("stationByName"){
+ $urlString = $urlString."?q=";
+ my $count;
+ my $element = @a;
+ for ($count = 2; $count < $element; $count++) {
+ $urlString = $urlString."%20".$a[$count];
+ }
+ }
+
+ when("stationById"){
+ $urlString = $urlString."?id=".$a[2];
+ }
+
+ when("stationByGeo"){
+ $a[2] = AttrVal("global", "latitude", 0) unless(defined($a[2]));
+ $a[3] = AttrVal("global", "longitude", 0) unless(defined($a[3]));
+ $urlString = $urlString."?lat=$a[2]&lon=$a[3]";
+ }
+
+ default: { return $usage; }
+ }
+
+ UpdateReadings($hash, $urlString, "g_");
+
+ return;
+
+# return $response;
+}
+
+sub
+OWO_Attr(@){
+ my @a = @_;
+ my $hash = $defs{$a[1]};
+ my (undef, $name, $attrName, $attrValue) = @a;
+
+ given($attrName){
+
+ when("owoInterval"){
+ if($attrValue ne ""){
+ $attrValue = 600 if($attrValue < 600);
+ $hash->{helper}{INTERVAL} = $attrValue;
+ } else {
+ $hash->{helper}{INTERVAL} = 1800;
+ }
+ $attr{$name}{$attrName} = $attrValue;
+ RemoveInternalTimer($hash);
+ InternalTimer(gettimeofday()+$hash->{helper}{INTERVAL}, "OWO_GetStatus", $hash, 0);
+ break;
+ }
+
+ default {
+ $attr{$name}{$attrName} = $attrValue;
+ }
+ }
+ return "";
+}
+
+sub
+OWO_GetStatus($;$){
+ my ($hash, $local) = @_;
+ my $name = $hash->{NAME};
+ my $loglevel = AttrVal($name, "loglevel", 3);
+ $local = 0 unless(defined($local));
+
+ $attr{$name}{"owoInterval"} = 600 if(AttrVal($name,"owoInterval",0) < 600);
+
+##### start of send job (own weather data)
+#
+# do we have anything to send from our own station?
+#
+
+ my ($user, $pass) = split(":", AttrVal($name, "owoUser",""));
+ my $station = AttrVal($name, "owoStation", undef);
+
+ if(defined($user) && defined($station)){
+ Log $loglevel, "openweather $name started: SendData";
+ my $lat = AttrVal("global", "latitude", "?");
+ my $lon = AttrVal("global", "longitude", "?");
+ my $alt = AttrVal("global", "altitude", "?");
+
+ my $urlString = "http://$user:$pass\@openweathermap.org/data/post";
+ my $dataString = "name=$station&lat=$lat&long=$lon&alt=$alt";
+
+ my ($count, $paraName, $paraVal, $p, $s, $v, $o);
+ for ($count = 0; $count < 20; $count++) {
+ $paraName = "owoSrc".sprintf("%02d",$count);
+ $paraVal = AttrVal($name, $paraName, undef);
+ if(defined($paraVal)){
+ ($p, $s, $v, $o) = split(":", AttrVal($name, $paraName, ""));
+ $v = ReadingsVal($s, $v, "?") + $o;
+ $dataString = $dataString."&$p=$v";
+ Log $loglevel, "openweather $name reading: $paraName $p $s $v";
+ readingsSingleUpdate($hash, "my_".$p, $v, 1);
+ }
+ }
+
+ $dataString .= "&APPID=".AttrVal($name, "owoApiKey", "");
+
+ my $sendString = $urlString."?".$dataString;
+ if(AttrVal($name, "owoDebug",1) == 0){
+ GetFileFromURL($sendString);
+ Log $loglevel, "openweather $name sending: $dataString";
+ } else {
+ Log $loglevel, "openweather $name debug: $dataString";
+ }
+
+ readingsBeginUpdate($hash);
+ readingsBulkUpdate($hash, "state","active");
+ if(AttrVal($name, "owoTimestamp", 0) == 1){
+ readingsBulkUpdate($hash, "my_lastSent", time);
+ } else {
+ readingsBulkUpdate($hash, "my_lastSent", localtime(time));
+ }
+ readingsEndUpdate($hash, 1);
+ }
+
+##### end of send job
+
+##### start of update job (set station)
+#
+# Do we already have a stationId set?
+# If yes => update this station
+#
+ my $cId = ReadingsVal($name,"c_stationId", undef);
+ if(defined($cId)){
+ my $cName = ReadingsVal($name,"stationName", "");
+ Log $loglevel, "openweather $name retrievingStationData Id: $cId Name: $cName";
+ fhem("set $name stationById $cId");# if($cId ne "");
+ }
+
+##### end of update job
+
+ InternalTimer(gettimeofday()+$hash->{helper}{INTERVAL}, "OWO_GetStatus", $hash, 0) unless($local == 1);
+ return;
+}
+
+sub
+OWO_Define($$){
+ my ($hash, $def) = @_;
+ my @a = split("[ \t][ \t]*", $def);
+ my $name = $hash->{NAME};
+
+ $hash->{helper}{INTERVAL} = 1800;
+ $hash->{helper}{AVAILABLE} = 1;
+
+ $attr{$name}{"owoDebug"} = 1;
+ $attr{$name}{"owoInterval"} = 1800;
+ $attr{$name}{"owoGetUrl"} = "http://api.openweathermap.org/data/2.5/weather";
+
+ readingsBeginUpdate($hash);
+ readingsBulkUpdate($hash, "state","defined");
+ readingsEndUpdate($hash, 1);
+
+ InternalTimer(gettimeofday()+$hash->{helper}{INTERVAL}, "OWO_GetStatus", $hash, 0);
+ Log 3, "openweather: $name created";
+
+ return;
+}
+
+sub
+OWO_Undefine($$){
+ my($hash, $name) = @_;
+ RemoveInternalTimer($hash);
+ return undef;
+}
+
+sub
+UpdateReadings($$$){
+ my ($hash, $url, $prefix) = @_;
+ my $name = $hash->{NAME};
+ my $loglevel = AttrVal($name, "loglevel", 3);
+ my ($jsonWeather, $response);
+
+ $url .= "&APPID=".AttrVal($name, "owoApiKey", "");
+ $response = GetFileFromURL("$url");
+
+ if(AttrVal($name, "owoDebug", 1) == 1){
+ Log $loglevel, "openweather $name response:\n$response";
+ }
+
+ my $json = JSON->new->allow_nonref;
+ try {
+ $jsonWeather = $json->decode($response);
+ } catch {
+ Log $loglevel, "openweather $name error: JSPON decode";
+ return;
+ };
+
+ readingsBeginUpdate($hash);
+ if(AttrVal($name, "owoRaw", 0) == 1){
+ readingsBulkUpdate($hash, $prefix."rawData", $response);
+ } else {
+ readingsBulkUpdate($hash, $prefix."rawData", "not requested");
+ }
+ if(AttrVal($name, "owoTimestamp", 0) == 1){
+ readingsBulkUpdate($hash, $prefix."lastWx", $jsonWeather->{dt});
+ readingsBulkUpdate($hash, $prefix."sunrise", $jsonWeather->{sys}{sunrise});
+ readingsBulkUpdate($hash, $prefix."sunset", $jsonWeather->{sys}{sunset});
+ } else {
+ readingsBulkUpdate($hash, $prefix."lastWx", localtime($jsonWeather->{dt}));
+ readingsBulkUpdate($hash, $prefix."sunrise", localtime($jsonWeather->{sys}{sunrise}));
+ readingsBulkUpdate($hash, $prefix."sunset", localtime($jsonWeather->{sys}{sunset}));
+ }
+ readingsBulkUpdate($hash, $prefix."stationId", $jsonWeather->{id});
+ readingsBulkUpdate($hash, $prefix."lastRxCode", $jsonWeather->{cod});
+ readingsBulkUpdate($hash, $prefix."stationName", $jsonWeather->{name});
+ readingsBulkUpdate($hash, $prefix."humidity", int($jsonWeather->{main}{humidity}));
+ readingsBulkUpdate($hash, $prefix."pressureAbs", int($jsonWeather->{main}{pressure}));
+ readingsBulkUpdate($hash, $prefix."pressureRel", int($jsonWeather->{main}{sea_level}));
+ readingsBulkUpdate($hash, $prefix."windSpeed", $jsonWeather->{wind}{speed});
+ readingsBulkUpdate($hash, $prefix."windDir", int($jsonWeather->{wind}{deg}));
+ readingsBulkUpdate($hash, $prefix."clouds", $jsonWeather->{clouds}{all});
+ readingsBulkUpdate($hash, $prefix."rain3h", $jsonWeather->{rain}{"3h"});
+ readingsBulkUpdate($hash, $prefix."snow3h", $jsonWeather->{snow}{"3h"});
+ readingsBulkUpdate($hash, $prefix."stationLat", sprintf("%.4f",$jsonWeather->{coord}{lat}));
+ readingsBulkUpdate($hash, $prefix."stationLon", sprintf("%.4f",$jsonWeather->{coord}{lon}));
+ readingsBulkUpdate($hash, $prefix."temperature", sprintf("%.1f",$jsonWeather->{main}{temp}-273.15));
+ readingsBulkUpdate($hash, $prefix."tempMin", sprintf("%.1f",$jsonWeather->{main}{temp_min}-273.15));
+ readingsBulkUpdate($hash, $prefix."tempMax", sprintf("%.1f",$jsonWeather->{main}{temp_max}-273.15));
+ readingsBulkUpdate($hash, "state", "active");
+ readingsEndUpdate($hash, 1);
+
+ return;
+}
+
+sub
+OWO_abs2rel($$$){
+# Messwerte
+my $Pa = $_[0];
+my $Temp = $_[1];
+my $Alti = $_[2];
+
+# Konstanten
+my $g0 = 9.80665;
+my $R = 287.05;
+my $T = 273.15;
+my $Ch = 0.12;
+my $a = 0.065;
+my $E = 0;
+
+if($Temp < 9.1) { $E = 5.6402*(-0.0916 + exp(0.06 * $Temp)); }
+ else { $E = 18.2194*(1.0463 - exp(-0.0666 * $Temp)); }
+
+my $xp = $Alti * $g0 / ($R*($T+$Temp + $Ch*$E + $a*$Alti/2));
+my $Pr = $Pa*exp($xp);
+
+return int($Pr);
+}
+
+sub
+OWO_isday($$){
+ my $name = $_[0];
+ my $src = $_[1];
+ my $response;
+
+ if(AttrVal($name, "owoTimestamp",0)){
+ $response = (time > ReadingsVal($name, $src."_sunrise", 0) && time < ReadingsVal($name, $src."_sunset", 0) ? "1" : "0");
+ } else {
+ $response = "Attribute owoTimestamp not set to 1!";
+ }
+ return $response;
+}
+
+
+# OpenWeatherMap API parameters
+# -----------------------------
+# 01 wind_dir - wind direction, grad
+# 02 wind_speed - wind speed, mps
+# 03 temp - temperature, grad C
+# 04 humidity - relative humidity, %
+# 05 pressure - atmosphere pressure
+# 06 wind_gust - speed of wind gust, mps
+# 07 rain_1h - rain in recent hour, mm
+# 08 rain_24h - rain in recent 24 hours, mm
+# 09 rain_today - rain today, mm
+# 10 snow - snow in recent 24 hours, mm
+# 11 lum - illumination, W/M²
+# 12 radiation - radiation
+# 13 dewpoint - dewpoint
+# 14 uv - UV index
+# name - station name
+# lat - latitude
+# long - longitude
+# alt - altitude, m
+
+1;
+
+=pod
+=begin html
+
+
+
openweathermap
+
+
+
+ Define
+
+
+ define <name> openweathermap
+
+ This module provides connection to openweathermap-network www.openweathermap.org (owo)
+ You can use this module to do three different tasks:
+
+
+ - 1. send weather data from your own weather station to owo network.
+ - 2. set any weather data in owo network as datasource for your fhem installation. Data from this station will be updated periodically.
+ - 3. retrieve weather data from any weather station in owo network once. (same as 2. but without update)
+
+
+ Example:
+
+ define owo openweathermap
+
+
+
+ Configuration of your owo tasks
+
+
+ - Prerequisits
+
+
+ - please check global attributes latitude, longitude and altitude are set correctly
+ - you can use all task alone, in any combination or all together
+
+
+ - 1. providing your own weather data to owo network
+
+
+ define myWeather openweather
+ attr myWeather owoUser myuser:mypassword
+ attr myWeather owoStation myStationName
+ attr myWeather owoInterval 600
+ attr myWeather owoSrc00 temp:sensorname:temperature
+
+
+ - 2. set a weather station from owo network as data source for your fhem installation
+
+
+ set myWeather stationByName Leimen
+
+ set myWeather stationById 2879241
+
+ set myWeather stationByGeo 49.3511 8.6894
+
+
+
+ - All commands will retrieve weather data for Leimen (near Heidelberg,DE)
+ - Readings will be updated periodically, based on value of owoInterval.
+ - If lat and lon value in stationByGeo are omitted, the corresponding values from global attributes are used.
+ - All readings will use prefix "c_"
+
+
+
+ - 3. get weather data from a selected weather station once (e.g. to do own presentations)
+
+
+ get myWeather stationByName Leimen
+
+ get myWeather stationById 2879241
+
+ get myWeather stationByGeo 49.3511 8.6894
+
+
+
+ - All commands will retrieve weather data for Leimen (near Heidelberg,DE) once.
+ - Readings will not be updated periodically.
+ - If lat and lon value in stationByGeo are omitted, the corresponding values from global attributes are used.
+ - All readings will use prefix "g_"
+
+
+
+
+
+
+
+ Set-Commands
+
+
+ set <name> <stationById stationId>|<stationByName stationName>|<stationByGeo> [lat lon]>
+
+
+
+
+ Get-Commands
+
+
+ set <name> <stationById stationId>|<stationByName stationName>|<stationByGeo> [lat lon]>
+
+ Used exactly as the "Set" command, but with two differences:
+
+ - all generated readings use prefix "g_" instead of "c_"
+ - readings will not be updated automatically
+
+
+
+
+ Attributes
+
+ - loglevel
+ - do_not_notify
+ - readingFnAttributes
+
+ - owoApiKey
+ <yourOpenweathermapApiKey> - find it in your owo account! If set, it will be used in all owo requests.
+ - owoDebug
+ <0|1> this attribute must be defined and set to 0 to start sending own weather data to owo network. Otherwise you can find all data as debug informations in logfile.
+ - owoGetUrl
+ <owoApiUrl> - current URL to owo api. If this url changes, you can correct it here unless updated version of 98_openweather becomes available.
+ - owoInterval
+ <intervalSeconds> - define the interval used for sending own weather data and for updating SET station. Default = 1800sec. If deleted, default will be used.
+ Please do not set interval below 600 seconds! This regulation is defined by openweathermap.org.
+ Values below 600 will be corrected to 600.
+ - owoStation
+ <yourStationName> - define the station name to be used in "my stats" in owo account
+ - owoUser
+ <user:password> - define your username and password for owo access here
+ - owoRaw
+ <0|1> - defines wether JSON date from owo will be shown in a reading (e.g. to use it for own presentations)
+ - owoTimestamp
+ <0|1> - defines whether date/time readings show timestamps or localtime-formatted informations
+ - owoSrc00 ... owoSrc19
+ Each of this attributes contains information about weather data to be sent in format owoParam:sensorName:readingName:offset
+ Example: attr owo owoSrc00 temp:outside:temperature
will define an attribut owoSrc00, and
+ reading "temperature" from device "outside" will be sent to owo network als paramater "temp" (which indicates current temperature)
+ Parameter "offset" will be added to the read value (e.g. necessary to send dewpoint - use offset 273.15 to send correct value)
+
+
+ Generated Readings/Events:
+
+ - state - current device state (defined|active)
+ - c_<readingName> - weather data from SET weather station. Readings will be updated periodically
+ - g_<readingName> - weather data from GET command. Readings will NOT be updated periodically
+ - my_lastSent - time of last upload to owo network
+ - my_<readingName> - all readings from own weather station. These readings will be sent to owo network.
+
+
+ Author's notes
+
+ - Module uses Perl JSON to decode weather data. If not installed in your environment, please install with
+
+
+ - further informations about sending your own weather data to owo: Link
+ - further informations about owo location search: Link
+ - further informations about owo weather data: Link
+
+
+
+=end html
+
+=cut
diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt
index 348fd0262..2ce40c4bc 100644
--- a/fhem/MAINTAINER.txt
+++ b/fhem/MAINTAINER.txt
@@ -168,6 +168,7 @@ FHEM/98_dewpoint.pm wherzig http://forum.fhem.de Automatis
FHEM/98_dummy.pm rudolfkoenig http://forum.fhem.de Automatisierung
FHEM/98_fheminfo.pm mfr69bs http://forum.fhem.de Sonstiges
FHEM/98_notice.pm mfr69bs http://forum.fhem.de Sonstiges
+FHEM/98_openweathermap.pm betateilchen http://forum.fhem.de Unterstuetzende Dienste
FHEM/98_structure.pm rudolfkoenig http://forum.fhem.de Automatisierung
FHEM/98_telnet.pm rudolfkoenig http://forum.fhem.de Automatisierung
FHEM/98_update.pm mfr69bs http://forum.fhem.de Sonstiges
diff --git a/fhem/docs/commandref_frame.html b/fhem/docs/commandref_frame.html
index f9d3a91aa..5d7dc9552 100644
--- a/fhem/docs/commandref_frame.html
+++ b/fhem/docs/commandref_frame.html
@@ -94,10 +94,11 @@
holiday
LightScene
notify
+ openweathermap
PID
PRESENCE
PachLog
- remotecontrol
+ remotecontrol
SUNRISE_EL
sequence
speedtest