59_WUup.pm 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. # $Id: 59_WUup.pm 15290 2017-10-19 15:24:44Z mahowi $
  2. ################################################################################
  3. # 59_WUup.pm
  4. #
  5. # Copyright: mahowi
  6. # e-mail: mahowi@gmx.net
  7. #
  8. # Based on 55_weco.pm by betateilchen
  9. #
  10. # This file is part of fhem.
  11. #
  12. # Fhem is free software: you can redistribute it and/or modify
  13. # it under the terms of the GNU General Public License as published by
  14. # the Free Software Foundation, either version 2 of the License, or
  15. # (at your option) any later version.
  16. #
  17. # Fhem is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. # GNU General Public License for more details.
  21. #
  22. # You should have received a copy of the GNU General Public License
  23. # along with fhem. If not, see <http://www.gnu.org/licenses/>.
  24. #
  25. ################################################################################
  26. package main;
  27. use strict;
  28. use warnings;
  29. use Time::HiRes qw(gettimeofday);
  30. use HttpUtils;
  31. use UConv;
  32. my $version = "0.9.5";
  33. # Declare functions
  34. sub WUup_Initialize($);
  35. sub WUup_Define($$$);
  36. sub WUup_Undef($$);
  37. sub WUup_Set($@);
  38. sub WUup_Attr(@);
  39. sub WUup_stateRequestTimer($);
  40. sub WUup_send($);
  41. sub WUup_receive($);
  42. ################################################################################
  43. #
  44. # Main routines
  45. #
  46. ################################################################################
  47. sub WUup_Initialize($) {
  48. my ($hash) = @_;
  49. $hash->{DefFn} = "WUup_Define";
  50. $hash->{UndefFn} = "WUup_Undef";
  51. $hash->{SetFn} = "WUup_Set";
  52. $hash->{AttrFn} = "WUup_Attr";
  53. $hash->{AttrList} =
  54. "disable:1 "
  55. . "disabledForIntervals "
  56. . "interval "
  57. . "unit_windspeed:km/h,m/s "
  58. . "wubaromin wudailyrainin wudewptf wuhumidity wurainin wusoilmoisture "
  59. . "wusoiltempf wusolarradiation wutempf wuUV wuwinddir wuwinddir_avg2m "
  60. . "wuwindgustdir wuwindgustdir_10m wuwindgustmph wuwindgustmph_10m "
  61. . "wuwindspdmph_avg2m wuwindspeedmph "
  62. . $readingFnAttributes;
  63. $hash->{VERSION} = $version;
  64. }
  65. sub WUup_Define($$$) {
  66. my ( $hash, $def ) = @_;
  67. my @a = split( "[ \t][ \t]*", $def );
  68. return "syntax: define <name> WUup <stationID> <password>"
  69. if ( int(@a) != 4 );
  70. my $name = $hash->{NAME};
  71. $hash->{VERSION} = $version;
  72. $hash->{INTERVAL} = 300;
  73. $hash->{helper}{stationid} = $a[2];
  74. $hash->{helper}{password} = $a[3];
  75. $hash->{helper}{softwaretype} = 'FHEM';
  76. $hash->{helper}{url} =
  77. "https://weatherstation.wunderground.com/weatherstation/updateweatherstation.php";
  78. $hash->{helper}{url_rf} =
  79. "https://rtupdate.wunderground.com/weatherstation/updateweatherstation.php";
  80. readingsSingleUpdate( $hash, "state", "defined", 1 );
  81. $attr{$name}{room} = "Weather" if ( !defined( $attr{$name}{room} ) );
  82. $attr{$name}{unit_windspeed} = "km/h"
  83. if ( !defined( $attr{$name}{unit_windspeed} ) );
  84. RemoveInternalTimer($hash);
  85. if ($init_done) {
  86. WUup_stateRequestTimer($hash);
  87. }
  88. else {
  89. InternalTimer( gettimeofday(), "WUup_stateRequestTimer", $hash, 0 );
  90. }
  91. Log3 $name, 3, "WUup ($name): defined";
  92. return undef;
  93. }
  94. sub WUup_Undef($$) {
  95. my ( $hash, $arg ) = @_;
  96. RemoveInternalTimer($hash);
  97. return undef;
  98. }
  99. sub WUup_Set($@) {
  100. my ( $hash, $name, $cmd, @args ) = @_;
  101. return "\"set $name\" needs at least one argument" unless ( defined($cmd) );
  102. if ( $cmd eq "update" ) {
  103. WUup_stateRequestTimer($hash);
  104. }
  105. else {
  106. return "Unknown argument $cmd, choose one of update:noArg";
  107. }
  108. }
  109. sub WUup_Attr(@) {
  110. my ( $cmd, $name, $attrName, $attrVal ) = @_;
  111. my $hash = $defs{$name};
  112. if ( $attrName eq "disable" ) {
  113. if ( $cmd eq "set" and $attrVal eq "1" ) {
  114. readingsSingleUpdate( $hash, "state", "disabled", 1 );
  115. Log3 $name, 3, "WUup ($name) - disabled";
  116. }
  117. elsif ( $cmd eq "del" ) {
  118. readingsSingleUpdate( $hash, "state", "active", 1 );
  119. Log3 $name, 3, "WUup ($name) - enabled";
  120. }
  121. }
  122. if ( $attrName eq "disabledForIntervals" ) {
  123. if ( $cmd eq "set" ) {
  124. readingsSingleUpdate( $hash, "state", "unknown", 1 );
  125. Log3 $name, 3, "WUup ($name) - disabledForIntervals";
  126. }
  127. elsif ( $cmd eq "del" ) {
  128. readingsSingleUpdate( $hash, "state", "active", 1 );
  129. Log3 $name, 3, "WUup ($name) - enabled";
  130. }
  131. }
  132. if ( $attrName eq "interval" ) {
  133. if ( $cmd eq "set" ) {
  134. if ( $attrVal < 3 ) {
  135. Log3 $name, 1,
  136. "WUup ($name) - interval too small, please use something >= 3 (sec), default is 300 (sec).";
  137. return
  138. "interval too small, please use something >= 3 (sec), default is 300 (sec)";
  139. }
  140. else {
  141. $hash->{INTERVAL} = $attrVal;
  142. Log3 $name, 4, "WUup ($name) - set interval to $attrVal";
  143. }
  144. }
  145. elsif ( $cmd eq "del" ) {
  146. $hash->{INTERVAL} = 300;
  147. Log3 $name, 4, "WUup ($name) - set interval to default";
  148. }
  149. }
  150. return undef;
  151. }
  152. sub WUup_stateRequestTimer($) {
  153. my ($hash) = @_;
  154. my $name = $hash->{NAME};
  155. if ( !IsDisabled($name) ) {
  156. readingsSingleUpdate( $hash, "state", "active", 1 )
  157. if (
  158. (
  159. ReadingsVal( $name, "state", 0 ) eq "defined"
  160. or ReadingsVal( $name, "state", 0 ) eq "disabled"
  161. or ReadingsVal( $name, "state", 0 ) eq "Unknown"
  162. )
  163. );
  164. WUup_send($hash);
  165. }
  166. else {
  167. readingsSingleUpdate( $hash, "state", "disabled", 1 );
  168. }
  169. InternalTimer( gettimeofday() + $hash->{INTERVAL},
  170. "WUup_stateRequestTimer", $hash, 1 );
  171. Log3 $name, 5,
  172. "Sub WUup_stateRequestTimer ($name) - Request Timer is called";
  173. }
  174. sub WUup_send($) {
  175. my ($hash) = @_;
  176. my $name = $hash->{NAME};
  177. my $version = $hash->{VERSION};
  178. my $url = "";
  179. if ( $hash->{INTERVAL} < 300 ) {
  180. $url = $hash->{helper}{url_rf};
  181. }
  182. else {
  183. $url = $hash->{helper}{url};
  184. }
  185. $url .= "?ID=" . $hash->{helper}{stationid};
  186. $url .= "&PASSWORD=" . $hash->{helper}{password};
  187. my $datestring = strftime "%F+%T", gmtime;
  188. $datestring =~ s/:/%3A/g;
  189. $url .= "&dateutc=" . $datestring;
  190. $attr{$name}{unit_windspeed} = "km/h"
  191. if ( !defined( $attr{$name}{unit_windspeed} ) );
  192. my ( $data, $d, $r, $o );
  193. my $a = $attr{$name};
  194. while ( my ( $key, $value ) = each(%$a) ) {
  195. next if substr( $key, 0, 2 ) ne 'wu';
  196. $key = substr( $key, 2, length($key) - 2 );
  197. ( $d, $r, $o ) = split( ":", $value );
  198. if ( defined($r) ) {
  199. $o = ( defined($o) ) ? $o : 0;
  200. $value = ReadingsVal( $d, $r, 0 ) + $o;
  201. }
  202. if ( $key =~ /\w+f$/ ) {
  203. $value = UConv::c2f( $value, 4 );
  204. }
  205. elsif ( $key =~ /\w+mph.*/ ) {
  206. if ( $attr{$name}{unit_windspeed} eq "m/s" ) {
  207. Log3 $name, 5, "WUup ($name) - windspeed unit is m/s";
  208. $value = UConv::kph2mph( ( UConv::mps2kph( $value, 4 ) ), 4 );
  209. }
  210. else {
  211. Log3 $name, 5, "WUup ($name) - windspeed unit is km/h";
  212. $value = UConv::kph2mph( $value, 4 );
  213. }
  214. }
  215. elsif ( $key eq "baromin" ) {
  216. $value = UConv::hpa2inhg( $value, 4 );
  217. }
  218. elsif ( $key =~ /.*rainin$/ ) {
  219. $value = UConv::mm2in( $value, 4 );
  220. }
  221. $data .= "&$key=$value";
  222. }
  223. readingsBeginUpdate($hash);
  224. if ( defined($data) ) {
  225. readingsBulkUpdate( $hash, "data", $data );
  226. Log3 $name, 4, "WUup ($name) - data sent: $data";
  227. $url .= $data;
  228. $url .= "&softwaretype=" . $hash->{helper}{softwaretype};
  229. $url .= "&action=updateraw";
  230. if ( $hash->{INTERVAL} < 300 ) {
  231. $url .= "&realtime=1&rtfreq=" . $hash->{INTERVAL};
  232. }
  233. my $param = {
  234. url => $url,
  235. timeout => 6,
  236. hash => $hash,
  237. method => "GET",
  238. header =>
  239. "agent: FHEM-WUup/$version\r\nUser-Agent: FHEM-WUup/$version",
  240. callback => \&WUup_receive
  241. };
  242. Log3 $name, 5, "WUup ($name) - full URL: $url";
  243. HttpUtils_NonblockingGet($param);
  244. # my $response = GetFileFromURL($url);
  245. # readingsBulkUpdate( $hash, "response", $response );
  246. # Log3 $name, 4, "WUup ($name) - server response: $response";
  247. }
  248. else {
  249. CommandDeleteReading( undef, "$name data" );
  250. CommandDeleteReading( undef, "$name response" );
  251. Log3 $name, 3, "WUup ($name) - no data";
  252. readingsBulkUpdate( $hash, "state", "defined" );
  253. }
  254. readingsEndUpdate( $hash, 1 );
  255. return;
  256. }
  257. sub WUup_receive($) {
  258. my ( $param, $err, $data ) = @_;
  259. my $hash = $param->{hash};
  260. my $name = $hash->{NAME};
  261. if ( $err ne "" ) {
  262. Log3 $name, 3,
  263. "WUup ($name) - error while requesting " . $param->{url} . " - $err";
  264. readingsSingleUpdate( $hash, "state", "ERROR", undef );
  265. readingsSingleUpdate( $hash, "response", $err, undef );
  266. }
  267. elsif ( $data ne "" ) {
  268. Log3 $name, 4, "WUup ($name) - server response: $data";
  269. readingsSingleUpdate( $hash, "state", "active", undef );
  270. readingsSingleUpdate( $hash, "response", $data, undef );
  271. }
  272. }
  273. 1;
  274. ################################################################################
  275. #
  276. # Documentation
  277. #
  278. ################################################################################
  279. #
  280. # Changelog:
  281. #
  282. # 2017-01-23 initial release
  283. # 2017-02-10 added german docu
  284. # 2017-02-22 fixed bug when module cannot get reenabled after disabling
  285. # added disabledForIntervals
  286. # changed attribute WUInterval to interval
  287. # default interval 300
  288. # 2017-02-23 added attribute unit_windspeed
  289. # converted units rounded to 4 decimal places
  290. # 2017-03-16 implemented non-blocking mode
  291. # 2017-08-16 integrated RapidFire mode (thanks to Scooty66)
  292. # 2017-10-10 added windspdmph_avg2m, winddir_avg2m, windgustmph_10m,
  293. # windgustdir_10m (thanks to Aeroschmelz for reminding me)
  294. # timeout raised to 6s, fixed state error (thanks to mumpitzstuff)
  295. # 2017-10-16 fixed attributes
  296. # 2017-10-19 added set-command "update"
  297. #
  298. ################################################################################
  299. =pod
  300. =item helper
  301. =item summary sends weather data to Weather Underground
  302. =item summary_DE sendet Wetterdaten zu Weather Underground
  303. =begin html
  304. <a name="WUup"></a>
  305. <h3>WUup</h3>
  306. <ul>
  307. <a name="WUupdefine"></a>
  308. <b>Define</b>
  309. <ul>
  310. <br/>
  311. <code>define &lt;name&gt; WUup &lt;stationId&gt; &lt;password&gt;</code>
  312. <br/><br/>
  313. This module provides connection to
  314. <a href="https://www.wunderground.com">www.wunderground.com</a></br>
  315. to send data from your own weather station.<br/>
  316. </ul>
  317. <br/><br/>
  318. <a name="WUupset"></a>
  319. <b>Set-Commands</b><br/>
  320. <ul>
  321. <li><b>update</b> - send data to Weather Underground</li>
  322. </ul>
  323. <br/><br/>
  324. <a name="WUupget"></a>
  325. <b>Get-Commands</b><br/>
  326. <ul>
  327. <br/>
  328. - not implemented -<br/>
  329. </ul>
  330. <br/><br/>
  331. <a name="WUupattr"></a>
  332. <b>Attributes</b><br/><br/>
  333. <ul>
  334. <li><b><a href="#readingFnAttributes">readingFnAttributes</a></b></li>
  335. <li><b>interval</b> - Interval (seconds) to send data to
  336. www.wunderground.com.
  337. Will be adjusted to 300 (which is the default) if set to a value lower than 3.<br />
  338. If lower than 300, RapidFire mode will be used.</li>
  339. <li><b>disable</b> - disables the module</li>
  340. <li><b><a href="#disabledForIntervals">disabledForIntervals</a></b></li>
  341. <li><b>unit_windspeed</b> - change the units of your windspeed readings (m/s or km/h)</li>
  342. <li><b>wu....</b> - Attribute name corresponding to
  343. <a href="http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol">parameter name from api.</a>
  344. Each of these attributes contains information about weather data to be sent
  345. in format <code>sensorName:readingName</code><br/>
  346. Example: <code>attr WUup wutempf outside:temperature</code> will
  347. define the attribute wutempf and <br/>
  348. reading "temperature" from device "outside" will be sent to
  349. network as parameter "tempf" (which indicates current temperature)
  350. <br/>
  351. Units get converted to angloamerican system automatically
  352. (&deg;C -> &deg;F; km/h(m/s) -> mph; mm -> in; hPa -> inHg)<br/><br/>
  353. <u>The following information is supported:</u>
  354. <ul>
  355. <li>winddir - [0-360 instantaneous wind direction]</li>
  356. <li>windspeedmph - [mph instantaneous wind speed]</li>
  357. <li>windgustmph - [mph current wind gust, using software specific time period]</li>
  358. <li>windgustdir - [0-360 using software specific time period]</li>
  359. <li>windspdmph_avg2m - [mph 2 minute average wind speed mph]</li>
  360. <li>winddir_avg2m - [0-360 2 minute average wind direction]</li>
  361. <li>windgustmph_10m - [mph past 10 minutes wind gust mph]</li>
  362. <li>windgustdir_10m - [0-360 past 10 minutes wind gust direction]</li>
  363. <li>humidity - [&#37; outdoor humidity 0-100&#37;]</li>
  364. <li>dewptf- [F outdoor dewpoint F]</li>
  365. <li>tempf - [F outdoor temperature]</li>
  366. <li>rainin - [rain inches over the past hour)] -- the accumulated rainfall in the past 60 min</li>
  367. <li>dailyrainin - [rain inches so far today in local time]</li>
  368. <li>baromin - [barometric pressure inches]</li>
  369. <li>soiltempf - [F soil temperature]</li>
  370. <li>soilmoisture - [&#37;]</li>
  371. <li>solarradiation - [W/m&sup2;]</li>
  372. <li>UV - [index]</li>
  373. </ul>
  374. </li>
  375. </ul>
  376. <br/><br/>
  377. <b>Readings/Events:</b>
  378. <br/><br/>
  379. <ul>
  380. <li><b>data</b> - data string transmitted to www.wunderground.com</li>
  381. <li><b>response</b> - response string received from server</li>
  382. </ul>
  383. <br/><br/>
  384. <b>Notes</b><br/><br/>
  385. <ul>
  386. <li>Find complete api description
  387. <a href="http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol">here</a></li>
  388. <li>Have fun!</li><br/>
  389. </ul>
  390. </ul>
  391. =end html
  392. =begin html_DE
  393. <a name="WUup"></a>
  394. <h3>WUup</h3>
  395. <ul>
  396. <a name="WUupdefine"></a>
  397. <b>Define</b>
  398. <ul>
  399. <br/>
  400. <code>define &lt;name&gt; WUup &lt;stationId&gt; &lt;password&gt;</code>
  401. <br/><br/>
  402. Dieses Modul stellt eine Verbindung zu <a href="https://www.wunderground.com">www.wunderground.com</a></br>
  403. her, um Daten einer eigenen Wetterstation zu versenden..<br/>
  404. </ul>
  405. <br/><br/>
  406. <a name="WUupset"></a>
  407. <b>Set-Befehle</b><br/>
  408. <ul>
  409. <li><b>update</b> - sende Daten an Weather Underground</li>
  410. </ul>
  411. <br/><br/>
  412. <a name="WUupget"></a>
  413. <b>Get-Befehle</b><br/>
  414. <ul>
  415. <br/>
  416. - keine -<br/>
  417. </ul>
  418. <br/><br/>
  419. <a name="WUupattr"></a>
  420. <b>Attribute</b><br/><br/>
  421. <ul>
  422. <li><b><a href="#readingFnAttributes">readingFnAttributes</a></b></li>
  423. <li><b>interval</b> - Sendeinterval in Sekunden. Wird auf 300 (Default-Wert)
  424. eingestellt, wenn der Wert kleiner als 3 ist.<br />
  425. Wenn der Wert kleiner als 300 ist, wird der RapidFire Modus verwendet.</li>
  426. <li><b>disable</b> - deaktiviert das Modul</li>
  427. <li><b><a href="#disabledForIntervals">disabledForIntervals</a></b></li>
  428. <li><b>unit_windspeed</b> - gibt die Einheit der Readings für die
  429. Windgeschwindigkeiten an (m/s oder km/h)</li>
  430. <li><b>wu....</b> - Attributname entsprechend dem
  431. <a href="http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol">Parameternamen aus der API.</a><br />
  432. Jedes dieser Attribute enth&auml;lt Informationen &uuml;ber zu sendende Wetterdaten
  433. im Format <code>sensorName:readingName</code>.<br/>
  434. Beispiel: <code>attr WUup wutempf outside:temperature</code> definiert
  435. das Attribut wutempf und sendet das Reading "temperature" vom Ger&auml;t "outside" als Parameter "tempf"
  436. (welches die aktuelle Temperatur angibt).
  437. <br />
  438. Einheiten werden automatisch ins anglo-amerikanische System umgerechnet.
  439. (&deg;C -> &deg;F; km/h(m/s) -> mph; mm -> in; hPa -> inHg)<br/><br/>
  440. <u>Unterst&uuml;tzte Angaben</u>
  441. <ul>
  442. <li>Winddir - [0-360 momentane Windrichtung]</li>
  443. <li>Windspeedmph - [mph momentane Windgeschwindigkeit]</li>
  444. <li>Windgustmph - [mph aktuellen B&ouml;e, mit Software-spezifischem Zeitraum]</li>
  445. <li>Windgustdir - [0-360 mit Software-spezifischer Zeit]</li>
  446. <li>Windspdmph_avg2m - [mph durchschnittliche Windgeschwindigkeit innerhalb 2 Minuten]</li>
  447. <li>Winddir_avg2m - [0-360 durchschnittliche Windrichtung innerhalb 2 Minuten]</li>
  448. <li>Windgustmph_10m - [mph B&ouml;en der vergangenen 10 Minuten]</li>
  449. <li>Windgustdir_10m - [0-360 Richtung der B&ouml;en der letzten 10 Minuten]</li>
  450. <li>Feuchtigkeit - [&#37; Au&szlig;enfeuchtigkeit 0-100&#37;]</li>
  451. <li>Dewptf- [F Taupunkt im Freien]</li>
  452. <li>Tempf - [F Au&szlig;entemperatur]</li>
  453. <li>Rainin - [in Regen in der vergangenen Stunde]</li>
  454. <li>Dailyrainin - [in Regenmenge bisher heute]</li>
  455. <li>Baromin - [inHg barometrischer Druck]</li>
  456. <li>Soiltempf - [F Bodentemperatur]</li>
  457. <li>Bodenfeuchtigkeit - [&#37;]</li>
  458. <li>Solarradiation - [W/m&sup2;]</li>
  459. <li>UV - [Index]</li>
  460. </ul>
  461. </li>
  462. </ul>
  463. <br/><br/>
  464. <b>Readings/Events:</b>
  465. <br/><br/>
  466. <ul>
  467. <li><b>data</b> - Daten, die zu www.wunderground.com gesendet werden</li>
  468. <li><b>response</b> - Antwort, die vom Server empfangen wird</li>
  469. </ul>
  470. <br/><br/>
  471. <b>Notizen</b><br/><br/>
  472. <ul>
  473. <li>Die komplette API-Beschreibung findet sich
  474. <a href="http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol">hier</a></li>
  475. <li>Viel Spa&szlig;!</li><br/>
  476. </ul>
  477. </ul>
  478. =end html_DE
  479. =cut