98_openweathermap.pm 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. # $Id: 98_openweathermap.pm 11239 2016-04-14 10:24:10Z betateilchen $
  2. ##############################################################################
  3. #
  4. # 98_openweathermap.pm
  5. # An FHEM Perl module connecting to www.openweathermap.org (owo)
  6. # providing the following tasks:
  7. #
  8. # 1. send weather data from your own weather station to owo network
  9. #
  10. # 2. set a wheater station as datasource inside your fhem installation
  11. #
  12. # 3. retrieve wheather date via owo APII from any weather station
  13. # inside owo network
  14. #
  15. # All tasks can be accessed single or in any desired combination.
  16. # Copyright: betateilchen ®
  17. # e-mail : fhem.development@betateilchen.de
  18. #
  19. # This file is part of fhem.
  20. #
  21. # Fhem is free software: you can redistribute it and/or modify
  22. # it under the terms of the GNU General Public License as published by
  23. # the Free Software Foundation, either version 2 of the License, or
  24. # (at your option) any later version.
  25. #
  26. # Fhem is distributed in the hope that it will be useful,
  27. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  29. # GNU General Public License for more details.
  30. #
  31. # You should have received a copy of the GNU General Public License
  32. # along with fhem. If not, see <http://www.gnu.org/licenses/>.
  33. #
  34. ##############################################################################
  35. # Changelog:
  36. #
  37. # 2013-07-28 initial release
  38. #
  39. # 2013-07-29 fixed: some typos in documentation
  40. # added: "set <name> send"
  41. #
  42. # 2013-07-30 modi: replaced try/catch by eval
  43. # added: some more logging
  44. # added: delete some station readings before update
  45. # added: attribute owoSendUrl
  46. #
  47. # 2013-08-08 added: proxy support by reading env-Settings
  48. #
  49. # 2013-08-11 modi: switched from GetLogLevel() to Log3()
  50. # fixed: use JSON (due to Fritzbox problems)
  51. #
  52. # 2013-08-12 added: XML for decoding, controlled by attribute owoUseXml
  53. # added: attribute owoProxy for proxy configuration
  54. #
  55. # 2013-08-13 added: new reading for html response on "send"
  56. # added: new reading for html response on "get/set"
  57. # 2013-10-12 added: NotifyFn
  58. #
  59. # 2013-12-08 fixed: first try to remove duplicate processing
  60. #
  61. # 2014-02-04 added: shutdownFn
  62. #
  63. # 2014-02-14 modi: changed Loglevel from 3 to 4 where possible
  64. #
  65. # 2014-03-22 added: added set command 'clear'
  66. #
  67. package main;
  68. use strict;
  69. use warnings;
  70. use POSIX;
  71. use XML::Simple;
  72. eval {require JSON};
  73. use feature qw/say switch/;
  74. no if $] >= 5.017011, warnings => 'experimental';
  75. require LWP::UserAgent; # test
  76. my $ua = LWP::UserAgent->new; # test
  77. $ua->timeout(10); # test
  78. $ua->env_proxy; # test
  79. sub OWO_abs2rel($$$);
  80. sub OWO_isday($$);
  81. ###################################
  82. sub openweathermap_Initialize($) {
  83. my ($hash) = @_;
  84. $hash->{SetFn} = "OWO_Set";
  85. $hash->{GetFn} = "OWO_Get";
  86. $hash->{DefFn} = "OWO_Define";
  87. $hash->{UndefFn} = "OWO_Undefine";
  88. $hash->{NotifyFn} = "OWO_Notify";
  89. $hash->{AttrFn} = "OWO_Attr";
  90. $hash->{ShutdownFn} = "OWO_Shutdown";
  91. $hash->{AttrList} = "do_not_notify:0,1 ".
  92. "owoGetUrl owoSendUrl owoInterval:600,900,1800,3600 ".
  93. "owoApiKey owoProxy owoStation owoUser owoUseXml:1,0 ".
  94. "owoDebug:0,1 owoRaw:0,1 owoTimestamp:0,1 ".
  95. "owoSrc00 owoSrc01 owoSrc02 owoSrc03 owoSrc04 ".
  96. "owoSrc05 owoSrc06 owoSrc07 owoSrc08 owoSrc09 ".
  97. "owoSrc10 owoSrc11 owoSrc12 owoSrc13 owoSrc14 ".
  98. "owoSrc15 owoSrc16 owoSrc17 owoSrc18 owoSrc19 ".
  99. $readingFnAttributes;
  100. }
  101. sub OWO_Shutdown($) {
  102. my ($hash) = @_;
  103. my $name = $hash->{NAME};
  104. Log3 ($name,4,"owo $name: shutdown requested");
  105. return undef;
  106. }
  107. sub OWO_Set($@){
  108. my ($hash, @a) = @_;
  109. my $name = $hash->{NAME};
  110. my $usage = "Unknown argument, choose one of clear:readings stationById stationByGeo ".
  111. "stationByName stationByZip send:noArg";
  112. my $response;
  113. return "No Argument given" if(!defined($a[1]));
  114. my $urlString = AttrVal($name, "owoGetUrl", undef);
  115. return "Please set attribute owoGetUrl!" if(!defined($urlString));
  116. my $cmd = $a[1];
  117. given($cmd){
  118. when("?") { return $usage; }
  119. when("clear"){
  120. CommandDeleteReading(undef, "$name _.*");
  121. CommandDeleteReading(undef, "$name c_.*");
  122. CommandDeleteReading(undef, "$name g_.*");
  123. return;
  124. }
  125. when("send"){
  126. OWO_GetStatus($hash,1);
  127. return;
  128. }
  129. when("stationByName"){
  130. $urlString = $urlString."?q=";
  131. my $count;
  132. my $element = @a;
  133. for ($count = 2; $count < $element; $count++) {
  134. $urlString = $urlString."%20".$a[$count];
  135. }
  136. }
  137. when("stationById"){
  138. $urlString = $urlString."?id=".$a[2];
  139. }
  140. when("stationByZip"){
  141. $urlString = $urlString."?zip=".$a[2];
  142. }
  143. when("stationByGeo"){
  144. $a[2] = AttrVal("global", "latitude", 0) unless(defined($a[2]));
  145. $a[3] = AttrVal("global", "longitude", 0) unless(defined($a[3]));
  146. $urlString = $urlString."?lat=$a[2]&lon=$a[3]";
  147. }
  148. default: { return $usage; }
  149. }
  150. UpdateReadings($hash, $urlString, "c_");
  151. return;
  152. }
  153. sub OWO_Get($@){
  154. my ($hash, @a) = @_;
  155. my $name = $hash->{NAME};
  156. my $usage = "Unknown argument, choose one of stationById stationByGeo stationByName stationByZip";
  157. my $response;
  158. return "No Argument given" if(!defined($a[1]));
  159. my $urlString = AttrVal($name, "owoGetUrl", undef);
  160. return "Please set attribute owoGetUrl!" if(!defined($urlString));
  161. my $cmd = $a[1];
  162. given($cmd){
  163. when("?") { return $usage; }
  164. when("stationByName"){
  165. $urlString = $urlString."?q=";
  166. my $count;
  167. my $element = @a;
  168. for ($count = 2; $count < $element; $count++) {
  169. $urlString = $urlString."%20".$a[$count];
  170. }
  171. }
  172. when("stationById"){
  173. $urlString = $urlString."?id=".$a[2];
  174. }
  175. when("stationByZip"){
  176. $urlString = $urlString."?zip=".$a[2];
  177. }
  178. when("stationByGeo"){
  179. $a[2] = AttrVal("global", "latitude", 0) unless(defined($a[2]));
  180. $a[3] = AttrVal("global", "longitude", 0) unless(defined($a[3]));
  181. $urlString = $urlString."?lat=$a[2]&lon=$a[3]";
  182. }
  183. default: { return $usage; }
  184. }
  185. UpdateReadings($hash, $urlString, "g_");
  186. return;
  187. # return $response;
  188. }
  189. sub OWO_Attr(@){
  190. my @a = @_;
  191. my $hash = $defs{$a[1]};
  192. my (undef, $name, $attrName, $attrValue) = @a;
  193. given($attrName){
  194. when("owoInterval"){
  195. if($attrValue ne ""){
  196. $attrValue = 600 if($attrValue < 600);
  197. $hash->{helper}{INTERVAL} = $attrValue;
  198. } else {
  199. $hash->{helper}{INTERVAL} = 1800;
  200. }
  201. $attr{$name}{$attrName} = $attrValue;
  202. RemoveInternalTimer($hash);
  203. InternalTimer(gettimeofday()+$hash->{helper}{INTERVAL}, "OWO_GetStatus", $hash, 0);
  204. break;
  205. }
  206. when("owoProxy"){
  207. if($attrValue ne ""){
  208. $ua->proxy(['http'], $attrValue);
  209. }
  210. }
  211. default {
  212. $attr{$name}{$attrName} = $attrValue;
  213. }
  214. }
  215. return "";
  216. }
  217. sub OWO_Notify($$) {
  218. my ($hash,$dev) = @_;
  219. if( grep(m/^INITIALIZED$/, @{$dev->{CHANGED}}) ) {
  220. delete $modules{openweathermap}->{NotifyFn};
  221. foreach my $d (keys %defs) {
  222. next if($defs{$d}{TYPE} ne "openweathermap");
  223. OWO_GetStatus($hash);
  224. }
  225. }
  226. }
  227. sub OWO_GetStatus($;$){
  228. my ($hash, $local) = @_;
  229. my $name = $hash->{NAME};
  230. my $htmlDummy;
  231. $local = 0 unless(defined($local));
  232. $attr{$name}{"owoInterval"} = 600 if(AttrVal($name,"owoInterval",0) < 600);
  233. RemoveInternalTimer($hash);
  234. ##### start of send job (own weather data)
  235. #
  236. # do we have anything to send from our own station?
  237. #
  238. my ($user, $pass) = split(":", AttrVal($name, "owoUser",""));
  239. my $station = AttrVal($name, "owoStation", undef);
  240. if(defined($user) && defined($station)){
  241. Log3($name, 3, "owo $name: started: SendData");
  242. my $lat = AttrVal("global", "latitude", "");
  243. my $lon = AttrVal("global", "longitude", "");
  244. my $alt = AttrVal("global", "altitude", "");
  245. my $urlString = AttrVal($name, "owoSendUrl", "http://openweathermap.org/data/post");
  246. my ($p1, $p2) = split("//", $urlString);
  247. $urlString = $p1."//$user:$pass\@".$p2;
  248. my $dataString = "name=$station&lat=$lat&long=$lon&alt=$alt";
  249. my ($count, $paraName, $paraVal, $p, $s, $v, $o);
  250. for ($count = 0; $count < 20; $count++) {
  251. $paraName = "owoSrc".sprintf("%02d",$count);
  252. $paraVal = AttrVal($name, $paraName, undef);
  253. if(defined($paraVal)){
  254. ($p, $s, $v, $o) = split(":", AttrVal($name, $paraName, ""));
  255. $o = 0 if(!defined($o));
  256. $v = ReadingsVal($s, $v, "?") + $o;
  257. $dataString = $dataString."&$p=$v";
  258. Log3($name, 4, "owo $name: reading: $paraName $p $s $v");
  259. readingsSingleUpdate($hash, "my_".$p, $v, 1);
  260. }
  261. }
  262. $dataString .= "&APPID=".AttrVal($name, "owoApiKey", "");
  263. my $sendString = $urlString."?".$dataString;
  264. if(AttrVal($name, "owoDebug",1) == 0){
  265. Log3($name, 4, "owo $name: sending: $dataString");
  266. $htmlDummy = $ua->post($sendString);
  267. Log3($name, 3, "owo $name: htmlResponse: ".$htmlDummy->status_line);
  268. } else {
  269. Log3($name, 3, "owo $name: debug: $dataString");
  270. }
  271. readingsBeginUpdate($hash);
  272. readingsBulkUpdate($hash, "_httpResponse_my", $htmlDummy->status_line) if $htmlDummy;
  273. readingsBulkUpdate($hash, "my_response", $htmlDummy->decoded_content) if $htmlDummy;
  274. readingsBulkUpdate($hash, "state","active");
  275. if(AttrVal($name, "owoTimestamp", 0) == 1){
  276. readingsBulkUpdate($hash, "my_lastSent", time);
  277. } else {
  278. readingsBulkUpdate($hash, "my_lastSent", localtime(time));
  279. }
  280. readingsEndUpdate($hash, 1);
  281. if(defined($htmlDummy)){
  282. CommandDeleteReading(undef, "$name my_.*") if $htmlDummy->is_error;
  283. }
  284. }
  285. ##### end of send job
  286. ##### start of update job (set station)
  287. #
  288. # Do we already have a stationId set?
  289. # If yes => update this station
  290. #
  291. my $cId = ReadingsVal($name,"c_stationId", undef);
  292. if(defined($cId)){
  293. my $cName = ReadingsVal($name,"stationName", "");
  294. Log3($name, 4, "owo $name: retrievingStationData: Id: $cId Name: $cName");
  295. fhem("set $name stationById $cId");
  296. }
  297. ##### end of update job
  298. InternalTimer(gettimeofday()+$hash->{helper}{INTERVAL}, "OWO_GetStatus", $hash, 0) unless($local == 1);
  299. return;
  300. }
  301. sub OWO_Define($$){
  302. my ($hash, $def) = @_;
  303. my @a = split("[ \t][ \t]*", $def);
  304. my $name = $hash->{NAME};
  305. $hash->{helper}{INTERVAL} = 1800;
  306. $hash->{helper}{AVAILABLE} = 1;
  307. $attr{$name}{"owoDebug"} = 1;
  308. $attr{$name}{"owoUseXml"} = 1;
  309. $attr{$name}{"owoInterval"} = 1800;
  310. $attr{$name}{"owoGetUrl"} = "http://api.openweathermap.org/data/2.5/weather";
  311. $attr{$name}{"owoSendUrl"} = "http://openweathermap.org/data/post";
  312. if( $init_done ) {
  313. delete $modules{openweathermap}->{NotifyFn};
  314. OWO_GetStatus($hash);
  315. } else {
  316. readingsSingleUpdate($hash, "state", "defined",1);
  317. }
  318. # readingsSingleUpdate($hash, "state","defined",1);
  319. # InternalTimer(gettimeofday()+$hash->{helper}{INTERVAL}, "OWO_GetStatus", $hash, 0);
  320. Log3($name, 4, "owo $name: created");
  321. return;
  322. }
  323. sub OWO_Undefine($$){
  324. my($hash, $name) = @_;
  325. RemoveInternalTimer($hash);
  326. return undef;
  327. }
  328. sub UpdateReadings($$$){
  329. my ($hash, $url, $prefix) = @_;
  330. my $name = $hash->{NAME};
  331. my ($jsonWeather, $response);
  332. my $xmlMode = AttrVal($name, "owoUseXml", "");
  333. $url .= "&mode=xml" if($xmlMode eq "1");
  334. $url .= "&APPID=".AttrVal($name, "owoApiKey", "");
  335. eval {$response = $ua->get("$url")};
  336. #
  337. # error handling for not found stations (error 404 from server)
  338. #
  339. if($response->decoded_content =~ m/error/i){
  340. CommandDeleteReading(undef, "$name $prefix.*");
  341. readingsSingleUpdate($hash, "_httpResponse_".substr($prefix,0,1), $response->decoded_content, 1);
  342. return;
  343. }
  344. if(defined($response)){
  345. if(AttrVal($name, "owoDebug", 1) == 1){
  346. Log3($name, 4, "owo $name: response:\n".$response->decoded_content);
  347. }
  348. } else {
  349. Log3($name, 4, "owo $name: error: no response from server");
  350. return;
  351. }
  352. CommandDeleteReading(undef, "$name $prefix.*");
  353. readingsSingleUpdate($hash, "_httpResponse_".substr($prefix,0,1), $response->status_line, 1);
  354. if($xmlMode eq "1" && $response->is_success){
  355. Log3($name, 4, "owo $name: decoding XML");
  356. my $xml = new XML::Simple;
  357. $jsonWeather = undef;
  358. $jsonWeather = $xml->XMLin($response->decoded_content, KeyAttr => 'current' );
  359. if(defined($jsonWeather)){
  360. readingsBeginUpdate($hash);
  361. if(AttrVal($name, "owoRaw", 0) == 1){
  362. readingsBulkUpdate($hash, $prefix."rawData", $response->decoded_content);
  363. }
  364. readingsBulkUpdate($hash, "_dataSource", "www.openweathermap.org");
  365. readingsBulkUpdate($hash, "_decodedWith", "XML");
  366. readingsBulkUpdate($hash, $prefix."lastWx", $jsonWeather->{lastupdate}{value});
  367. readingsBulkUpdate($hash, $prefix."sunrise", $jsonWeather->{city}{sun}{rise});
  368. readingsBulkUpdate($hash, $prefix."sunset", $jsonWeather->{city}{sun}{set});
  369. readingsBulkUpdate($hash, $prefix."stationId", $jsonWeather->{city}{id});
  370. readingsBulkUpdate($hash, $prefix."stationName", utf8ToLatin1($jsonWeather->{city}{name}));
  371. readingsBulkUpdate($hash, $prefix."stationCountry", $jsonWeather->{city}{country});
  372. readingsBulkUpdate($hash, $prefix."stationLat", sprintf("%.4f",$jsonWeather->{city}{coord}{lat}));
  373. readingsBulkUpdate($hash, $prefix."stationLon", sprintf("%.4f",$jsonWeather->{city}{coord}{lon}));
  374. readingsBulkUpdate($hash, $prefix."temperature", sprintf("%.1f",$jsonWeather->{temperature}{value}-273.15));
  375. readingsBulkUpdate($hash, $prefix."tempMin", sprintf("%.1f",$jsonWeather->{temperature}{min}-273.15));
  376. readingsBulkUpdate($hash, $prefix."tempMax", sprintf("%.1f",$jsonWeather->{temperature}{max}-273.15));
  377. readingsBulkUpdate($hash, $prefix."humidity", $jsonWeather->{humidity}{value});
  378. readingsBulkUpdate($hash, $prefix."pressure", $jsonWeather->{pressure}{value});
  379. # readingsBulkUpdate($hash, $prefix."pressureRel", $jsonWeather->{main}{sea_level});
  380. readingsBulkUpdate($hash, $prefix."windSpeed", $jsonWeather->{wind}{speed}{value});
  381. readingsBulkUpdate($hash, $prefix."windDir", $jsonWeather->{wind}{direction}{value});
  382. readingsBulkUpdate($hash, $prefix."clouds", $jsonWeather->{clouds}{value});
  383. readingsBulkUpdate($hash, $prefix."rain3h", $jsonWeather->{rain}{"3h"});
  384. readingsBulkUpdate($hash, $prefix."snow3h", $jsonWeather->{snow}{"3h"});
  385. readingsBulkUpdate($hash, "state", "active");
  386. readingsEndUpdate($hash, 1);
  387. } else {
  388. Log3($name, 2, "owo $name error: update not possible!");
  389. }
  390. }
  391. if($xmlMode ne "1" && $response->is_success){
  392. Log3($name, 4, "owo $name: decoding JSON");
  393. my $json = JSON->new->allow_nonref;
  394. eval {$jsonWeather = $json->decode($response->decoded_content)}; warn $@ if $@;
  395. if(defined($jsonWeather)){
  396. readingsBeginUpdate($hash);
  397. if(AttrVal($name, "owoRaw", 0) == 1){
  398. readingsBulkUpdate($hash, $prefix."rawData", $response->decoded_content);
  399. }
  400. if(AttrVal($name, "owoTimestamp", 0) == 1){
  401. readingsBulkUpdate($hash, $prefix."lastWx", $jsonWeather->{dt});
  402. readingsBulkUpdate($hash, $prefix."sunrise", $jsonWeather->{sys}{sunrise});
  403. readingsBulkUpdate($hash, $prefix."sunset", $jsonWeather->{sys}{sunset});
  404. } else {
  405. readingsBulkUpdate($hash, $prefix."lastWx", localtime($jsonWeather->{dt}));
  406. readingsBulkUpdate($hash, $prefix."sunrise", localtime($jsonWeather->{sys}{sunrise}));
  407. readingsBulkUpdate($hash, $prefix."sunset", localtime($jsonWeather->{sys}{sunset}));
  408. }
  409. readingsBulkUpdate($hash, "_dataSource", "www.openweathermap.org");
  410. readingsBulkUpdate($hash, "_decodedWith", "JSON");
  411. readingsBulkUpdate($hash, $prefix."stationId", $jsonWeather->{id});
  412. readingsBulkUpdate($hash, $prefix."lastRxCode", $jsonWeather->{cod});
  413. readingsBulkUpdate($hash, $prefix."stationName", utf8ToLatin1($jsonWeather->{name}));
  414. readingsBulkUpdate($hash, $prefix."humidity", $jsonWeather->{main}{humidity});
  415. readingsBulkUpdate($hash, $prefix."pressureAbs", $jsonWeather->{main}{pressure});
  416. readingsBulkUpdate($hash, $prefix."pressureRel", $jsonWeather->{main}{sea_level});
  417. readingsBulkUpdate($hash, $prefix."windSpeed", $jsonWeather->{wind}{speed});
  418. readingsBulkUpdate($hash, $prefix."windDir", $jsonWeather->{wind}{deg});
  419. readingsBulkUpdate($hash, $prefix."clouds", $jsonWeather->{clouds}{all});
  420. readingsBulkUpdate($hash, $prefix."rain3h", $jsonWeather->{rain}{"3h"});
  421. readingsBulkUpdate($hash, $prefix."snow3h", $jsonWeather->{snow}{"3h"});
  422. readingsBulkUpdate($hash, $prefix."stationLat", sprintf("%.4f",$jsonWeather->{coord}{lat}));
  423. readingsBulkUpdate($hash, $prefix."stationLon", sprintf("%.4f",$jsonWeather->{coord}{lon}));
  424. readingsBulkUpdate($hash, $prefix."temperature", sprintf("%.1f",$jsonWeather->{main}{temp}-273.15));
  425. readingsBulkUpdate($hash, $prefix."tempMin", sprintf("%.1f",$jsonWeather->{main}{temp_min}-273.15));
  426. readingsBulkUpdate($hash, $prefix."tempMax", sprintf("%.1f",$jsonWeather->{main}{temp_max}-273.15));
  427. readingsBulkUpdate($hash, "state", "active");
  428. readingsEndUpdate($hash, 1);
  429. } else {
  430. Log3($name, 2, "owo $name error: update not possible!");
  431. }
  432. }
  433. return;
  434. }
  435. sub OWO_abs2rel($$$){
  436. # Messwerte
  437. my $Pa = $_[0];
  438. my $Temp = $_[1];
  439. my $Alti = $_[2];
  440. # Konstanten
  441. my $g0 = 9.80665;
  442. my $R = 287.05;
  443. my $T = 273.15;
  444. my $Ch = 0.12;
  445. my $a = 0.065;
  446. my $E = 0;
  447. if($Temp < 9.1) { $E = 5.6402*(-0.0916 + exp(0.06 * $Temp)); }
  448. else { $E = 18.2194*(1.0463 - exp(-0.0666 * $Temp)); }
  449. my $xp = $Alti * $g0 / ($R*($T+$Temp + $Ch*$E + $a*$Alti/2));
  450. my $Pr = $Pa*exp($xp);
  451. return int($Pr);
  452. }
  453. sub OWO_isday($$){
  454. my $name = $_[0];
  455. my $src = $_[1];
  456. my $response;
  457. if(AttrVal($name, "owoTimestamp",0)){
  458. $response = (time > ReadingsVal($name, $src."_sunrise", 0) && time < ReadingsVal($name, $src."_sunset", 0) ? "1" : "0");
  459. } else {
  460. $response = "Attribute owoTimestamp not set to 1!";
  461. }
  462. return $response;
  463. }
  464. # OpenWeatherMap API parameters
  465. # -----------------------------
  466. # 01 wind_dir - wind direction, grad
  467. # 02 wind_speed - wind speed, mps
  468. # 03 temp - temperature, grad C
  469. # 04 humidity - relative humidity, %
  470. # 05 pressure - atmosphere pressure
  471. # 06 wind_gust - speed of wind gust, mps
  472. # 07 rain_1h - rain in recent hour, mm
  473. # 08 rain_24h - rain in recent 24 hours, mm
  474. # 09 rain_today - rain today, mm
  475. # 10 snow - snow in recent 24 hours, mm
  476. # 11 lum - illumination, W/M²
  477. # 12 radiation - radiation
  478. # 13 dewpoint - dewpoint
  479. # 14 uv - UV index
  480. # name - station name
  481. # lat - latitude
  482. # long - longitude
  483. # alt - altitude, m
  484. 1;
  485. =pod
  486. not to be translated
  487. =begin html
  488. <a name="openweathermap"></a>
  489. <h3>openweathermap</h3>
  490. <ul>
  491. <b>Prerequisits</b>
  492. <ul>
  493. <br/>
  494. <li>Module uses following additional Perl modules:<br/><br/>
  495. <code>XML::Simple, JSON</code><br/><br/>
  496. If not already installed in your environment, please install them using appropriate commands from your environment.<br/>
  497. Use of JSON is optional. You can activate it by setting attribute owoUseXml to 0</li><br/>
  498. <li>please check global attributes latitude, longitude and altitude are set correctly</li>
  499. <li>you can use all task alone, in any combination or all together</li>
  500. </ul>
  501. <br/><br/>
  502. <a name="openweathermapdefine"></a>
  503. <b>Define</b>
  504. <ul>
  505. <br/>
  506. <code>define &lt;name&gt; openweathermap</code>
  507. <br/><br/>
  508. This module provides connection to openweathermap-network www.openweathermap.org (owo)<br/>
  509. You can use this module to do three different tasks:<br/>
  510. <br/>
  511. <ul>
  512. <li>1. send weather data from your own weather station to owo network.</li>
  513. <li>2. set any weather data in owo network as datasource for your fhem installation. Data from this station will be updated periodically.</li>
  514. <li>3. retrieve weather data from any weather station in owo network once. (same as 2. but without update)</li>
  515. </ul>
  516. <br/>
  517. Example:<br/>
  518. <br/>
  519. <ul><code>define owo openweathermap</code></ul>
  520. </ul>
  521. <br/><br/>
  522. <b>Configuration of your owo tasks</b><br/><br/>
  523. <ul>
  524. <a name="owoconfiguration1"></a>
  525. <li>1. providing your own weather data to owo network</li>
  526. <br/>
  527. <ul><code>
  528. define owo openweathermap<br/>
  529. attr owo owoUser myuser:mypassword<br/>
  530. attr owo owoStation myStationName<br/>
  531. attr owo owoInterval 600<br/>
  532. attr owo owoSrc00 temp:sensorname:temperature<br/>
  533. </code></ul><br/>
  534. <a name="owoconfiguration2"></a>
  535. <li>2. set a weather station from owo network as data source for your fhem installation</li>
  536. <br/>
  537. <ul><code>
  538. set owo stationByName Leimen
  539. <br/><br/>
  540. set owo stationById 2879241
  541. <br/><br/>
  542. set owo stationByGeo 49.3511 8.6894
  543. </code></ul>
  544. <br/><br/>
  545. <ul>
  546. <li>All commands will retrieve weather data for Leimen (near Heidelberg,DE)</li>
  547. <li>Readings will be updated periodically, based on value of owoInterval.</li>
  548. <li>If lat and lon value in stationByGeo are omitted, the corresponding values from global attributes are used.</li>
  549. <li>All readings will use prefix "c_"</li>
  550. </ul>
  551. <br/>
  552. <a name="owoconfiguration3"></a>
  553. <li>3. get weather data from a selected weather station once (e.g. to do own presentations)</li>
  554. <br/>
  555. <ul><code>
  556. get owo stationByName Leimen
  557. <br/><br/>
  558. get owo stationById 2879241
  559. <br/><br/>
  560. get owo stationByGeo 49.3511 8.6894
  561. </code></ul>
  562. <br/><br/>
  563. <ul>
  564. <li>All commands will retrieve weather data for Leimen (near Heidelberg,DE) once.</li>
  565. <li>Readings will not be updated periodically.</li>
  566. <li>If lat and lon value in stationByGeo are omitted, the corresponding values from global attributes are used.</li>
  567. <li>All readings will use prefix "g_"</li>
  568. </ul>
  569. <br/>
  570. </ul>
  571. <br/><br/>
  572. <a name="openweathermapset"></a>
  573. <b>Set-Commands</b><br/>
  574. <ul>
  575. <br/>
  576. <code>set &lt;name&gt; clear</code><br/>
  577. <br/>
  578. <ul>Delete all readings for cleanup</ul>
  579. <br/><br/>
  580. <code>set &lt;name&gt; send</code><br/>
  581. <br/>
  582. <ul>start an update cycle manually:
  583. <ul>
  584. <li>send own data</li>
  585. <li>update c_* readings from "set" station (if defined)</li>
  586. <br/>
  587. <li>does not affect or re-trigger running timer cycles!</li>
  588. <li>main purpose: for debugging and testing</li>
  589. </ul>
  590. </ul>
  591. <br/><br/>
  592. <code>set &lt;name&gt; &lt;stationById stationId&gt;|&lt;stationByName stationName&gt;|&lt;stationByGeo> [lat lon]&gt;|&lt;stationByZip stationZipCode&gt;</code>
  593. <br/><br/>
  594. <ul>see description above: <a href="#owoconfiguration2">Configuration task 2</a></ul>
  595. <br/><br/>
  596. </ul>
  597. <br/><br/>
  598. <a name="openweathermapget"></a>
  599. <b>Get-Commands</b><br/>
  600. <ul>
  601. <br/>
  602. <code>get &lt;name&gt; &lt;stationById stationId&gt;|&lt;stationByName stationName&gt;|&lt;stationByGeo> [lat lon]&gt;|&lt;stationByZip stationZipCode&gt;</code>
  603. <br/><br/>
  604. <ul>see description above: <a href="#owoconfiguration3">Configuration task 3</a></ul>
  605. <br/>
  606. Used exactly as the "set" command, but with two differences:<br/><br/>
  607. <ul>
  608. <li>all generated readings use prefix "g_" instead of "c_"</li>
  609. <li>readings will not be updated automatically</li>
  610. </ul>
  611. </ul>
  612. <br/><br/>
  613. <a name="openweathermapattr"></a>
  614. <b>Attributes</b><br/><br/>
  615. <ul>
  616. <li><a href="#do_not_notify">do_not_notify</a></li>
  617. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  618. <br/>
  619. <li><b>owoApiKey</b></li>
  620. &lt;yourOpenweathermapApiKey&gt; - find it in your owo account! If set, it will be used in all owo requests.<br/>
  621. <li><b>owoDebug</b></li>
  622. &lt;0|1&gt; this attribute <b>must be defined and set to 0</b> to start sending own weather data to owo network. Otherwise you can find all data as debug informations in logfile.<br/>
  623. <li><b>owoGetUrl</b></li>
  624. &lt;owoApiUrl&gt; - current URL to owo api. If this url changes, you can correct it here unless updated version of 98_openweather becomes available.<br/>
  625. <li><b>owoInterval</b></li>
  626. &lt;intervalSeconds&gt; - define the interval used for sending own weather data and for updating SET station. Default = 1800sec. If deleted, default will be used.<br/>
  627. <b>Please do not set interval below 600 seconds! This regulation is defined by openweathermap.org.</b><br/>
  628. Values below 600 will be corrected to 600.<br/>
  629. <li><b>owoProxy</b></li>
  630. &lt;proxyAddress&gt; - define a proxy server address, please give full url and port, e.g. http://192.168.111.222:8080<br/>
  631. <li><b>owoStation</b></li>
  632. &lt;yourStationName&gt; - define the station name to be used in "my stats" in owo account<br/>
  633. <li><b>owoUser</b></li>
  634. &lt;user:password&gt; - define your username and password for owo access here<br/>
  635. <li><b>owoRaw</b></li>
  636. &lt;0|1&gt; - defines wether JSON date from owo will be shown in an additional reading (e.g. to use it for own presentations)<br/>
  637. <li><b>owoSendUrl</b></li>
  638. Current URL to post your own data. If this url changes, you can correct it here unless updated version of 98_openweather becomes available.<br/>
  639. <li><b>owoTimestamp</b></li>
  640. &lt;0|1&gt; - defines whether date/time readings show timestamps or localtime-formatted informations<br/>
  641. <li><b>owoSrc00 ... owoSrc19</b></li>
  642. Each of this attributes contains information about weather data to be sent in format <code>owoParam:sensorName:readingName:offset</code><br/>
  643. Example: <code>attr owo owoSrc00 temp:outside:temperature</code> will define an attribut owoSrc00, and <br/>
  644. reading "temperature" from device "outside" will be sent to owo network als paramater "temp" (which indicates current temperature)<br/>
  645. Parameter "offset" will be added to the read value (e.g. necessary to send dewpoint - use offset 273.15 to send correct value)
  646. <li><b>owoUseXml</b></li>
  647. &lt;0|1&gt; - defines wether data must be decoded from XML, e.g. JSON not available on Fritzbox<br/>
  648. </ul>
  649. <br/><br/>
  650. <b>Generated Readings/Events:</b><br/><br/>
  651. <ul>
  652. <li><b>state</b> - current device state (defined|active)</li>
  653. <li><b>c_&lt;readingName&gt;</b> - weather data from SET weather station. Readings will be updated periodically</li>
  654. <li><b>g_&lt;readingName&gt;</b> - weather data from GET command. Readings will NOT be updated periodically</li>
  655. <li><b>my_lastSent</b> - time of last upload to owo network</li>
  656. <li><b>my_&lt;readingName&gt;</b> - all readings from own weather station. These readings will be sent to owo network.</li>
  657. </ul>
  658. <br/><br/>
  659. <b>Author's notes</b><br/><br/>
  660. <ul>
  661. <li>further informations about sending your own weather data to owo: <a href="http://openweathermap.org/stations">Link</a></li>
  662. <li>further informations about owo location search: <a href="http://openweathermap.org/API">Link</a></li>
  663. <li>further informations about owo weather data: <a href="http://bugs.openweathermap.org/projects/api/wiki/Weather_Data">Link</a></li>
  664. </ul>
  665. </ul>
  666. =end html
  667. =begin html_DE
  668. <a name="openweathermap"></a>
  669. <h3>openweathermap</h3>
  670. <ul>
  671. Sorry, keine deutsche Dokumentation vorhanden.<br/><br/>
  672. Die englische Doku gibt es hier: <a href='http://fhem.de/commandref.html#openweathermap'>openweathermap</a><br/>
  673. </ul>
  674. =end html_DE
  675. =cut