59_PROPLANTA.pm 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  1. ####################################################################################################
  2. # $Id: 59_PROPLANTA.pm 17079 2018-08-02 17:47:03Z tupol $
  3. #
  4. # 59_PROPLANTA.pm
  5. #
  6. # (c) 2014 Torsten Poitzsch
  7. # (c) 2014-2016 tupol http://forum.fhem.de/index.php?action=profile;u=5432
  8. #
  9. # Weather forecast values for 12 days are captured from www.proplanta.de
  10. # inspired by 23_KOSTALPIKO.pm
  11. #
  12. # Copyright notice
  13. #
  14. # This script is free software; you can redistribute it and/or modify
  15. # it under the terms of the GNU General Public License as published by
  16. # the Free Software Foundation; either version 2 of the License, or
  17. # (at your option) any later version.
  18. #
  19. # The GNU General Public License can be found at
  20. # http://www.gnu.org/copyleft/gpl.html.
  21. # A copy is found in the text file GPL.txt and important notices to the license
  22. # from the author is found in LICENSE.txt distributed with these scripts.
  23. #
  24. # This script is distributed in the hope that it will be useful,
  25. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  27. # GNU General Public License for more details.
  28. #
  29. # This copyright notice MUST APPEAR in all copies of the script!
  30. #
  31. ####################################################################################################
  32. ###############################################
  33. # parser for the weather data
  34. package MyProplantaParser;
  35. use base qw(HTML::Parser);
  36. use Time::HiRes qw(usleep);
  37. our @texte = ();
  38. my $lookupTag = "span|b";
  39. my $curTag = "";
  40. my $curReadingName = "";
  41. my $curRowID = "";
  42. my $curCol = 0;
  43. our $startDay = 0;
  44. my $curTextPos = 0;
  45. my $curReadingType = 0;
  46. # 1 = span|b Text, 2 = readingName, 3 = Tag-Type
  47. # Tag-Types:
  48. # 1 = Number Col 3
  49. # 2 = Number Col 2-5
  50. # 3 = Number Col 2|4|6|8
  51. # 4 = Intensity-Text Col 2-5
  52. # 5 = Time Col 2-5
  53. # 6 = Time Col 3
  54. # 7 = alternative text of image Col 2-5 (weather state)
  55. # 8 = MinMaxNummer Col 3 (cloud base)
  56. # 9 = Date Col 2-5 / bold
  57. # 10 = alternative text of Col 3 (wind direction)
  58. # 11 = alternative text of image Col 3 (current weather state)
  59. # 12 = Text Col 3
  60. my @knownNoneIDs = ( ["Temperatur", "temperature", 1]
  61. ,["relative Feuchte", "humidity", 1]
  62. ,["Sichtweite", "visibility", 1]
  63. ,["Wetterzustand", "weather", 11]
  64. ,["Windrichtung", "windDir", 10]
  65. ,["Windgeschwindigkeit", "wind", 1]
  66. ,["Luftdruck", "pressure", 1]
  67. ,["Taupunkt", "dewPoint", 1]
  68. ,["Uhrzeit", "obsTime", 6]
  69. ,["Höhe der", "cloudBase", 8]
  70. ,["Höhe der", "cloudBase", 8]
  71. );
  72. # 1 = Tag-ID, 2 = readingName, 3 = Tag-Type (see above)
  73. my @knownIDs = (
  74. ["DATUM", "date", 9]
  75. ,["TMAX", "tempMax", 2]
  76. ,["TMIN", "tempMin", 2]
  77. ,["NW", "chOfRainDay", 2]
  78. ,["NW_Nacht", "chOfRainNight", 2]
  79. ,["BF", "frost", 4]
  80. ,["VERDUNST", "evapor", 4]
  81. ,["TAUBILDUNG", "dew", 4]
  82. ,["SD", "sun", 2]
  83. ,["UV", "uv", 2]
  84. ,["GS", "rad", 3]
  85. ,["WETTER_ID", "weather", 7]
  86. ,["WETTER_ID_MORGENS", "weatherMorning", 7]
  87. ,["WETTER_ID_TAGSUEBER", "weatherDay", 7]
  88. ,["WETTER_ID_ABENDS", "weatherEvening", 7]
  89. ,["WETTER_ID_NACHT", "weatherNight", 7]
  90. ,["WETTER_ID_0", "weather00", 7]
  91. ,["WETTER_ID_3", "weather03", 7]
  92. ,["WETTER_ID_6", "weather06", 7]
  93. ,["WETTER_ID_9", "weather09", 7]
  94. ,["WETTER_ID_12", "weather12", 7]
  95. ,["WETTER_ID_15", "weather15", 7]
  96. ,["WETTER_ID_18", "weather18", 7]
  97. ,["WETTER_ID_21", "weather21", 7]
  98. ,["T_0", "temp00", 2]
  99. ,["T_3", "temp03", 2]
  100. ,["T_6", "temp06", 2]
  101. ,["T_9", "temp09", 2]
  102. ,["T_12", "temp12", 2]
  103. ,["T_15", "temp15", 2]
  104. ,["T_18", "temp18", 2]
  105. ,["T_21", "temp21", 2]
  106. ,["NW_0", "chOfRain00", 2]
  107. ,["NW_3", "chOfRain03", 2]
  108. ,["NW_6", "chOfRain06", 2]
  109. ,["NW_9", "chOfRain09", 2]
  110. ,["NW_12", "chOfRain12", 2]
  111. ,["NW_15", "chOfRain15", 2]
  112. ,["NW_18", "chOfRain18", 2]
  113. ,["NW_21", "chOfRain21", 2]
  114. ,["NS_0", "rain00", 2]
  115. ,["NS_3", "rain03", 2]
  116. ,["NS_6", "rain06", 2]
  117. ,["NS_9", "rain09", 2]
  118. ,["NS_12", "rain12", 2]
  119. ,["NS_15", "rain15", 2]
  120. ,["NS_18", "rain18", 2]
  121. ,["NS_21", "rain21", 2]
  122. ,["NS_24H", "rain", 2]
  123. ,["BD_0", "cloud00", 2]
  124. ,["BD_3", "cloud03", 2]
  125. ,["BD_6", "cloud06", 2]
  126. ,["BD_9", "cloud09", 2]
  127. ,["BD_12", "cloud12", 2]
  128. ,["BD_15", "cloud15", 2]
  129. ,["BD_18", "cloud18", 2]
  130. ,["BD_21", "cloud21", 2]
  131. ,["MA", "moonRise", 5]
  132. ,["MU", "moonSet", 5]
  133. ,["WGRAD_0", "windDir00", 2]
  134. ,["WGRAD_3", "windDir03", 2]
  135. ,["WGRAD_6", "windDir06", 2]
  136. ,["WGRAD_9", "windDir09", 2]
  137. ,["WGRAD_12", "windDir12", 2]
  138. ,["WGRAD_15", "windDir15", 2]
  139. ,["WGRAD_18", "windDir18", 2]
  140. ,["WGRAD_21", "windDir21", 2]
  141. ,["WGESCHW_0", "wind00", 2]
  142. ,["WGESCHW_3", "wind03", 2]
  143. ,["WGESCHW_6", "wind06", 2]
  144. ,["WGESCHW_9", "wind09", 2]
  145. ,["WGESCHW_12", "wind12", 2]
  146. ,["WGESCHW_15", "wind15", 2]
  147. ,["WGESCHW_18", "wind18", 2]
  148. ,["WGESCHW_21", "wind21", 2]
  149. ,["BGESCHW_0", "gust00", 2]
  150. ,["BGESCHW_3", "gust03", 2]
  151. ,["BGESCHW_6", "gust06", 2]
  152. ,["BGESCHW_9", "gust09", 2]
  153. ,["BGESCHW_12", "gust12", 2]
  154. ,["BGESCHW_15", "gust15", 2]
  155. ,["BGESCHW_18", "gust18", 2]
  156. ,["BGESCHW_21", "gust21", 2]
  157. );
  158. my %intensity = ( "keine" => 0
  159. ,"nein" => 0
  160. ,"gering" => 1
  161. ,"leicht" => 1
  162. ,"ja" => 1
  163. ,"mäßig" => 2
  164. ,"mäßig" => 2
  165. ,"stark" => 3
  166. );
  167. my %winddir = ( "Nord" => 0
  168. ,"Nord-Nordost" => 23
  169. ,"Nordost" => 45
  170. ,"Ost-Nordost" => 68
  171. ,"Ost" => 90
  172. ,"Ost-Südost" => 113
  173. ,"Ost-Südost" => 113
  174. ,"Südost" => 135
  175. ,"Südost" => 135
  176. ,"Süd-Südost" => 158
  177. ,"Süd-Südost" => 158
  178. ,"Süd" => 180
  179. ,"Süd" => 180
  180. ,"Süd-Südwest" => 203
  181. ,"Süd-Südwest" => 203
  182. ,"Südwest" => 225
  183. ,"Südwest" => 225
  184. ,"West-Südwest" => 248
  185. ,"West-Südwest" => 248
  186. ,"West" => 270
  187. ,"West-Nordwest" => 303
  188. ,"Nordwest" => 325
  189. ,"Nord-Nordwest" => 348
  190. );
  191. ##############################################
  192. sub get_wday($)
  193. {
  194. my ($date) = @_;
  195. my @wday_txt = qw(So Mo Di Mi Do Fr Sa);
  196. my @th=localtime $date;
  197. return $wday_txt [$th[6]];
  198. }
  199. ##############################################
  200. # here HTML::text/start/end are overridden
  201. sub text
  202. {
  203. my ( $self, $text ) = @_;
  204. my $found = 0;
  205. my $readingName;
  206. # Wait 1ms to reduce CPU load and hence blocking of FHEM by it (workaround until a better solution is available)
  207. usleep (1000);
  208. if ( $curTag =~ $lookupTag ) {
  209. $curTextPos++;
  210. $text =~ s/^\s+//; # trim string
  211. $text =~ s/\s+$//;
  212. $text =~ s/0/0/g; # replace 0
  213. $text =~ s/1/1/g; # replace 1
  214. $text =~ s/2/2/g; # replace 2
  215. $text =~ s/3/3/g; # replace 3
  216. $text =~ s/4/4/g; # replace 4
  217. $text =~ s/5/5/g; # replace 5
  218. $text =~ s/6/6/g; # replace 6
  219. $text =~ s/7/7/g; # replace 7
  220. $text =~ s/8/8/g; # replace 8
  221. $text =~ s/9/9/g; # replace 9
  222. # Tag-Type 0 = Check for readings without tag-ID (current readings)
  223. if ($curReadingType == 0) {
  224. if ($startDay == 0 && $curCol == 1 && $curTextPos == 1)
  225. {
  226. foreach my $r (@knownNoneIDs)
  227. {
  228. if ( $$r[0] eq $text )
  229. {
  230. $curReadingName = $$r[1];
  231. $curReadingType = $$r[2];
  232. last;
  233. }
  234. }
  235. }
  236. }
  237. # Tag-Type 1 = Number Col 3
  238. elsif ($curReadingType == 1) {
  239. if ( $curCol == 3 )
  240. {
  241. $readingName = $curReadingName;
  242. if ( $text =~ m/([-,\+]?\d+[,\.]?\d*)/ )
  243. {
  244. $text = $1;
  245. $text =~ tr/,/./; # komma durch punkt ersetzen
  246. }
  247. push( @texte, $readingName."|".$text );
  248. $curReadingType = 0;
  249. }
  250. }
  251. # Tag-Type 2 = Number Col 2-5
  252. elsif ($curReadingType == 2) {
  253. if ( 1 < $curCol && $curCol <= 5 )
  254. {
  255. $readingName = "fc".($startDay+$curCol-2)."_".$curReadingName;
  256. if ( $text =~ m/([-+]?\d+[,.]?\d*)/ )
  257. {
  258. $text = $1;
  259. $text =~ tr/,/./; # komma durch punkt ersetzen
  260. }
  261. push( @texte, $readingName."|".$text );
  262. }
  263. }
  264. # Tag-Type 3 = Number Col 2|4|6|8
  265. elsif ($curReadingType == 3) {
  266. if ( 2 <= $curCol && $curCol <= 5 )
  267. {
  268. if ( $curTextPos % 2 == 1 )
  269. {
  270. $readingName = "fc".($startDay+$curCol-2)."_".$curReadingName;
  271. $text =~ tr/,/./; # komma durch punkt ersetzen
  272. push( @texte, $readingName."|".$text );
  273. }
  274. }
  275. }
  276. # Tag-Type 4 = Intensity-Text Col 2-5
  277. elsif ($curReadingType == 4) {
  278. if ( 2 <= $curCol && $curCol <= 5 )
  279. {
  280. $readingName = "fc".($startDay+$curCol-2)."_".$curReadingName;
  281. $text = $intensity{$text} if defined $intensity{$text};
  282. push( @texte, $readingName . "|" . $text );
  283. }
  284. }
  285. # Tag-Type 5 = Time Col 2-5
  286. elsif ($curReadingType == 5) {
  287. if ( 2 <= $curCol && $curCol <= 5 )
  288. {
  289. $readingName = "fc".($startDay+$curCol-2)."_".$curReadingName;
  290. if ( $text =~ m/([012-]?[-0-9][.:][-0-5][-0-9])/ )
  291. {
  292. $text = $1;
  293. $text =~ tr/./:/; # Punkt durch Doppelpunkt ersetzen
  294. }
  295. push( @texte, $readingName."|".$text );
  296. }
  297. }
  298. # Tag-Type 6 = Time Col 3
  299. elsif ($curReadingType == 6) {
  300. if ( $curCol == 3 )
  301. {
  302. $readingName = $curReadingName;
  303. if ( $text =~ m/([012-]?[-0-9][.:][-0-5][-0-9])/ )
  304. {
  305. $text = $1;
  306. $text =~ tr/./:/; # Punkt durch Doppelpunkt ersetzen
  307. }
  308. push( @texte, $readingName."|".$text );
  309. }
  310. }
  311. # Tag-Type 8 = MinMaxNumber Col 3
  312. elsif ($curReadingType == 8) {
  313. if ( $curCol == 3 )
  314. {
  315. $readingName = $curReadingName;
  316. if ( $text =~ m/(\d+)\s*-\s*(\d+)/ )
  317. {
  318. push( @texte, $readingName."Min|".$1 );
  319. push( @texte, $readingName."Max|".$2 );
  320. }
  321. else
  322. {
  323. push( @texte, $readingName."Min|-" );
  324. push( @texte, $readingName."Max|-" );
  325. }
  326. }
  327. }
  328. # Tag-Type 9 = Date Col 2-5
  329. elsif ($curReadingType == 9 && $curTag eq "b") {
  330. if ( 1 < $curCol && $curCol <= 5 ) {
  331. $readingName = "fc".($startDay+$curCol-2)."_".$curReadingName;
  332. push( @texte, $readingName."|".$text );
  333. }
  334. }
  335. # Tag-Type 12 = Text Col 3
  336. elsif ($curReadingType == 12) {
  337. if ( $curCol == 3 )
  338. {
  339. $readingName = $curReadingName;
  340. push( @texte, $readingName."|".$text );
  341. $curReadingType = 0;
  342. }
  343. }
  344. }
  345. }
  346. ##############################################
  347. sub start
  348. {
  349. my ( $self, $tagname, $attr, $attrseq, $origtext ) = @_;
  350. $curTag = $tagname;
  351. if ( $tagname eq "tr" ) {
  352. $curReadingType = 0;
  353. $curCol = 0;
  354. $curTextPos = 0;
  355. if ( defined( $attr->{id} ) ) {
  356. foreach my $r (@knownIDs) {
  357. if ( $$r[0] eq $attr->{id} ) {
  358. $curReadingName = $$r[1];
  359. $curReadingType = $$r[2];
  360. last;
  361. }
  362. }
  363. }
  364. }
  365. elsif ($tagname eq "td") {
  366. $curCol++;
  367. $curTextPos = 0;
  368. }
  369. #wetterstate and icon - process immediately
  370. elsif ($tagname eq "img"
  371. && ( $curReadingType == 7 && 2 <= $curCol && $curCol <= 5
  372. || $curReadingType == 11 && $curCol == 3) ) {
  373. # process alternative text
  374. $readingName = $curReadingName;
  375. $readingName = "fc" . ($startDay+$curCol-2) . "_" . $readingName if $curReadingType == 7;
  376. $text = $attr->{alt};
  377. $text =~ s/Wetterzustand: //;
  378. # $text =~ s/ö/oe/;
  379. # $text =~ s/ä/ae/;
  380. # $text =~ s/ü/ue/;
  381. # $text =~ s/ß/ss/;
  382. push( @texte, $readingName . "|" . $text );
  383. # Image URL
  384. push( @texte, $readingName."Icon" . "|" . $attr->{src} );
  385. }
  386. #wind direction - process immediately
  387. elsif ($tagname eq "img" && $curReadingType == 10 && $curCol == 3 ) {
  388. # process alternative text
  389. $readingName = $curReadingName;
  390. $text = $attr->{alt};
  391. $text =~ s/Windrichtung: //;
  392. $text = $winddir{$text} if defined $winddir{$text};
  393. # $text =~ s/ö/oe/;
  394. # $text =~ s/ä/ae/;
  395. # $text =~ s/ü/ue/;
  396. # $text =~ s/ß/ss/;
  397. push( @texte, $readingName . "|" . $text );
  398. # Image URL
  399. push( @texte, $readingName."Icon" . "|" . $attr->{src} );
  400. }
  401. }
  402. ##############################################
  403. sub end
  404. {
  405. my ( $self, $tagname, $attr, $attrseq, $origtext ) = @_;
  406. $curTag = "";
  407. if ( $tagname eq "tr" ) {
  408. $curReadingType = 0
  409. };
  410. }
  411. ##############################################
  412. package main;
  413. use strict;
  414. use feature qw/say switch/;
  415. use Encode qw/from_to/;
  416. use warnings;
  417. my $missingModul;
  418. eval "use LWP::UserAgent;1" or $missingModul .= "LWP::UserAgent ";
  419. eval "use HTTP::Request;1" or $missingModul .= "HTTP::Request ";
  420. eval "use HTML::Parser;1" or $missingModul .= "HTML::Parser ";
  421. eval "use MIME::Base64;1" or $missingModul .= "MIME::Base64 ";
  422. require 'Blocking.pm';
  423. require 'HttpUtils.pm';
  424. use vars qw($readingFnAttributes);
  425. use vars qw(%defs);
  426. my $MODUL = "PROPLANTA";
  427. # my %url_template_1 =( "de" => "http://www.proplanta.de/Wetter/LOKALERORT-Wetter.html"
  428. # , "at" => "http://www.proplanta.de/Agrarwetter-Oesterreich/LOKALERORT/"
  429. # , "ch" => "http://www.proplanta.de/Agrarwetter-Schweiz/LOKALERORT/"
  430. # , "fr" => "http://www.proplanta.de/Agrarwetter-Frankreich/LOKALERORT.html"
  431. # , "it" => "http://www.proplanta.de/Agrarwetter-Italien/LOKALERORT.html"
  432. # );
  433. my %url_template = ( "de" => "https://www.proplanta.de/Wetter/profi-wetter.php?SITEID=60&PLZ=LOKALERORT&STADT=LOKALERORT&WETTERaufrufen=stadt&Wtp=&SUCHE=Wetter&wT="
  434. , "at" => "https://www.proplanta.de/Wetter-Oesterreich/profi-wetter-at.php?SITEID=70&PLZ=LOKALERORT&STADT=LOKALERORT&WETTERaufrufen=stadt&Wtp=&SUCHE=Wetter&wT="
  435. , "ch" => "https://www.proplanta.de/Wetter-Schweiz/profi-wetter-ch.php?SITEID=80&PLZ=LOKALERORT&STADT=LOKALERORT&WETTERaufrufen=stadt&Wtp=&SUCHE=Wetter&wT="
  436. , "fr" => "https://www.proplanta.de/Wetter-Frankreich/profi-wetter-fr.php?SITEID=50&PLZ=LOKALERORT&STADT=LOKALERORT&WETTERaufrufen=stadt&Wtp=&SUCHE=Wetter-Frankreich&wT="
  437. , "it" => "https://www.proplanta.de/Wetter-Italien/profi-wetter-it.php?SITEID=40&PLZ=LOKALERORT&STADT=LOKALERORT&WETTERaufrufen=stadt&Wtp=&SUCHE=Wetter-Italien&wT="
  438. );
  439. ########################################
  440. sub PROPLANTA_Log($$$)
  441. {
  442. my ( $hash, $loglevel, $text ) = @_;
  443. my $xline = ( caller(0) )[2];
  444. my $xsubroutine = ( caller(1) )[3];
  445. my $sub = ( split( ':', $xsubroutine ) )[2];
  446. $sub =~ s/PROPLANTA_//;
  447. my $instName = ( ref($hash) eq "HASH" ) ? $hash->{NAME} : $hash;
  448. Log3 $instName, $loglevel, "$MODUL $instName: $sub.$xline " . $text;
  449. }
  450. ###################################
  451. sub PROPLANTA_Initialize($)
  452. {
  453. my ($hash) = @_;
  454. $hash->{DefFn} = "PROPLANTA_Define";
  455. $hash->{UndefFn} = "PROPLANTA_Undef";
  456. $hash->{SetFn} = "PROPLANTA_Set";
  457. $hash->{AttrList} = "INTERVAL URL disable:0,1 forecastDays:4,7,11,14 " . $readingFnAttributes;
  458. }
  459. ###################################
  460. sub PROPLANTA_Define($$)
  461. {
  462. my ( $hash, $def ) = @_;
  463. my $name = $hash->{NAME};
  464. my $lang = "";
  465. my @a = split( "[ \t][ \t]*", $def );
  466. return "Error: Perl moduls ".$missingModul."are missing on this system"
  467. if $missingModul;
  468. return "Wrong syntax: use define <name> PROPLANTA [City] [CountryCode]" if int(@a) > 4;
  469. $lang = "de" if int(@a) == 3;
  470. $lang = lc( $a[3] ) if int(@a) == 4;
  471. if ( $lang ne "")
  472. { # {my $test="http://www.proplanta.de/Wetter/LOKALERORT-Wetter.html";; $test =~ s/LOKALERORT/München/g;; return $test;;}
  473. return "Wrong country code '$lang': use " . join(" | ", keys( %url_template ) ) unless defined( $url_template{$lang} );
  474. my $URL = $url_template{$lang};
  475. my $ort_encode= $a[2];
  476. # change Umlaute from UTF8 in Percent-encode
  477. $ort_encode =~ s/Ä|Ä/%C4/g;
  478. $ort_encode =~ s/Ö|Ö/%D6/g;
  479. $ort_encode =~ s/Ü|Ü/%DC/g;
  480. $ort_encode =~ s/ß|ß/%DF/g;
  481. $ort_encode =~ s/ä|ä/%E4/g;
  482. $ort_encode =~ s/ö|ö/%F6/g;
  483. $ort_encode =~ s/ü|ü/%FC/g;
  484. $URL =~ s/LOKALERORT/$ort_encode/g;
  485. $hash->{URL} = $URL;
  486. # $URL = $url_template_2{$lang};
  487. # $URL =~ s/LOKALERORT/$ort/g;
  488. # $hash->{URL2} = $URL;
  489. }
  490. $hash->{STATE} = "Initializing";
  491. $hash->{fhem}{LOCAL} = 0;
  492. $hash->{INTERVAL} = 3600;
  493. $hash->{fhem}{modulVersion} = '$Date: 2018-08-02 19:47:03 +0200 (Thu, 02 Aug 2018) $';
  494. RemoveInternalTimer($hash);
  495. #Get first data after 32 seconds
  496. InternalTimer( gettimeofday() + 32, "PROPLANTA_Start", $hash, 0 );
  497. return undef;
  498. }
  499. #####################################
  500. sub PROPLANTA_Undef($$)
  501. {
  502. my ( $hash, $arg ) = @_;
  503. RemoveInternalTimer( $hash );
  504. BlockingKill( $hash->{helper}{RUNNING_PID} ) if ( defined( $hash->{helper}{RUNNING_PID} ) );
  505. return undef;
  506. }
  507. #####################################
  508. sub PROPLANTA_Set($@)
  509. {
  510. my ($hash, $name, $cmd, @val) = @_;
  511. # my $reUINT = '^([\\+]?\\d+)$';
  512. my $usage = "Unknown argument $cmd, choose one of update:noArg ";
  513. return $usage unless defined $cmd;
  514. if ( $cmd eq "?" ) {
  515. return $usage;
  516. }
  517. elsif ( $cmd eq "update" ) {
  518. Log3 $name, 3, "PROPLANTA: set $name $cmd ".join(" ", @val);
  519. $hash->{fhem}{LOCAL} = 1;
  520. PROPLANTA_Start($hash);
  521. $hash->{fhem}{LOCAL} = 0;
  522. }
  523. else {
  524. return $usage;
  525. }
  526. return;
  527. }
  528. #####################################
  529. # acquires the html page
  530. sub PROPLANTA_HtmlAcquire($$)
  531. {
  532. my ($hash, $URL) = @_;
  533. my $name = $hash->{NAME};
  534. return unless (defined($hash->{NAME}));
  535. PROPLANTA_Log $hash, 4, "Start capturing of $URL";
  536. #$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0;
  537. my $err_log = "";
  538. my $agent = LWP::UserAgent->new( env_proxy => 1, keep_alive => 1, protocols_allowed => ['http', 'https'], timeout => 10
  539. , agent => "Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko" );
  540. my $request = HTTP::Request->new( GET => $URL );
  541. my $response = $agent->request($request);
  542. $err_log = "Can't get $URL -- " . $response->status_line
  543. unless $response->is_success;
  544. if ( $err_log ne "" )
  545. {
  546. readingsSingleUpdate($hash, "lastConnection", $response->status_line, 1);
  547. PROPLANTA_Log $hash, 1, "Error: $err_log";
  548. return "Error|Error " . $response->status_line;
  549. }
  550. PROPLANTA_Log $hash, 4, length($response->content)." characters captured";
  551. my $returnString = $response->content;
  552. from_to($returnString,"iso-8859-1","utf8", Encode::FB_QUIET);
  553. return $returnString;
  554. }
  555. #####################################
  556. sub PROPLANTA_Start($)
  557. {
  558. my ($hash) = @_;
  559. my $name = $hash->{NAME};
  560. return unless (defined($hash->{NAME}));
  561. $hash->{INTERVAL} = AttrVal( $name, "INTERVAL", $hash->{INTERVAL} );
  562. readingsSingleUpdate($hash, "state", "disabled", 1) if AttrVal($name, "disable", 0 ) == 1;
  563. if($hash->{INTERVAL} > 0) {
  564. # reset timer if interval is defined
  565. RemoveInternalTimer( $hash );
  566. InternalTimer(gettimeofday() + $hash->{INTERVAL}, "PROPLANTA_Start", $hash, 1 );
  567. return undef if AttrVal($name, "disable", 0 ) == 1 && !$hash->{fhem}{LOCAL};
  568. }
  569. if ( AttrVal( $name, 'URL', '') eq '' && not defined( $hash->{URL} ) )
  570. {
  571. PROPLANTA_Log $hash, 3, "missing URL";
  572. return;
  573. }
  574. # "Set update"-action will kill a running update child process
  575. if (defined ($hash->{helper}{RUNNING_PID}) && $hash->{fhem}{LOCAL})
  576. {
  577. BlockingKill($hash->{helper}{RUNNING_PID});
  578. delete( $hash->{helper}{RUNNING_PID} );
  579. PROPLANTA_Log $hash, 4, "Killing old forked process";
  580. }
  581. unless (defined ($hash->{helper}{RUNNING_PID}))
  582. {
  583. $hash->{helper}{RUNNING_PID} =
  584. BlockingCall(
  585. "PROPLANTA_Run", # callback worker task
  586. $name, # name of the device
  587. "PROPLANTA_Done", # callback result method
  588. 120, # timeout seconds
  589. "PROPLANTA_Aborted", # callback for abortion
  590. $hash ); # parameter for abortion
  591. PROPLANTA_Log $hash, 4, "Start forked process to capture html";
  592. }
  593. else
  594. {
  595. PROPLANTA_Log $hash, 1, "Could not start forked process, old process still running";
  596. }
  597. }
  598. #####################################
  599. sub PROPLANTA_Run($)
  600. {
  601. eval "setpriority( 0, 0, 10);"; #work-around for old perl
  602. my ($name) = @_;
  603. my $ptext=$name;
  604. my $URL;
  605. my $response;
  606. return unless ( defined($name) );
  607. my $hash = $defs{$name};
  608. return unless (defined($hash->{NAME}));
  609. my $readingStartTime = time();
  610. my $fcDays = AttrVal( $name, 'forecastDays', 14 );
  611. my $parser = MyProplantaParser->new;
  612. # get date from Attribut URL only
  613. my $attrURL = AttrVal( $name, 'URL', "" );
  614. if ($attrURL ne "") {
  615. $response = PROPLANTA_HtmlAcquire($hash,$attrURL);
  616. if ($response =~ /^Error\|/) {
  617. $ptext .= "|".$response;
  618. }
  619. else {
  620. PROPLANTA_Log $hash, 4, "Start HTML parsing of captured page";
  621. $parser->report_tags(qw(tr td span b img));
  622. @MyProplantaParser::texte = ();
  623. $MyProplantaParser::startDay = 0;
  624. # parsing the complete html-page-response, needs some time
  625. $parser->parse($response);
  626. }
  627. }
  628. # Get data from location specified in define
  629. else {
  630. $URL = $hash->{URL};
  631. my @URL_days = (0, 4, 7, 11);
  632. foreach (@URL_days) {
  633. last unless $_ < $fcDays;
  634. $response = PROPLANTA_HtmlAcquire($hash,$URL . $_);
  635. $MyProplantaParser::startDay = $_;
  636. if ($response !~ /^Error\|/) {
  637. PROPLANTA_Log $hash, 4, "Start HTML parsing of captured page";
  638. $parser->parse($response);
  639. }
  640. }
  641. PROPLANTA_Log $hash, 4, "Found terms: " . @MyProplantaParser::texte;
  642. # pack the results in a single string
  643. if (@MyProplantaParser::texte > 0) {
  644. $ptext .= "|". join('|', @MyProplantaParser::texte);
  645. }
  646. PROPLANTA_Log $hash, 5, "Parsed string: " . $ptext;
  647. }
  648. $ptext .= "|durationFetchReadings|";
  649. $ptext .= sprintf "%.2f", time() - $readingStartTime;
  650. return $ptext;
  651. }
  652. #####################################
  653. # asyncronous callback by blocking
  654. sub PROPLANTA_Done($)
  655. {
  656. my ($string) = @_;
  657. return unless ( defined($string) );
  658. # all term are separated by "|" , the first is the name of the instance
  659. my ( $name, %values ) = split( "\\|", $string );
  660. my $hash = $defs{$name};
  661. return unless ( defined($hash->{NAME}) );
  662. PROPLANTA_Log $hash, 4, "Forked process successfully finished";
  663. # delete the marker for RUNNING_PID process
  664. delete( $hash->{helper}{RUNNING_PID} );
  665. # Wetterdaten speichern
  666. readingsBeginUpdate($hash);
  667. if ( defined $values{Error} )
  668. {
  669. readingsBulkUpdate( $hash, "lastConnection", $values{Error} );
  670. }
  671. else
  672. {
  673. my $x = 0;
  674. my $fcDays = AttrVal( $name, 'forecastDays', 14 );
  675. while (my ($rName, $rValue) = each(%values) )
  676. {
  677. if ($fcDays < 14 && $rName =~ /^fc(\d+)_/)
  678. {
  679. next unless $1 < $fcDays;
  680. }
  681. readingsBulkUpdate( $hash, $rName, $rValue );
  682. PROPLANTA_Log $hash, 5, "reading:$rName value:$rValue";
  683. }
  684. if (keys %values > 0)
  685. {
  686. my $newState;
  687. if (defined $values{fc0_tempMin} && defined $values{fc0_tempMax})
  688. {
  689. $newState = "Tmin: " . $values{fc0_tempMin} . " Tmax: " . $values{fc0_tempMax};
  690. # Achtung! Nach Mitternacht fehlen für 1 h die aktuellen Werte
  691. $newState .= " T: " . $values{temperature} . " H: " . $values{humidity} . " W: " . $values{wind} . " P: " . $values{pressure}
  692. if defined $values{temperature} && defined $values{humidity} && defined $values{wind} && defined $values{pressure};
  693. }
  694. else
  695. {
  696. $newState = "Error: Could not capture all data. Please check URL or city name.";
  697. }
  698. readingsBulkUpdate($hash, "state", $newState);
  699. readingsBulkUpdate( $hash, "lastConnection", keys( %values )." values captured in ".$values{durationFetchReadings}." s" );
  700. PROPLANTA_Log $hash, 4, keys( %values )." values captured";
  701. }
  702. else
  703. {
  704. readingsBulkUpdate( $hash, "lastConnection", "no data found" );
  705. PROPLANTA_Log $hash, 1, "No data found. Check city name or URL.";
  706. }
  707. }
  708. readingsEndUpdate( $hash, 1 );
  709. }
  710. #####################################
  711. sub PROPLANTA_Aborted($)
  712. {
  713. my ($hash) = @_;
  714. delete( $hash->{helper}{RUNNING_PID} );
  715. PROPLANTA_Log $hash, 4, "Forked process timed out";
  716. }
  717. ##### noch nicht fertig ###########
  718. sub #####################################
  719. PROPLANTA_Html(@)
  720. {
  721. my ($d,$days) = @_;
  722. $d = "<none>" if(!$d);
  723. $days = 3 unless defined $days;
  724. return "$d is not a PROPLANTA instance<br>"
  725. if(!$defs{$d} || $defs{$d}{TYPE} ne "PROPLANTA");
  726. my $uselocal= 0; #AttrVal($d,"localicons",0);
  727. my $isday;
  728. if ( exists &isday) {
  729. $isday = isday();
  730. }
  731. else {
  732. $isday = 1; #($hour>6 && $hour<19);
  733. }
  734. my $ret = "<table border=0><thead align=center>";
  735. $ret .= sprintf '<tr><th colspan=9 align=left>%s</th></tr>', $defs{$d}{DEF};
  736. $ret .= '<tr><th>Tag</th><th>morgens</th><th>tagsueber</th><th>abends</th><th>nachts</th><th>min</th><th>max</th><th>Regen tags</th><th>Frost</th></tr></thead>';
  737. $ret .= "<tbody align=center>";
  738. # define MyForecast weblink htmlCode { PROPLANTA_Html("ProPlanta_Wetter") }
  739. for(my $i=0; $i<$days; $i++) {
  740. $ret .= sprintf('<tr><td>%s</td><td>%s<br><img src="%s"></td><td>%s<br><img src="%s"></td><td>%s<br><img src="%s"></td><td>%s<br><img src="%s"></td><td>%s°C</td><td>%s°C</td><td>%s %%</td><td>%s</td></tr>',
  741. ReadingsVal($d, "fc".$i."_date", ""),
  742. ReadingsVal($d, "fc".$i."_weatherMorning", ""), ReadingsVal($d, "fc".$i."_weatherMorningIcon", ""),
  743. ReadingsVal($d, "fc".$i."_weatherDay", ""), ReadingsVal($d, "fc".$i."_weatherDayIcon", ""),
  744. ReadingsVal($d, "fc".$i."_weatherEvening", ""), ReadingsVal($d, "fc".$i."_weatherEveningIcon", ""),
  745. ReadingsVal($d, "fc".$i."_weatherNight", ""), ReadingsVal($d, "fc".$i."_weatherNightIcon", ""),
  746. ReadingsVal($d, "fc".$i."_tempMin", ""), ReadingsVal($d, "fc".$i."_tempMax", ""),
  747. ReadingsVal($d, "fc".$i."_chOfRainDay", ""),
  748. ReadingsVal($d, "fc".$i."_frost", "") ? "ja" : "nein"
  749. );
  750. }
  751. # for(my $i=0; $i<=4; $i++) {
  752. # $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>',
  753. # WWOIconIMGTag(ReadingsVal($d, "fc${i}_weatherDayIcon", ""),$uselocal,$isday),
  754. # ReadingsVal($d, "fc${i}_date", ""),
  755. # ReadingsVal($d, "fc${i}_weatherDay", ""),
  756. # ReadingsVal($d, "fc${i}_tempMinC", ""), ReadingsVal($d, "fc${i}_tempMaxC", ""),
  757. # }
  758. $ret .= "</tbody></table>";
  759. return $ret;
  760. }
  761. #####################################
  762. 1;
  763. =pod
  764. =item device
  765. =item summary extracts weather data from www.proplanta.de
  766. =item summary_DE Extrahiert Wetterdaten von www.proplanta.de
  767. =begin html
  768. <a name="PROPLANTA"></a>
  769. <h3>PROPLANTA</h3>
  770. <div>
  771. <ul>
  772. The module extracts weather data from <a href="http://www.proplanta.de">www.proplanta.de</a>.
  773. <br>
  774. The website provides a forecast for 12 days, for the first 7 days in a 3-hours-interval.
  775. <br>
  776. This module causes a high CPU load. It is recommended to reduce the number of captured forecast days.
  777. <br>
  778. It uses the perl modules HTTP::Request, LWP::UserAgent and HTML::Parse.
  779. <br/><br/>
  780. <a name="PROPLANTAdefine"></a>
  781. <b>Define</b>
  782. <ul>
  783. <br>
  784. <code>define &lt;name&gt; PROPLANTA [City] [CountryCode]</code>
  785. <br>
  786. Example:
  787. <br>
  788. <code>define wetter PROPLANTA Bern ch</code>
  789. <br>
  790. <code>define wetter PROPLANTA Wittingen+(Niedersachsen)</code>
  791. <br>&nbsp;
  792. <li><code>[City]</code>
  793. <br>
  794. Optional. The city must be selectable on <a href="http://www.proplanta.de">www.proplanta.de</a>.
  795. <br>
  796. Please pay attention to the <b>Capital</b> letters in the city names.
  797. Spaces within the name are replaced by a + (plus).
  798. </li><br>
  799. <li><code>[CountryCode]</code>
  800. <br>
  801. Optional. Possible values: de (default), at, ch, fr, it
  802. </li><br>
  803. The function <code>PROPLANTA_Html</code> creates a HTML code for a weather forecast for the given days (default is 3).
  804. <br>
  805. Example:
  806. <br>
  807. <code>define HTMLForecast weblink htmlCode { PROPLANTA_Html("ProPlanta_Wetter"[, days])}</code>
  808. <br/><br/>
  809. </ul>
  810. <br>
  811. <a name="PROPLANTAset"></a>
  812. <b>Set</b>
  813. <ul>
  814. <br>
  815. <li><code>set &lt;name&gt; update</code>
  816. <br>
  817. The weather data are immediately polled from the website.
  818. </li><br>
  819. </ul>
  820. <br>
  821. <a name="PROPLANTAattr"></a>
  822. <b>Attributes</b>
  823. <ul>
  824. <br>
  825. <li><code>forecastDays &lt;4-14&gt;</code>
  826. <br>
  827. Number of days for which the forecast data shall be fetched. Default is 14 days (incl. today).
  828. </li><br>
  829. <li><code>INTERVAL &lt;seconds&gt;</code>
  830. <br>
  831. Poll interval for weather data in seconds (default 3600 = 1 hour)
  832. </li><br>
  833. <li><code>URL &lt;internet address&gt;</code>
  834. <br>
  835. URL to extract information from. Overwrites the values in the 'define' term.
  836. </li><br>
  837. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  838. </ul>
  839. <br>
  840. <a name="PROPLANTAreading"></a>
  841. <b>Forecast readings</b>
  842. <ul>
  843. <br>
  844. <li><b>fc</b><i>0|1|2|3|...|13</i><b>_...</b> - forecast values for <i>today|tommorrow|in 2|3|...|13 days</i></li>
  845. <li><b>fc</b><i>0</i><b>_...<i>00|03|06|09|12|15|18|21</i></b> - forecast values for <i>today</i> at <i>00|03|06|09|12|15|18|21</i> o'clock</li>
  846. <li><b>fc</b><i>0</i><b>_chOfRain</b><i>Day|Night</i> - chance of rain <i>today</i> by <i>day|night</i> in %</li>
  847. <li><b>fc</b><i>0</i><b>_chOfRain</b><i>15</i> - chance of rain <i>today</i> at <i>15:00</i> in %</li>
  848. <li><b>fc</b><i>0</i><b>_cloud</b><i>15</i> - cloud coverage <i>today</i> at <i>15:00</i> in %</li>
  849. <li><b>fc</b><i>0</i><b>_dew</b> - dew formation <i>today</i> (0=none, 1=small, 2=medium, 3=strong)</li>
  850. <li><b>fc</b><i>0</i><b>_evapor</b> - evaporation <i>today</i> (0=none, 1=small, 2=medium, 3=strong)</li>
  851. <li><b>fc</b><i>0</i><b>_frost</b> - ground frost <i>today</i> (0=no, 1=yes)</li>
  852. <li><b>fc</b><i>0</i><b>_gust</b><i>15</i> - maximal wind gusts <i>today</i> at <i>15</i>:00 o'clock in km/h</li>
  853. <li><b>fc</b><i>0</i><b>_moon</b><i>Rise|Set</i> - moon <i>rise|set today</i></li>
  854. <li><b>fc</b><i>0</i><b>_rad</b> - global radiation <i>today</i></li>
  855. <li><b>fc</b><i>0</i><b>_rain</b><i>15</i> - amount of rainfall <i>today</i> at <i>15</i>:00 o'clock in mm</li>
  856. <li><b>fc</b><i>0</i><b>_sun</b> - relative sun shine duration <i>today</i> in % (between sun rise and set)</li>
  857. <li><b>fc</b><i>0</i><b>_temp</b><i>Min|Max</i> - <i>minimal|maximal</i> temperature <i>today</i> in °C</li>
  858. <li><b>fc</b><i>0</i><b>_temp</b><i>15</i> - temperatur <i>today</i> at <i>15</i>:00 o'clock in °C</li>
  859. <li><b>fc</b><i>0</i><b>_uv</b> - UV-Index <i>today</i></li>
  860. <li><b>fc</b><i>0</i><b>_weather</b><i>Morning|Day|Evening|Night</i> - weather situation <i>today morning|during day|in the evening|during night</i></li>
  861. <li><b>fc</b><i>0</i><b>_weather</b><i>Day</i><b>Icon</b> - icon of weather situation <i>today</i> by <i>day</i></li>
  862. <li><b>fc</b><i>0</i><b>_wind</b><i>15</i> - wind speed <i>today</i> at <i>15</i>:00 Uhr in km/h</li>
  863. <li><b>fc</b><i>0</i><b>_windDir</b><i>15</i> - wind direction <i>today</i> at <i>15</i>:00 Uhr in °</li>
  864. <li>etc.</li>
  865. </ul>
  866. <br>
  867. </ul>
  868. </div>
  869. =end html
  870. =begin html_DE
  871. <a name="PROPLANTA"></a>
  872. <h3>PROPLANTA</h3>
  873. <div>
  874. <ul>
  875. <a name="PROPLANTAdefine"></a>
  876. Das Modul extrahiert Wetterdaten von der Website <a href="http://www.proplanta.de">www.proplanta.de</a>.
  877. <br/>
  878. Es stellt eine Vorhersage für 12 Tage zur Verfügung - während der ersten 7 Tage im 3-Stunden-Intervall.
  879. <br>
  880. Dieses Modul erzeugt eine hohe CPU-Last. Es wird deshalb empfohlen, die auszulesenden Vorhersagetage zu reduzieren.
  881. <br>
  882. <i>Es nutzt die Perl-Module HTTP::Request, LWP::UserAgent und HTML::Parse</i>.
  883. <br>
  884. Für detaillierte Anleitungen bitte die <a href="http://www.fhemwiki.de/wiki/PROPLANTA"><b>FHEM-Wiki</b></a> konsultieren und ergänzen.
  885. <br/><br/>
  886. <b>Define</b>
  887. <ul>
  888. <br>
  889. <code>define &lt;Name&gt; PROPLANTA [Stadt] [Ländercode]</code>
  890. <br>
  891. Beispiel:
  892. <br>
  893. <code>define wetter PROPLANTA Bern ch</code>
  894. <br>
  895. <code>define wetter PROPLANTA Wittingen+(Niedersachsen)</code>
  896. <br>&nbsp;
  897. <li><code>[Stadt]</code>
  898. <br>
  899. Optional. Die Stadt muss auf <a href="http://www.proplanta.de">www.proplanta.de</a> auswählbar sein.
  900. <br>
  901. Wichtig!! Auf die <b>großen</b> Anfangsbuchstaben achten. Leerzeichen im Stadtnamen werden durch ein + (Plus) ersetzt.
  902. </li><br>
  903. <li><code>[Ländercode]</code>
  904. <br>
  905. Optional. Mögliche Werte: de (Standard), at, ch, fr, it
  906. </li><br>
  907. Über die Funktion <code>PROPLANTA_Html</code> wird ein HTML-Code für eine Vorhersage für die angegebenen Anzahl Tage (standardmäßig 3) erzeugt.
  908. <br>
  909. Beispiel:
  910. <br>
  911. <code>define Vorschau weblink htmlCode {PROPLANTA_Html("Wetter"[, Tage])}</code>
  912. <br/><br/>
  913. </ul>
  914. <br>
  915. <a name="PROPLANTAset"></a>
  916. <b>Set</b>
  917. <ul>
  918. <br>
  919. <li><code>set &lt;name&gt; update</code>
  920. <br>
  921. Startet sofort ein neues Auslesen der Wetterdaten.
  922. </li><br>
  923. </ul>
  924. <a name="PROPLANTAattr"></a>
  925. <b>Attribute</b>
  926. <ul>
  927. <br>
  928. <li><code>forecastDays &lt;4-14&gt;</code>
  929. <br>
  930. Anzahl Tage, für die die Vorhersage ausgelesen werden soll. Standard ist 14 Tage (inkl. heute).
  931. </li><br>
  932. <li><code>INTERVAL &lt;Abfrageintervall&gt;</code>
  933. <br>
  934. Abfrageintervall in Sekunden (Standard 3600 = 1 Stunde)
  935. </li><br>
  936. <li><code>URL &lt;Internetadresse&gt;</code>
  937. <br>
  938. Internetadresse, von der die Daten ausgelesen werden (überschreibt die Werte im 'define'-Term)
  939. </li><br>
  940. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  941. </ul>
  942. <br><br>
  943. <a name="PROPLANTAreading"></a>
  944. <b>Vorhersagewerte</b>
  945. <ul>
  946. <br>
  947. <li><b>fc</b><i>0|1|2|3...|13</i><b>_...</b> - Vorhersagewerte für <i>heute|morgen|übermorgen|in 3|...|13 Tagen</i></li>
  948. <li><b>fc</b><i>0</i><b>_...<i>00|03|06|09|12|15|18|21</i></b> - Vorhersagewerte für <i>heute</i> um <i>00|03|06|09|12|15|18|21</i> Uhr</li>
  949. <li><b>fc</b><i>0</i><b>_chOfRain</b><i>Day|Night</i> - <i>heutiges</i> Niederschlagsrisiko <i>tagsüber|nachts</i> in %</li>
  950. <li><b>fc</b><i>1</i><b>_chOfRain</b><i>15</i> - <i>morgiges</i> Niederschlagsrisiko um <i>15</i>:00 Uhr in %</li>
  951. <li><b>fc</b><i>2</i><b>_cloud</b><i>15</i> - Wolkenbedeckungsgrad <i>übermorgen</i> um <i>15</i>:00 Uhr in %</li>
  952. <li><b>fc</b><i>0</i><b>_dew</b> - Taubildung <i>heute</i> (0=keine, 1=leicht, 2=mäßig, 3=stark)</li>
  953. <li><b>fc</b><i>0</i><b>_evapor</b> - Verdunstung <i>heute</i> (0=keine, 1=gering, 2=mäßig, 3=stark)</li>
  954. <li><b>fc</b><i>0</i><b>_frost</b> - Bodenfrost <i>heute</i> (0=nein, 1=ja)</li>
  955. <li><b>fc</b><i>0</i><b>_gust</b><i>15</i> - maximale Windböen <i>heute</i> um <i>15</i>:00 Uhr in km/h</li>
  956. <li><b>fc</b><i>1</i><b>_moon</b><i>Rise|Set</i> - Mond<i>auf|unter</i>gang <i>morgen</i></li>
  957. <li><b>fc</b><i>0</i><b>_rad</b> - Globalstrahlung <i>heute</i></li>
  958. <li><b>fc</b><i>0</i><b>_rain</b><i>15</i> - Niederschlagsmenge <i>heute</i> um <i>15</i>:00 Uhr in mm</li>
  959. <li><b>fc</b><i>0</i><b>_sun</b> - relative Sonnenscheindauer <i>heute</i> in % (zwischen Sonnenauf- und -untergang)</li>
  960. <li><b>fc</b><i>0</i><b>_temp</b><i>Min|Max</i> - <i>Minimal|Maximal</i>temperatur <i>heute</i> in °C</li>
  961. <li><b>fc</b><i>1</i><b>_temp</b><i>15</i> - Temperatur <i>morgen</i> um <i>15</i>:00 Uhr in °C</li>
  962. <li><b>fc</b><i>0</i><b>_uv</b> - UV-Index <i>heute</i></li>
  963. <li><b>fc</b><i>0</i><b>_weather</b><i>Morning|Day|Evening|Night</i> - Wetterzustand <i>heute morgen|tagsüber|abends|nachts</i></li>
  964. <li><b>fc</b><i>0</i><b>_weather</b><i>Day</i><b>Icon</b> - Icon Wetterzustand <i>heute tagsüber</i></li>
  965. <li><b>fc</b><i>0</i><b>_wind</b><i>15</i> - Windgeschwindigkeit <i>heute</i> um <i>15</i>:00 Uhr in km/h</li>
  966. <li><b>fc</b><i>0</i><b>_windDir</b><i>15</i> - Windrichtung <i>heute</i> um <i>15</i>:00 Uhr in ° (Grad)</li>
  967. <li>etc.</li>
  968. </ul>
  969. <br>
  970. <b>Aktuelle Werte</b>
  971. <ul>
  972. <br>
  973. <li><b>cloudBase</b><i>Min|Max</i> - Höhe der <i>minimalen|maximalen</i> Wolkenuntergrenze in m</li>
  974. <li><b>dewPoint</b> - Taupunkt in °C</li>
  975. <li><b>humidity</b> - relative Feuchtigkeit in %</li>
  976. <li><b>obs_time</b> - Uhrzeit der Wetterbeobachtung</li>
  977. <li><b>pressure</b> - Luftdruck in hPa</li>
  978. <li><b>temperature</b> - Temperature in °C</li>
  979. <li><b>visibility</b> - Sichtweite in km</li>
  980. <li><b>weather</b> - Wetterzustand</li>
  981. <li><b>weatherIcon</b> - Icon Wetterzustand</li>
  982. <li><b>wind</b> - Windgeschwindigkeit in km/h</li>
  983. <li><b>windDir</b> - Windrichtung in ° (Grad)</li>
  984. </ul>
  985. <br><br>
  986. </ul>
  987. </div>
  988. =end html_DE
  989. =cut