59_WWO.pm 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. # $Id: 59_WWO.pm 8215 2015-03-15 07:32:49Z baumrasen $
  2. ##############################################################################
  3. #
  4. # 59_WWO.pm
  5. # Copyright by Andreas Vogt
  6. # e-mail: sourceforge at baumrasen dot de
  7. #
  8. # get current weather condition and forecast from worldweatheronline.com
  9. #
  10. # based / modified from 59_Weather.pm written by Dr. Boris Neubert
  11. # e-mail: omega at online dot de
  12. #
  13. # This file is part of fhem.
  14. #
  15. # Fhem is free software: you can redistribute it and/or modify
  16. # it under the terms of the GNU General Public License as published by
  17. # the Free Software Foundation, either version 2 of the License, or
  18. # (at your option) any later version.
  19. #
  20. # Fhem is distributed in the hope that it will be useful,
  21. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. # GNU General Public License for more details.
  24. #
  25. # You should have received a copy of the GNU General Public License
  26. # along with fhem. If not, see <http://www.gnu.org/licenses/>.
  27. #
  28. ##############################################################################
  29. package main;
  30. use strict;
  31. use warnings;
  32. use Time::HiRes qw(gettimeofday);
  33. use HttpUtils;
  34. # use Date::Calc qw(Day_of_Week Day_of_Week_to_Text);
  35. #
  36. # uses the Free Weather API: http://developer.worldweatheronline.com
  37. #
  38. # Mapping of current supported encodings
  39. my %DEFAULT_ENCODINGS = (
  40. en => 'latin1',
  41. da => 'latin1',
  42. de => 'latin1',
  43. es => 'latin1',
  44. fi => 'latin1',
  45. fr => 'latin1',
  46. it => 'latin1',
  47. ja => 'utf-8',
  48. ko => 'utf-8',
  49. nl => 'latin1',
  50. no => 'latin1',
  51. 'pt-BR' => 'latin1',
  52. ru => 'utf-8',
  53. sv => 'latin1',
  54. 'zh-CN' => 'utf-8',
  55. 'zh-TW' => 'utf-8',
  56. );
  57. #####################################
  58. sub WWO_Initialize($) {
  59. my ($hash) = @_;
  60. # Provider
  61. # $hash->{Clients} = undef;
  62. # Consumer
  63. $hash->{DefFn} = "WWO_Define";
  64. $hash->{UndefFn} = "WWO_Undef";
  65. $hash->{GetFn} = "WWO_Get";
  66. $hash->{SetFn} = "WWO_Set";
  67. #$hash->{AttrFn} = "WWO_Attr";
  68. #$hash->{AttrList}= "days:0,1,2,3,4,5 loglevel:0,1,2,3,4,5 localicons event-on-update-reading event-on-change-reading";
  69. #$hash->{AttrList}= "loglevel:0,1,2,3,4,5 localicons event-on-update-reading event-on-change-reading";
  70. $hash->{AttrList}= "localicons ".
  71. $readingFnAttributes;
  72. }
  73. ###################################
  74. sub latin1_to_utf8($) {
  75. # http://perldoc.perl.org/perluniintro.html, UNICODE IN OLDER PERLS
  76. my ($s)= @_;
  77. $s =~ s/([\x80-\xFF])/chr(0xC0|ord($1)>>6).chr(0x80|ord($1)&0x3F)/eg;
  78. return $s;
  79. }
  80. ###################################
  81. #sub temperature_in_c {
  82. # my ($temperature, $unitsystem)= @_;
  83. # return $unitsystem ne "SI" ? int(($temperature-32)*5/9+0.5) : $temperature;
  84. #}
  85. #sub wind_in_km_per_h {
  86. # my ($wind, $unitsystem)= @_;
  87. # return $unitsystem ne "SI" ? int(1.609344*$wind+0.5) : $wind;
  88. #}
  89. ###################################
  90. sub WWO_UpdateReading($$$$) {
  91. my ($hash,$prefix,$key,$value)= @_;
  92. #Debug "WWO: $prefix $key $value";
  93. #my $unitsystem= $hash->{READINGS}{unit_system}{VAL};
  94. #not needed
  95. if($key eq "date") {
  96. my @da = split("-", $value);
  97. $value = sprintf("%02d.%02d.",$da[2],$da[1]);
  98. $value= $value;
  99. }
  100. # elsif($key eq "tempMaxC") {
  101. # $key= "tempMaxC";
  102. # #$value= temperature_in_c($value,$unitsystem);
  103. # $value= $value;
  104. # } elsif($key eq "humidity") {
  105. # # standardize reading - allow generic logging of humidity.
  106. # $value=~ s/.*?(\d+).*/$1/; # extract numeric
  107. # }
  108. #Debug "WWO: $prefix $key $value";
  109. my $reading= $prefix . $key;
  110. readingsBulkUpdate($hash,$reading,$value);
  111. if($key eq "temp_C") {
  112. readingsBulkUpdate($hash,"temperature",$value); # additional entry for compatibility
  113. }
  114. # if($key eq "date") {
  115. # $reading = $prefix . "shortdate";
  116. # my @da = split("-", $value);
  117. # $value = left(Day_of_Week_to_Text(Day_of_Week($da[0], $da[1], $da[2]), 3),2);
  118. # readingsBulkUpdate($hash,$reading,$value); # additional entry
  119. # }
  120. if($key eq "weatherIconUrl") {
  121. # $value =~ s/.*\/([^.\/]*)\.*/$1/;
  122. $value =~ s/.*\/([^\/]+\.[^\.]+)/$1/;
  123. $reading= $prefix . "icon";
  124. readingsBulkUpdate($hash,$reading,$value); # additional entry for icon name
  125. }
  126. if($reading eq "windspeedKmph") {
  127. #$value=~ s/.*?(\d+).*/$1/; # extract numeric
  128. # readingsBulkUpdate($hash,"wind",wind_in_km_per_h($value,$unitsystem)); # additional entry for compatibility
  129. readingsBulkUpdate($hash,"wind",$value); # additional entry for compatibility
  130. }
  131. return 1;
  132. }
  133. ###################################
  134. sub WWO_RetrieveDataDirectly($)
  135. {
  136. my ($hash)= @_;
  137. my $location= $hash->{LOCATION};
  138. my $apikey = $hash->{APIKEY};
  139. my $days = $hash->{DAYS};
  140. $days = 5;
  141. #$location =~ s/([^\w()’*~!.-])/sprintf '%%%02x', ord $1/eg;
  142. my $lang= $hash->{LANG};
  143. my $fc = 0;
  144. my $fd = 0;
  145. my $days_addon = "&fx=no";
  146. if ($days > 0) {$days_addon = "&num_of_days=" . $days;}
  147. my $theurl = "http://api2.worldweatheronline.com/free/v1/weather.ashx?q=" . $location . "&extra=localObsTime&format=xml" . $days_addon . "&key=" . $apikey;
  148. #Debug "WWO: fecht url: $theurl";
  149. # my $xml = GetFileFromURL("http://free.worldweatheronline.com/feed/weather.ashx?q=" . $location . "&extra=localObsTime&format=xml" . $days_addon . "&key=" . $apikey);
  150. # my $xml = GetFileFromURL($theurl);
  151. my $xml = CustomGetFileFromURL(0, $theurl);
  152. #Debug "WWO: xml file content: $xml";
  153. # return 0 if( ! defined $xml || $xml eq "");
  154. if( ! defined $xml || $xml eq "") { # Log-Entry if nothing is returned
  155. Log3 $hash, 1,
  156. "WWO The API returns nothing. Look for an output of CustomGetFileFromURL above";
  157. return 0;
  158. }
  159. if ($xml eq "<h1>Developer Inactive</h1>") { # Log-Entry if API-Key not valid
  160. Log3 $hash, 1,
  161. "WWO The API returns, that the Developer is Inactive. Maybe the API-Key is not valid.";
  162. return 0;
  163. }
  164. if (index($xml, "error") != -1) { # check for an error-tag in the returned xml file
  165. Log3 $hash, 1,
  166. "WWO The API returns an error: $xml";
  167. return 0;
  168. }
  169. foreach my $llll (split("\/request>",$xml)) {
  170. #Debug "WWO: llll=\"$llll\"";
  171. foreach my $lll (split("\/current_condition>",$llll)) {
  172. #Debug "WWO: lll=\"$lll\"";
  173. $fc++;
  174. foreach my $ll (split("\/weather>",$lll)) {
  175. $fd++;
  176. # fc/fd = 1/1 > City/Type
  177. # fc/fd = 2/2 > current_condition
  178. # fc/fd = 3/3..5 > today, and following days
  179. #Debug "WWO: ll=\"$ll\"";
  180. foreach my $l (split(/<\/[\w]*>/,$ll)) { # with closing tag
  181. #Debug "WWO: all_line fc=\"$fc\" line=\"$l\"";
  182. next if($l eq ""); # skip empty lines
  183. next if($l =~ m/\/[\w]*>/); # skip closing tag lines
  184. next if($l =~ m/\?xml/); # skip xml declaration
  185. $l =~ s/<!\[CDATA\[//; # strip off <![CDATA[
  186. $l =~ s/\]\]>//; # strip of [[>
  187. #$l =~ s/<!\[CDATA\[([\w\d\s.\/:]*)]]>/$1/; # strip of [[>
  188. #Debug "WWO: clean1 fc=\"$fc\" line=\"$l\"";
  189. #Debug "WWO: 1fc=\"$fc\" fd=\"$fd\" line=\"$l\"";
  190. $l =~ s/(<[\w]*>)(<[\w]*>)/$2/; # remove first tag in case of two tags in line
  191. #Debug "WWO: 2fc=\"$fc\" fd=\"$fd\" line=\"$l\"";
  192. #$l =~ s/(\/|\?)?>$//; # strip off /> and >
  193. $l =~ s/<//; # strip off /> and >
  194. my ($tag,$value)= split(">", $l, 2); # split tag data=..... at the first blank
  195. #Debug "WWO: 3tag=\"$tag\" value=\"$value\"";
  196. #$fc= 0 if($tag eq "current_condition");
  197. #$fc++ if($tag eq "weather");
  198. #next if((!defined($value)) || ($value == ""));
  199. next if((!defined($value)) || (!defined($tag)) || ($tag eq "") || ($value eq ""));
  200. #Debug "WWO: CHECKED tag=\"$tag\" value=\"$value\"";
  201. my $prefix = "";
  202. if ($fc == 3) {
  203. $prefix= $fd ? "fc" . ($fd-3) ."_" : "";
  204. } else {
  205. $prefix= ""; # may be it would be helpfull to set to 'now_' or so
  206. }
  207. my $key= $tag;
  208. #$value=~ s/^data=\"(.*)\"$/$1/; # extract DATA from data="DATA"
  209. # if($DEFAULT_ENCODINGS{$lang} eq "latin1") {
  210. # $value= latin1_to_utf8($value); # latin1 -> UTF-8
  211. # }
  212. #Debug "WWO: prefix=\"$prefix\" tag=\"$tag\" value=\"$value\"";
  213. WWO_UpdateReading($hash,$prefix,$key,$value);
  214. }
  215. }
  216. }
  217. }
  218. return 1;
  219. }
  220. ###################################
  221. sub WWO_GetUpdate($)
  222. {
  223. my ($hash) = @_;
  224. if(!$hash->{LOCAL}) {
  225. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "WWO_GetUpdate", $hash, 1);
  226. }
  227. readingsBeginUpdate($hash);
  228. WWO_RetrieveDataDirectly($hash);
  229. my $temperature= $hash->{READINGS}{temperature}{VAL};
  230. my $humidity= $hash->{READINGS}{humidity}{VAL};
  231. my $pressure= $hash->{READINGS}{pressure}{VAL};
  232. my $wind= $hash->{READINGS}{wind}{VAL};
  233. my $val= "T: $temperature H: $humidity W: $wind P: $pressure";
  234. #Log GetLogLevel($hash->{NAME},4), "WWO: Log-->". $hash->{NAME} . ": $val";
  235. Log3 $hash, 4, "WWO ". $hash->{NAME} . ": $val";
  236. #Debug "Now i will push the changed notify";
  237. #$hash->{CHANGED}[0]= $val;
  238. #push @{$hash->{CHANGED}}, "$val";
  239. #$hash->{STATE}= $val;
  240. ##$hash->{STATE} = $val; # List overview
  241. ##$hash->{READINGS}{state}{VAL} = $val;
  242. ##$hash->{CHANGED}[0] = $val; # For notify
  243. ##Log 1, "WWO $val";
  244. ##addEvent($hash, $val);
  245. ##readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1)); # DoTrigger, because sub is called by a timer instead of dispatch
  246. readingsBulkUpdate($hash, "state", $val);
  247. readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1)); # DoTrigger, because sub is called by a timer instead of dispatch
  248. return 1;
  249. }
  250. # Perl Special: { $defs{WWO}{READINGS}{condition}{VAL} }
  251. # conditions: Mostly Cloudy, Overcast, Clear, Chance of Rain
  252. ###################################
  253. sub WWO_Get($@) {
  254. my ($hash, @a) = @_;
  255. return "argument is missing" if(int(@a) != 2);
  256. $hash->{LOCAL} = 1;
  257. WWO_GetUpdate($hash);
  258. delete $hash->{LOCAL};
  259. my $reading= $a[1];
  260. my $value;
  261. if(defined($hash->{READINGS}{$reading})) {
  262. $value= $hash->{READINGS}{$reading}{VAL};
  263. } else {
  264. return "no such reading: $reading";
  265. }
  266. return "$a[0] $reading => $value";
  267. }
  268. ###################################
  269. sub WWO_Set($@) {
  270. my ($hash, @a) = @_;
  271. my $cmd= $a[1];
  272. # usage check
  273. if((@a == 2) && ($a[1] eq "update")) {
  274. RemoveInternalTimer($hash);
  275. WWO_GetUpdate($hash);
  276. return undef;
  277. } else {
  278. return "Unknown argument $cmd, only update is valid";
  279. }
  280. }
  281. #####################################
  282. sub WWO_Define($$) {
  283. my ($hash, $def) = @_;
  284. # define <name> WWO <location> <apikey>
  285. # define MyWWO WWO Berlin,Germany xxxxxxxxxxxxxxxxxxxx 3600
  286. my @a = split("[ \t][ \t]*", $def);
  287. #return "syntax: define <name> WWO <location> <apikey> [interval]"
  288. return "syntax: define <name> WWO <location> <apikey> [interval]" # interval option not acitve
  289. #if(int(@a) < 3 && int(@a) > 4);
  290. if(int(@a) < 3 && int(@a) > 3); # interval option not acitve
  291. $hash->{STATE} = "Initialized";
  292. $hash->{fhem}{interfaces}= "temperature;humidity;wind";
  293. my $name = $a[0];
  294. my $location = $a[2];
  295. my $apikey = $a[3];
  296. my $interval = 3600;
  297. my $lang = "en";
  298. # if(int(@a)>=5) { $interval= $a[4]; }
  299. my $days = 5; # fixed to 5 days, right values are a number from 0-5
  300. $hash->{LOCATION} = $location;
  301. $hash->{INTERVAL} = $interval;
  302. $hash->{APIKEY} = $apikey;
  303. $hash->{LANG} = $lang;
  304. $hash->{DAYS} = $days;
  305. $hash->{READINGS}{current_date_time}{TIME}= TimeNow();
  306. $hash->{READINGS}{current_date_time}{VAL}= "none";
  307. $hash->{LOCAL} = 1;
  308. WWO_GetUpdate($hash);
  309. delete $hash->{LOCAL};
  310. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "WWO_GetUpdate", $hash, 0);
  311. return undef;
  312. }
  313. #####################################
  314. sub WWO_Undef($$) {
  315. my ($hash, $arg) = @_;
  316. RemoveInternalTimer($hash);
  317. return undef;
  318. }
  319. ######################################
  320. # sub
  321. # WWO_Attr(@)
  322. # {
  323. # my @a = @_;
  324. # my $attr= $a[2];
  325. #
  326. # if($a[0] eq "set") { # set attribute
  327. # if($attr eq "days") {
  328. # }
  329. # }
  330. # elsif($a[0] eq "del") { # delete attribute
  331. # if($attr eq "days") {
  332. # }
  333. # }
  334. #
  335. # return undef;
  336. #
  337. # }
  338. #####################################
  339. sub
  340. WWOIconIMGTag($$$) {
  341. use constant WWOURL => "http://www.worldweatheronline.com/images/wsymbols01_png_64/";
  342. use constant SIZE => "50%";
  343. my ($icon,$uselocal,$isday)= @_;
  344. my $url;
  345. my $style= "";
  346. if($uselocal) {
  347. # strip off path and extension
  348. $icon =~ s,^/images/wsymbols01_png_64/(.*)\.png$,$1,;
  349. if($isday) {
  350. $icon= "weather/${icon}"
  351. } else {
  352. $icon= "weather/${icon}_night"
  353. }
  354. $url= "fhem/icons/$icon";
  355. $style= " height=".SIZE." width=".SIZE;
  356. } else {
  357. $url= WWOURL . $icon;
  358. }
  359. return "<img src=\"$url\"$style>";
  360. }
  361. #####################################
  362. sub
  363. WWOAsHtml($)
  364. {
  365. my ($d) = @_;
  366. $d = "<none>" if(!$d);
  367. return "$d is not a WWO instance<br>"
  368. if(!$defs{$d} || $defs{$d}{TYPE} ne "WWO");
  369. my $uselocal= AttrVal($d,"localicons",0);
  370. my $isday;
  371. if(exists &isday) {
  372. $isday = isday();
  373. } else {
  374. $isday = 1; #($hour>6 && $hour<19);
  375. }
  376. my $ret = "<table>";
  377. $ret .= sprintf('<tr><td>%s</td><td><br></td></tr>',
  378. ReadingsVal($d, "query", ""));
  379. $ret .= sprintf('<tr><td>%s</td><td>%s %s<br>temp: %s °C, hum %s<br>wind: %s km/h %s<br>pressure: %s bar visibility: %s km</td></tr>',
  380. WWOIconIMGTag(ReadingsVal($d, "icon", ""),$uselocal,$isday),
  381. ReadingsVal($d, "localObsDateTime", ""),ReadingsVal($d, "weatherDesc", ""),
  382. ReadingsVal($d, "temp_C", ""), ReadingsVal($d, "humidity", ""),
  383. ReadingsVal($d, "windspeedKmph", ""), ReadingsVal($d, "winddir16Point", ""),
  384. ReadingsVal($d, "pressure", ""),ReadingsVal($d, "visibility", ""));
  385. for(my $i=0; $i<=4; $i++) {
  386. $ret .= sprintf('<tr><td>%s</td><td>%s: %s<br>min %s °C max %s °C<br>wind: %s km/h %s<br>precip: %s mm</td></tr>',
  387. WWOIconIMGTag(ReadingsVal($d, "fc${i}_icon", ""),$uselocal,$isday),
  388. ReadingsVal($d, "fc${i}_date", ""),
  389. ReadingsVal($d, "fc${i}_weatherDesc", ""),
  390. ReadingsVal($d, "fc${i}_tempMinC", ""), ReadingsVal($d, "fc${i}_tempMaxC", ""),
  391. ReadingsVal($d, "fc${i}_windspeedKmph", ""), ReadingsVal($d, "fc${i}_winddir16Point", ""),
  392. ReadingsVal($d, "fc${i}_precipMM", ""));
  393. }
  394. $ret .= "</table>";
  395. $ret .= "<br> Powered by <a href=\"[url]http://www.worldweatheronline.com/[/url]\" title=\"Free local weather content provider\" target=\"_blank\">World Weather Online</a> ";
  396. return $ret;
  397. }
  398. #####################################
  399. sub right{
  400. my ($string,$nr) = @_;
  401. return substr $string, -$nr, $nr;
  402. }
  403. #####################################
  404. sub left{
  405. my ($string,$nr) = @_;
  406. return substr $string, 0, $nr;
  407. }
  408. #####################################
  409. 1;
  410. =pod
  411. =begin html
  412. <a name="WWO"></a>
  413. <h3>WWO</h3>
  414. <ul>
  415. <br>
  416. <a name="WWOdefine"></a>
  417. <b>Define</b>
  418. <ul>
  419. <code>define &lt;name&gt; WWO &lt;location&gt; &lt;apikey&gt;</code><br>
  420. <br>
  421. Defines a virtual device for WWO forecasts.<br><br>
  422. A WWO device periodically gathers current and forecast weather conditions
  423. from worldweatheronline.com (the free api version)<br>
  424. You need to signup at <a href="http://developer.worldweatheronline.com">http://developer.worldweatheronline.com</a> to get an apikey)<br><br>
  425. The parameter <code>location</code> is the WOEID (WHERE-ON-EARTH-ID), go to
  426. <a href="http://www.worldweatheronline.com">http://www.worldweatheronline.com</a> to find it out for your valid location.<br><br>
  427. The natural language in which the forecast information appears is english.
  428. <br><br>
  429. The interval is set to update the values every hour.
  430. <br><br>
  431. Examples:
  432. <pre>
  433. define MyWeather WWO Berlin,Germany
  434. </pre>
  435. The module provides one additional function <code>WWOAsHtml</code>. The function return the HTML code for a
  436. vertically arranged weather forecast.
  437. <br><br>
  438. Example:
  439. <pre>
  440. define MyWeatherWeblink weblink htmlCode { WWOAsHtml("MyWeather") }
  441. </pre>
  442. </ul>
  443. <br>
  444. <a name="Weatherset"></a>
  445. <b>Set </b>
  446. <ul>
  447. <code>set &lt;name&gt; update</code><br><br>
  448. Forces the retrieval of the weather data. The next automatic retrieval is scheduled to occur
  449. <code>interval</code> seconds later.<br><br>
  450. </ul>
  451. <br>
  452. <a name="Weatherget"></a>
  453. <b>Get</b>
  454. <ul>
  455. <code>get &lt;name&gt; &lt;reading&gt;</code><br><br>
  456. Valid readings and their meaning (? can be one of 0, 1, 2, 3, 4, 5 and stands
  457. for today, tomorrow, etc. - with 'fc?_' or without! - without is meaning 'current condition'):<br>
  458. <table>
  459. <tr><td>cloudcover</td><td>cloudcover in percent</td></tr>
  460. <tr><td>current_date_time</td><td>last update of forecast on server</td></tr>
  461. <tr><td>fc?_date</td><td>date of the forecast condition - not valid without 'fc?'</td></tr>
  462. <tr><td>fc?_icon</td><td>name of the forecasticon</td></tr>
  463. <tr><td>fc?_precipMM</td><td>preciption for day</td></tr>
  464. <tr><td>fc?_tempMaxC</td><td>forecasted daily high in degrees centigrade</td></tr>
  465. <tr><td>fc?_tempMaxF</td><td>forecasted daily high in degrees fahrenheit</td></tr>
  466. <tr><td>fc?_tempMinC</td><td>forecasted daily low in degrees centigrade</td></tr>
  467. <tr><td>fc?_tempMinF</td><td>forecasted daily low in degrees fahrenheit</td></tr>
  468. <tr><td>fc?_weatherCode</td><td>weathercode</td></tr>
  469. <tr><td>fc?_weatherDesc</td><td>short weather desciption</td></tr>
  470. <tr><td>fc?_weatherIconUrl</td><td>full url to the weathericonfile</td></tr>
  471. <tr><td>fc?_winddir16Point</td><td>winddirection with 16 points</td></tr>
  472. <tr><td>fc?_winddirDegree</td><td>windirection in degrees</td></tr>
  473. <tr><td>fc?_winddirection</td><td>winddirection</td></tr>
  474. <tr><td>fc?_windspeedKmph</td><td>windspeed in km/h</td></tr>
  475. <tr><td>fc?_windspeedMiles</td><td>windspeed in miles/h</td></tr>
  476. <tr><td>humidity</td><td>current humidity in %</td></tr>
  477. <tr><td>localObsDateTime</td><td>local time of observation</td></tr>
  478. <tr><td>observation_time</td><td>time of observation</td></tr>
  479. <tr><td>pressure</td><td>air pressure in hPa</td></tr>
  480. <tr><td>query</td><td>returns the queried location</td></tr>
  481. <tr><td>temperature</td><td>current temperature in degrees centigrade</td></tr>
  482. <tr><td>visibility</td><td>current visibilit in km</td></tr>
  483. </table>
  484. </ul>
  485. <br>
  486. <a name="Weatherattr"></a>
  487. <b>Attributes</b>
  488. <ul>
  489. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  490. </ul>
  491. <br>
  492. </ul>
  493. =end html
  494. =cut