98_rssFeed.pm 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226
  1. ##############################################
  2. # $Id: 98_rssFeed.pm 13080 2017-01-15 08:04:43Z Benni $
  3. ##############################################
  4. # 06.02.2016 - added content:encoded to be selected as
  5. # extractable reading
  6. # 06.02.2016 - setting encoding attribute to utf8 by default
  7. # when device is defined for the first time
  8. # 06.02.2016 - allowing call of custom user function for
  9. # text preparation of title, description and
  10. # content:encoded
  11. package main;
  12. use strict;
  13. use warnings;
  14. use POSIX;
  15. use Encode qw(encode);
  16. use IO::Uncompress::Gunzip qw(gunzip $GunzipError );
  17. use XML::Simple qw(:strict);
  18. my $modulename='rssFeed'; #Module-Name = TYPE
  19. my $nb_prefix='n';
  20. my $nb_separator="_";
  21. my $feed_prefix='f'.$nb_separator;
  22. my $debug_prefix='d'.$nb_separator;
  23. my $startup_wait_seconds=10;
  24. my $default_interval=3600;
  25. my $min_interval=300;
  26. my $default_max_lines=10;
  27. my $maximum_max_lines=99;
  28. my $nb_indexlength=length($maximum_max_lines);
  29. my $rdHeadlines='.headlines';
  30. my $tickerReadingsPrefix='ticker';
  31. my $rdToastTicker=$tickerReadingsPrefix.'Toast';
  32. my $rdMarqueeTicker=$tickerReadingsPrefix.'Marquee';
  33. my $defaultReadings="title,description,pubDate";
  34. my $allReadings=$defaultReadings.",link,buildDate,imageTitle,imageURL,encodedContent";
  35. my $defaultEncoding='utf8';
  36. my $defaultDisabledText='this rssFeed ist currently disabled';
  37. sub
  38. #======================================================================
  39. rssFeed_Log3($$$)
  40. #======================================================================
  41. #Using my own Log3 method, expecting the same
  42. #parameters as the official method
  43. #rssFeed_Log3 <devicename>,<loglevel>,<logmessage>
  44. #making sure, the device-name is always contained in the log message
  45. {
  46. my ($name,$lvl,$text)=@_;
  47. Log3 $name,$lvl,"$name: $text";
  48. return undef;
  49. }
  50. #======================================================================
  51. sub rssFeed_NotifyFn($$)
  52. #======================================================================
  53. {
  54. #TODO: Catch global INITIALIZED event!!!
  55. my ($hash,$dev)=@_;
  56. my $name=$hash->{NAME};
  57. my $src=$dev->{NAME};
  58. if($src eq 'global') {
  59. foreach my $event (@{$dev->{CHANGED}})
  60. {
  61. rssFeed_Log3 $name,5,"global event for $name: $event";
  62. if($event =~ /ATTR $name disable/) {
  63. rssFeed_Log3 $name,4,"$name disabled changed";
  64. if(IsDisabled($name)) {
  65. rssFeed_update($hash);
  66. rssFeed_Log3 $hash->{NAME},4,'NotifyFn: Removing timer (disabled)';
  67. RemoveInternalTimer($hash);
  68. readingsSingleUpdate($hash,'state','disabled',1);
  69. } else {
  70. my $nexttimer=gettimeofday()+$startup_wait_seconds;
  71. rssFeed_Log3 $name,4,'NotifyFn: starting timer. First event at '.localtime($nexttimer).' (enable)';
  72. $hash->{NEXTUPDATE}=localtime($nexttimer);
  73. InternalTimer($nexttimer, $modulename."_GetUpdate", $hash, 0);
  74. readingsSingleUpdate($hash,'state','defined',1);
  75. }
  76. } elsif($event =~/ATTR $name rfDisplayTickerReadings/) {
  77. rssFeed_Log3 $name,4,"$name rfDisplayTickerReadings changed";
  78. if(!AttrVal($name,'rfDisplayTickerReadings',undef)) {
  79. fhem("deletereading $name $tickerReadingsPrefix.*",1);
  80. } else {
  81. readingsSingleUpdate($hash,$rdToastTicker,'waiting for next update...',1);
  82. readingsSingleUpdate($hash,$rdMarqueeTicker,'waiting for next update...',1);
  83. }
  84. } elsif($event eq 'INITIALIZED') {
  85. if(IsDisabled($name)) {
  86. rssFeed_update($hash);
  87. rssFeed_Log3 $hash->{NAME},4,'NotifyFn: Removing timer (disabled)';
  88. RemoveInternalTimer($hash);
  89. readingsSingleUpdate($hash,'state','disabled',1);
  90. }
  91. }
  92. }
  93. }
  94. rssFeed_Log3 $name,5,"$name hat ein notify von von $src erhalten";
  95. return undef if(IsDisabled($name));
  96. return undef if($dev->{TYPE} eq 'FRITBOX');
  97. foreach my $event (@{$dev->{CHANGED}})
  98. {
  99. rssFeed_Log3 $name,5,"$src EVENT: $event";
  100. }
  101. return undef;
  102. }
  103. sub
  104. #======================================================================
  105. rssFeed_GetUpdate($)
  106. #======================================================================
  107. #This ist the Update-Routine called when internal timer has reached
  108. #end. It will call the update routine, updating feed data if device
  109. #is not disabled.
  110. {
  111. my ($hash) = @_;
  112. my $name = $hash->{NAME};
  113. rssFeed_Log3 $name,4,$modulename.'_GetUpdate';
  114. rssFeed_update(@_) if(!AttrVal($name,'disable',undef));
  115. #Setting Internal with next timer event time
  116. my $nexttimer=gettimeofday()+$hash->{INTERVAL};
  117. $hash->{NEXTUPDATE}=localtime($nexttimer);
  118. #Restarting timer
  119. rssFeed_Log3 $name,4,"restarting timer: next event ".localtime($nexttimer);
  120. InternalTimer($nexttimer, $modulename."_GetUpdate", $hash, 1);
  121. return undef;
  122. }
  123. sub
  124. #======================================================================
  125. rssFeed_Initialize($)
  126. #======================================================================
  127. #Module instance initialization (constructor)
  128. {
  129. my ($hash) = @_;
  130. #Telling FHEM what routines to use for module handling
  131. $hash->{SetFn} = $modulename."_Set"; #setter
  132. $hash->{GetFn} = $modulename."_Get"; #getter
  133. $hash->{DefFn} = $modulename."_Define"; #define
  134. $hash->{UndefFn} = $modulename."_Undef"; #undefine
  135. $hash->{NotifyFn} = $modulename."_NotifyFn"; #event handling
  136. #Telling FHEM what attributes are available
  137. $hash->{AttrList} = "disable:1,0 "
  138. . "rfDebug:1,0 " #enable (0) or disable (1) the device
  139. . "rfMaxLines " #maximum number of title-lines to extract from feed
  140. . "rfDisplayTitle " #display a title as first line in headlines (is perl special)
  141. . "rfTickerChars " #optional characters to display at the beginning and end of each headline
  142. . "rfEncode " #optional encoding to use for setting the readings (e.g. utf8)
  143. . "rfCustomTextPrepFn " #optional preparation of Text readings before they_re set (funtion)
  144. . "rfReadings:multiple-strict,".$allReadings." " #readings to fill (comma separated list)
  145. . "rfDisabledText "
  146. . "rfDisplayTickerReadings:1,0 "
  147. . "rfAllReadingsEvents:1,0 "
  148. #. "rfLatin1ToUtf8:1,0" #optional encoding using latin1ToUtf8 for readings (TEST ONLY)
  149. . $readingFnAttributes; #default FHEM FnAttributes -> see commandref.
  150. }
  151. sub
  152. #======================================================================
  153. rssFeedGetTicker($)
  154. #======================================================================
  155. #getting the Headlines from the given device
  156. #rssFeedGetTicker(<devicename>)
  157. #This routine will ber calle by 'get ticker'.
  158. {
  159. my ($name)=@_;
  160. #Checking if device exists ...
  161. if(!$defs{$name}) {
  162. return "$name ist not defined";
  163. }
  164. #... and has correct TYPE
  165. if(!($defs{$name}{'TYPE'} eq $modulename)){
  166. return "$name is no $modulename device";
  167. }
  168. #returning the Headlines stored in the corresponding reading
  169. return ReadingsVal($name,$rdHeadlines,"No headlines available!\nUse $name set update to refresh data.");
  170. #--> returning undef here leads to a syntax error.
  171. # I just don't know why yet???
  172. #return undef;|
  173. }
  174. sub
  175. #======================================================================
  176. rssFeed_Set($@)
  177. #======================================================================
  178. #Setter - Handling set commands for device
  179. {
  180. my ($hash, @a) = @_;
  181. my $name = shift @a;
  182. my $cmd=shift @a;
  183. #Currently only the update command is available to refressh
  184. #feed date
  185. if ($cmd eq 'update') {
  186. rssFeed_update(@_);
  187. }
  188. else {
  189. return "Unknown argument $cmd, choose one of update:noArg";
  190. }
  191. return undef;
  192. }
  193. sub
  194. #======================================================================
  195. rssFeed_Define($$)
  196. #======================================================================
  197. #defining the device using following syntax
  198. #define <name> rssFeed <feedurl> [interval]
  199. #Example URLs:
  200. # http://www.tagesschau.de/xml/rss2
  201. # http://www.spiegel.de/schlagzeilen/tops/index.rss
  202. {
  203. my ($hash, $def) = @_;
  204. my @a = split("[ \t][ \t]*", $def);
  205. #Check if at least 2 arguments are specified (name and url)
  206. return "Wrong syntax: use define <name> $modulename <feedURL> [interval]" if(int(@a) < 3);
  207. my $name=shift @a;
  208. my $type=shift @a;
  209. my $url=shift@a;
  210. my $interval=shift @a;
  211. #setting restrictions for event notifications
  212. $hash->{NOTIFYDEV}="global";
  213. if (defined($interval)) {
  214. #if interval defined, make sure its a valid number
  215. #and is at least 5 minutes (seconds)
  216. $interval=$interval+0;
  217. $interval=$min_interval if ($interval<$min_interval);
  218. $hash->{INTERVAL}=$interval;
  219. } else {
  220. #otherwise set default inteval of one hour
  221. $hash->{INTERVAL}=$default_interval;
  222. }
  223. #Storing the given feed-URL in the internals
  224. $hash->{URL}=$url;
  225. if(IsDisabled($name)) {
  226. readingsSingleUpdate($hash,'state',"disabled",0);
  227. return undef;
  228. }
  229. #return undef if(IsDisabled($name));
  230. #and setting a state reading for device
  231. #-> ToDo: finding a better state value (something meaningful)
  232. #-> Done: see in rssFeed_update -> set to last update timestamp
  233. readingsSingleUpdate($hash,'state','defined',1);
  234. rssFeed_Log3 $hash->{NAME},4,'Define: Removing probably existing timer';
  235. RemoveInternalTimer($hash);
  236. #Starting first timer loop with waiting for 10 second before first
  237. #update of feed data. Followint timers will then be started with the given
  238. #interval. This is for waiting a short ammount of time especially when
  239. #FHEM is started.
  240. my $nexttimer=gettimeofday()+$startup_wait_seconds;
  241. rssFeed_Log3 $name,4,'Define: starting timer. First event at '.localtime($nexttimer);
  242. $hash->{NEXTUPDATE}=localtime($nexttimer);
  243. InternalTimer($nexttimer, $modulename."_GetUpdate", $hash, 0);
  244. #Set default attributes
  245. #Do this only at very first definition of the device.
  246. #Prevent this during initialization of FHEM at startup.
  247. if ($init_done) {
  248. #setting default readings to be extracted if attribute rfReadings is not set
  249. my $attReadings=AttrVal($hash->{NAME},"rfReadings",undef);
  250. $attr{$hash->{NAME}}{rfReadings}=$defaultReadings if (!$attReadings);
  251. #setting default encoding if attribute rfEncode is not set
  252. my $attEncoding=AttrVal($hash->{NAME},"rfEncode",undef);
  253. $attr{$hash->{NAME}}{rfEncode}=$defaultEncoding if (!$attEncoding);
  254. }
  255. return undef;
  256. }
  257. sub
  258. #======================================================================
  259. rssFeed_Undef($$)
  260. #======================================================================
  261. #Undefine of device instance (destructor)
  262. #Simply remove running timer(s) of device instance to be undefined.
  263. {
  264. my ( $hash, $arg ) = @_;
  265. rssFeed_Log3 $hash->{NAME},4,'Undef: Removing timer';
  266. RemoveInternalTimer($hash);
  267. return undef;
  268. }
  269. sub
  270. #======================================================================
  271. rssFeed_Get($@)
  272. #======================================================================
  273. # getter - Handling get requests
  274. {
  275. my ($hash,@a)=@_;
  276. my $name=shift @a;
  277. my $cmd=shift @a;
  278. #Getting the ticker data (Healines)
  279. if ($cmd eq 'ticker') {
  280. return rssFeedGetTicker($name);
  281. } else {
  282. return "Unknown argument $cmd, choose one of ticker:noArg";
  283. }
  284. return undef;
  285. }
  286. sub
  287. #======================================================================
  288. rssFeed_update(@)
  289. #======================================================================
  290. #This subroutine is actually doing the update of the feed data for
  291. #the device. It's called by 'set update' and rssFeed_GetUpdate when
  292. #timer is up.
  293. {
  294. my ($dhash,@a)=@_;
  295. my $name=$dhash->{NAME};
  296. #Check if something wrong with the device's hash.
  297. if (!$name) {
  298. rssFeed_Log3($modulename.'_update',3,'Unable to extract device name');
  299. }
  300. rssFeed_Log3 $name,4,'updating feed data...';
  301. my $rfDebug=AttrVal($name,"rfDebug",undef);
  302. #Delete all previously stored data from the readings.
  303. #-> ToDo: maybe I'll extract this to a clear readings [what] command
  304. fhem("deletereading $name $nb_prefix.*[0-9]{$nb_indexlength}.*",1);
  305. fhem("deletereading $name $debug_prefix.*",1);
  306. fhem("deletereading $name $feed_prefix.*",1);
  307. fhem("deletereading $name preparedLines",1);
  308. #Checking if ticker characters are defined.
  309. #They will surround each headline in the ticker data
  310. my ($tt_start,$tt_end);
  311. my $ttt=AttrVal($name,'rfTickerChars','');
  312. if ($ttt) {
  313. $tt_start="$ttt ";
  314. $tt_end=" $ttt";
  315. } else {
  316. $tt_start='';
  317. $tt_end='';
  318. }
  319. #get encoding attribute
  320. my $enc=AttrVal($name,'rfEncode',undef);
  321. #TEST ONLY:
  322. #my $lutf=AttrVal($name,"latin1ToUtf8",undef);
  323. my $rfReadings=AttrVal($name,'rfReadings',$defaultReadings);
  324. my @setReadings = split /,/, $rfReadings;
  325. my %params = map { $_ => 1 } @setReadings;
  326. #create event for all readings that are created or updated if appropriate attribute
  327. #is set
  328. my $allEvents=int(AttrVal($name,'rfAllReadingsEvents','0'));
  329. rssFeed_Log3 $name,4,"rfAllReadingsEvents: $allEvents";
  330. #setting state to the same value as it is more meaningful than
  331. #just 'defined'
  332. readingsSingleUpdate($dhash,'state',localtime(gettimeofday()),1) if(!IsDisabled($name));
  333. #if the device is disabled then there will be no further update and only the
  334. #information, that the ticker is deactivated will be stored to ticker headlines
  335. # -> ToDo: This point will currently never be automatically reached, as this update-Routine
  336. # is not called by the timer event routine (rssFeed_GetUpdate) when the disable
  337. # attribute is set. Shoud be called at least once, when attribute dsable is set.
  338. if(AttrVal($name,'disable',undef)) {
  339. my $disabledText=AttrVal($name,"rfDisabledText",$defaultDisabledText);
  340. readingsSingleUpdate($dhash,$rdHeadlines,$tt_start.$disabledText.$tt_end,$allEvents);
  341. return ;
  342. }
  343. #Get how many lines should be extracted from feed from attributes.
  344. #Set default to 10 if not specified
  345. my ($lines) = shift;
  346. $lines = AttrVal($name,'rfMaxLines','10')+0;
  347. $lines =$default_max_lines if ($lines<=0);
  348. $lines =$maximum_max_lines if ($lines>$maximum_max_lines);
  349. rssFeed_Log3 $name,4,"rfMaxLines: $lines";
  350. #Check if the function specified in the attribute rfCustomTextPrepFn exists
  351. #and is callable:
  352. my $custPrepFn=AttrVal($name,'rfCustomTextPrepFn',undef);
  353. if(defined($custPrepFn)) {
  354. if (!defined(&$custPrepFn)) {
  355. rssFeed_Log3 $name,3,"WARNING: specified custom function $custPrepFn doesn't exist!";
  356. $custPrepFn=undef;
  357. } else {
  358. #Function exists, try to call it
  359. eval "$custPrepFn('x','x')";
  360. if ($@) {
  361. rssFeed_Log3 $name,3,"WARNING: Error when calling $custPrepFn(\$\$)!";
  362. rssFeed_Log3 $name,3,$@;
  363. $custPrepFn=undef;
  364. } else {
  365. rssFeed_Log3 $name,4,"Using specified custom function $custPrepFn later on";
  366. }
  367. }
  368. }
  369. my ($i,$nachrichten,$response,@ticker,@mticker,$ua,$url,$xml);
  370. $i = 0;
  371. #Getting URL from internals
  372. $url=InternalVal($name,'URL','');
  373. if (!$url) {
  374. #If there's no URL in internals, something is very wrong (see define)
  375. rssFeed_Log3 $name,3,'ERROR: url not defined';
  376. return;
  377. }
  378. rssFeed_Log3 $name,4,$url;
  379. #Getting feed data (hopefully it's xml data) from url
  380. my $urlbase=eval('URI->new("'.$url.'")->host');
  381. $response = GetFileFromURLQuiet($url,3,undef,1);
  382. if(!$response) {
  383. #Problem: no response was returned!
  384. rssFeed_Log3 $name,3,'ERROR: no response getting rss data from url';
  385. return;
  386. }
  387. #If verbose is set to 5 then log complete response
  388. rssFeed_Log3 $name,5,$response;
  389. #Trying to unzip received response
  390. my $runzipped=undef;
  391. gunzip \$response => \$runzipped;
  392. rssFeed_Log3 $name,5,"unzipError: $GunzipError";
  393. rssFeed_Log3 $name,5,"unzipError:This is ok! It only means that response is not gzipped.";
  394. #If the response was not zipped, the unzip-result is the original response data
  395. my $zipped=0;
  396. $zipped=1 if($runzipped ne $response);
  397. readingsSingleUpdate($dhash,"gzippedFeed",$zipped,$allEvents);
  398. #If rfDebug attribute is set then store complete response in reading
  399. if ($rfDebug) {
  400. readingsSingleUpdate($dhash,$debug_prefix."LastResponse",$response,$allEvents);
  401. readingsSingleUpdate($dhash,$debug_prefix."UnzippedResponse",$runzipped,$allEvents) if ($zipped);
  402. }
  403. #using unzipped responsedata if it was originally zipped
  404. $response=$runzipped if($zipped);
  405. #Trying to convert xml data from reponse to an array
  406. $xml = new XML::Simple;
  407. rssFeed_Log3 $name,5,'Trying to convert xml to array...';
  408. eval {$nachrichten=$xml->XMLin($response,KeyAttr => {}, ForceArray => ['item']);};
  409. if($@) {
  410. rssFeed_Log3 $name,3,"ERROR can't convert feed response" if($@);
  411. rssFeed_Log3 $name,4,"$@";
  412. return;
  413. }
  414. if(!$nachrichten->{channel}) {
  415. rssFeed_Log3 $name,4,'ERROR: no valid feed data available after conversion';
  416. return;
  417. }
  418. #$nachrichten = $xml->XMLin($response, ForceArray => ['item']) if(!$@);
  419. #Now starting update of the readings
  420. readingsBeginUpdate($dhash);
  421. #Extracting data from array and converting it to utf8 where necessary.
  422. if($params{'title'}) {
  423. my $feedTitle=$nachrichten->{channel}{title};
  424. $feedTitle=encode($enc,$feedTitle) if($enc);
  425. $feedTitle=eval("$custPrepFn('feedTitle','$feedTitle')") if ($custPrepFn);
  426. readingsBulkUpdate($dhash,$feed_prefix.'title',$feedTitle) if ($feedTitle);
  427. }
  428. if ($params{'description'}) {
  429. my $feedDescription=$nachrichten->{channel}{description};
  430. $feedDescription=encode($enc,$feedDescription) if ($enc);
  431. $feedDescription=eval("$custPrepFn('feedDescription','$feedDescription')") if ($custPrepFn);
  432. readingsBulkUpdate($dhash,$feed_prefix.'description',$feedDescription) if ($feedDescription);
  433. }
  434. my $feedLink=$nachrichten->{channel}{link};
  435. readingsBulkUpdate($dhash,$feed_prefix.'link',$feedLink) if ($feedLink && $params{'link'});
  436. my $feedBuildDate=$nachrichten->{channel}{lastBuildDate};
  437. readingsBulkUpdate($dhash,$feed_prefix.'buildDate',$feedBuildDate) if ($feedBuildDate && $params{'buildDate'});
  438. my $feedPubDate=$nachrichten->{channel}{pubDate};
  439. readingsBulkUpdate($dhash,$feed_prefix.'pubDate',$feedPubDate) if ($feedPubDate && $params{'pubDate'});
  440. my $feedImageURL=$nachrichten->{channel}{image}{url};
  441. readingsBulkUpdate($dhash,$feed_prefix.'imageURL',$feedImageURL) if ($feedImageURL && $params{'imageURL'});
  442. if ($params{'imageTitle'}) {
  443. my $feedImageTitle=$nachrichten->{channel}{image}{title};
  444. $feedImageTitle=encode($enc,$feedImageTitle) if ($enc);
  445. $feedImageTitle=eval("$custPrepFn('feedImageTitle','$feedImageTitle')") if ($custPrepFn);
  446. readingsBulkUpdate($dhash,$feed_prefix.'imageTitle',$feedImageTitle) if ($feedImageTitle);
  447. }
  448. #Loop through the array to extract the data for each single news block in
  449. #the feed data array
  450. while ($i < $lines) {
  451. #At least a title should exist
  452. if($nachrichten->{channel}{item}[$i]{title}) {
  453. my $cline=$nachrichten->{channel}{item}[$i]{title};
  454. last unless $cline;
  455. $cline=encode($enc,$cline) if ($enc);
  456. $cline=eval("$custPrepFn('title','$cline')") if ($custPrepFn);
  457. #store headlines tor ticker-array for later joining to healines string
  458. my $h = $tt_start.$cline.$tt_end;
  459. last unless $h;
  460. push (@ticker,$h);
  461. push (@mticker,$cline);
  462. #Index for numbering each news-block
  463. my $ndx=sprintf('%0'.$nb_indexlength.'s',$i);
  464. readingsBulkUpdate($dhash,$nb_prefix.$ndx.$nb_separator."title",$cline) if ($params{'title'});
  465. if ($params{'description'}) {
  466. my $cdesc=$nachrichten->{channel}{item}[$i]{description};
  467. $cdesc=encode($enc,$cdesc) if ($enc);
  468. $cdesc=eval("$custPrepFn('description','$cdesc')") if ($custPrepFn);
  469. readingsBulkUpdate($dhash,$nb_prefix.$ndx.$nb_separator."description", $cdesc);
  470. }
  471. if ($params{'link'}) {
  472. my $clink=$nachrichten->{channel}{item}[$i]{link};
  473. $clink=encode($enc,$clink) if ($enc);
  474. readingsBulkUpdate($dhash,$nb_prefix.$ndx.$nb_separator."link", $clink);
  475. }
  476. if ($params{'pubDate'}) {
  477. my $cdate=$nachrichten->{channel}{item}[$i]{pubDate};
  478. $cdate=encode($enc,$cdate) if ($enc);
  479. readingsBulkUpdate($dhash,$nb_prefix.$ndx.$nb_separator."pubDate", $cdate);
  480. }
  481. if ($params{'encodedContent'}) {
  482. my $econtent=$nachrichten->{channel}{item}[$i]{'content:encoded'};
  483. $econtent=encode($enc,$econtent) if($enc);
  484. $econtent=eval("$custPrepFn('encodedContent','$econtent')") if ($custPrepFn);
  485. readingsBulkUpdate($dhash,$nb_prefix.$ndx.$nb_separator.'encodedContent',$econtent);
  486. }
  487. }
  488. $i++;
  489. }
  490. my $tickerLines=@ticker;
  491. readingsBulkUpdate($dhash,"preparedLines", $tickerLines);
  492. #mass updating/generation of readings is complete so
  493. #tell FHEM to update them now!
  494. readingsEndUpdate($dhash,$allEvents);
  495. #joining all headlines separated by newlin in a single string and
  496. #store it in the readings
  497. my $tickerHeadlines=join("\n", @ticker);
  498. readingsSingleUpdate($dhash,$rdHeadlines, $tickerHeadlines,$allEvents);
  499. if(AttrVal($name,"rfDisplayTickerReadings",undef)) {
  500. readingsSingleUpdate($dhash,$rdToastTicker,$tickerHeadlines,1);
  501. my $mTickerLine=join(" $ttt ", @mticker);
  502. readingsSingleUpdate($dhash,$rdMarqueeTicker,$mTickerLine,1);
  503. } else {
  504. fhem("deletereading $name $tickerReadingsPrefix.*",1);
  505. }
  506. return;
  507. }
  508. 1;
  509. #======================================================================
  510. #======================================================================
  511. #
  512. # HTML Documentation for help and commandref
  513. #
  514. #======================================================================
  515. #======================================================================
  516. =pod
  517. =item device
  518. =item summary fetch data from RSS-Feeds
  519. =item summary_DE Stellt Daten eines RSS-Feed bereit
  520. =begin html
  521. <a name="rssFeed"></a>
  522. <h3>rssFeed</h3>
  523. <ul>
  524. This device helps to extract data from an rss feed specified by the
  525. url given in the DEF section. Trhe results will be extracted to
  526. several corresponding readings. Also the headlines of the news
  527. elements will be extracted to a special "ticker"-string that could
  528. be retrieved via GET or a special function.
  529. The data will be updated automatically after the given interval.
  530. <br/><br/>
  531. <a name="rssFeeddefine"></a>
  532. <b>Define</b>
  533. <ul>
  534. <code>define &lt;name&gt; rssFeed &lt;url&gt; [interval]</code>
  535. <br/><br/>
  536. <ul>
  537. url = url of the rss feed
  538. </ul>
  539. <ul>
  540. interval = actualization interval in seconds
  541. <br/>
  542. Minimum for this value is 600 and maximum is 86400
  543. </ul>
  544. <br/>
  545. Example:
  546. <ul>
  547. <code>define rssGEA rssFeed http://www.gea.de/rss?cat=Region%20Reutlingen&amp;main=true 3600</code>
  548. <br/><br/>
  549. The example will retrieve the data from the rss feed every hour
  550. </ul>
  551. </ul>
  552. <br/>
  553. <a name="rssFeedset"></a>
  554. <b>Set</b>
  555. <ul>
  556. <code>set &lt;name&gt; update</code><br/>
  557. retrieving the data from feed and updateing readings data
  558. </ul>
  559. <br/>
  560. <a name="rssFeedget"></a>
  561. <b>Get</b><br/>
  562. <ul>
  563. <code>get &lt;name&gt; ticker</code><br/>
  564. getting the headlines from the feed with specified formatting
  565. (also see attributes)
  566. </ul>
  567. <br/>
  568. <a name="rssFeedattr"></a>
  569. <b>Attributes</b>
  570. <ul>
  571. <li><a name="disabled">disable</a><br/>
  572. This attribute can be used to disable the entier feed device (1)
  573. or to activate it again (0 or attribute missing).
  574. If the device is disabled all readings will be removed, except
  575. the state reading which will then be set to "disabled".
  576. Data will no longer be automatically retrieved from the url.
  577. The ticker data contains only one line indicating the disabled
  578. ticker device. (s.a. attribute rfDisabledText).
  579. <br/>
  580. </li>
  581. <li><a name="rfDisabledText">rfDisabledText</a><br/>
  582. The text in this attribute will be returnde by GET ticker when the
  583. device is disabled (s.a. attribute disable).
  584. If this attribute is not specified a default text is returned.<br/>
  585. Example: <code>attr &lt;name&gt; rfDisabledText This feed is disabled</code>
  586. </li>
  587. <li><a name="rfTickerChars">rfTickerChars</a><br/>
  588. Specifies a string which will surround each headline in the ticker data.<br/>
  589. Example: <code>attr &lt;name&gt; rfTickerChars +++</code>
  590. <br/>
  591. Result: <code>+++ This is a sample headline +++</code>
  592. <br/>
  593. These characters are also used for "marquee"-ticker data.
  594. <br>
  595. </li>
  596. <li><a name="rfMaxLines">rfMaxLines</a><br/>
  597. Defines the maximum number of news items that will be extracted from the
  598. feed. If there are less items in the feed then specified by this attribute
  599. then only that few items are extracted.
  600. If this attribute is missing a default of 10 will be assumed.<br/>
  601. Example: <code>attr &lt;name&gt; rfMaxLines 15</code>
  602. <br/>
  603. </li>
  604. <li><a name="rfDisplayTickerReadings">rfDisplayTickerReadings</a><br/>
  605. If this attribute is set then there will be two additional readings
  606. containing the ticker data for "toast"-Tickers (same as rssFeedGetTicker())
  607. and one containing the ticker data for "marquee"-tickers on a single line.
  608. </li>
  609. <li><a name="rfEncode">rfEncode</a><br/>
  610. Defines an encoding which will be used for any text extracted from the
  611. feed that will be applied before setting the readings. Therefore the
  612. encode method of the Perl-core module Encode is used.
  613. If the attribute is missng then no encoding will be performed.
  614. Sometimes this is necessary when feeds contain wide characters that
  615. could sometimes lead to malfunction in FHEMWEB.
  616. Also the headlines data returned by rssFeedFunctions and get ticker
  617. are encoded using this method.<br/>
  618. This will be set to utf8 by default on first define
  619. <br/>
  620. </li>
  621. <li><a name="rfReadings">rfReadings</a><br/>
  622. This attribute defines the readings that will be created from the extracted
  623. data. It is a comma separated list of the following values:
  624. <ul>
  625. <li>title = title section<br/>
  626. extract the title section of the feed and each news item to a
  627. corresponding reading<br/>
  628. </li>
  629. <li>description = description section<br/>
  630. extract the description section of the feed and each news item
  631. to a corresponding reading
  632. <br/>
  633. </li>
  634. <li>encodedContent = content:encoded section<br/>
  635. if present this contains a more detailed description
  636. <br/>
  637. </li>
  638. <li>pubDate = Publication time of feed and of each news item will
  639. be extracted to a corresponding reading.
  640. <br/>
  641. </li>
  642. <li>link = link url to the feed or to the full article of a
  643. single news items in the feed.
  644. <br/>
  645. </li>
  646. <li>buildDate = time of the last feed actulization by the feed
  647. vendor.
  648. <br/>
  649. </li>
  650. <li>imageURl = url of a probably available image of a news item
  651. <br/>
  652. </li>
  653. <li>imageTitle = image title of a probably available news item
  654. image.
  655. <br/>
  656. </li>
  657. </ul>
  658. If this attribute is missing "title,description,pubDate" will be assumed
  659. as default value. When the device is defined for the first time the
  660. attribute will be automatically created with the default value.
  661. <br/>
  662. </li>
  663. <li><a name="rfCustomTextPrepFn">rfCustomTextPrepFn</a><br>
  664. Can specify a funtion located for example in 99_myUtils.pm
  665. This function will be uses for further modification of extracted
  666. feed data before setting it to the readings or the ticker list.
  667. The function will receive an id for the text type and the text itself.
  668. It must then return the modified Text.
  669. <br/>
  670. Possible text type ids are (s.a. rfReadings)<br>
  671. <ul>
  672. <li>feedTitle</li>
  673. <li>feedDescription</li>
  674. <li>imageTitle</li>
  675. <li>desctiption</li>
  676. <li>encodedContent</li>
  677. </ul>
  678. <br/>
  679. Example for 99_myUtils.pm:
  680. <pre>
  681. #Text preparation for rssFeedDevices
  682. sub rssFeedPrep($$)
  683. {
  684. my($texttype,$text) = @_;
  685. #Cut the lenght of description texts to max 50 characters
  686. my $tLn=length $text;
  687. $text=substr($text,0,47).'...' if ($tLn >50 && ($texttype=~/description/));
  688. #filter Probably errorneous HASH(xxxxxx) from any texts
  689. return ' ' if ($text=~/HASH\(.*\)/);
  690. #set a custom feed title reading
  691. return 'My Special Title' if ($texttype =~/feedTitle/);
  692. #returning modified text
  693. return $text;
  694. }
  695. </pre>
  696. and then set the attribute to that function:<br/>
  697. <code>attr &lt;rssFeedDevice&gt; rfCustomTextPrepFn rssFeedPrep</code>
  698. <br/>
  699. </li>
  700. <li>
  701. <a name="rfReadings">rfAllReadingsEvents</a><br/>
  702. If this attribute is set to 1 all Readings that are created or updated
  703. will generate appropriate events (depending on event-on-... attributes).
  704. By default no events are created for most Readings, especially not for
  705. the feed data Readings
  706. </li>
  707. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  708. </ul>
  709. <br/>
  710. <a name="rssFeedfunctions"></a>
  711. <b>Functions</b>
  712. <ul>
  713. <li>rssFeedGetTicker<br/>
  714. This function will returned the foratted headlines as a single string.
  715. Each headline will be separated by a new line character.
  716. The result of this function can for example be used in InfoPanel as
  717. ticker data.
  718. The function takes the name of a rssFeed device as single parameter.
  719. The result is the same as from <code>get ticker</code> as it uses this function too.
  720. Syntax: <code> rssFeedGetTicker(&lt;rssFeedDevice&gt;)</code><br/>
  721. </li>
  722. </ul><br/>
  723. <a name="rssFeedreadings"></a>
  724. <b>Readings</b>
  725. <ul>
  726. Depending on the attribute rfReadings a bunch of readings is created
  727. from the extracted news feed data.
  728. Some of the readings ar prefixed to tell to which part of the feed the
  729. data belongs to.
  730. </ul>
  731. <ul>
  732. <br/>
  733. <li><code>Nxx_</code><br/>
  734. readings with that prefix correspond to the news items in the feed.
  735. <code>xx</code> index of the news item
  736. <br/>
  737. Example showing the readings of a single news item<br/>
  738. <ul>
  739. <code> N00_title </code><br/>
  740. <code> N00_descripton </code><br/>
  741. <code> N00_pubDate </code><br/>
  742. </ul>
  743. </li>
  744. <li><code>f_</code><br/>
  745. redings with that prefix correspond to the feed itself.
  746. <br/>
  747. Example of feed-readings:
  748. <ul>
  749. <code> f_title </code><br/>
  750. <code> f_descripton </code><br/>
  751. <code> f_buildDate </code><br/>
  752. </ul>
  753. </li>
  754. <li><code>preparedLines</code><br/>
  755. This readings contains the number of new items that were extracted
  756. in the last update of the feed data.
  757. </li>
  758. <li>
  759. <code>tickerToast</code><br/>
  760. This reading contains the same data that is returned by the rssFeedGetTicker()
  761. funciton (if attribute rfDisplayTickerReadings is set)
  762. <br>
  763. Example: <code>+++ Headline 1 +++ \n +++ Headline 2 +++ \n +++ Headline 3 +++ </code>
  764. </li>
  765. <li>
  766. <code>tickerMarquee</code><br/>
  767. This reading contains the ticker data on a single line for "marquee" style
  768. tickers (if attribute rfDisplayTickerReadings is set)
  769. <br>
  770. Example: <code>Headline 1 +++ Hadline 2 +++ Headline 3 +++</code>
  771. </li>
  772. <li><code>gzippedFeed</code><br/>
  773. Sometimes RSS-Feed data is delivered gzipped. This is automatically
  774. recognized by the module. So if the received data was originally
  775. gzipped this reading is set to 1 otherwise it is set to 0
  776. </li>
  777. <li><code>state</code><br/>
  778. The state reading contains the timestamp of the last automatic or manual
  779. update of the device data from the feed, as long as the device is not
  780. disabled.
  781. If the device is disabled state contains "disabled".
  782. When the device is defined then the start of cyclic updates is retarded
  783. for about 10 seconds. During that time state is set to "defined"
  784. </li>
  785. </ul><br/>
  786. </ul>
  787. =end html
  788. =begin html_DE
  789. <a name="rssFeed"></a>
  790. <h3>rssFeed</h3>
  791. <ul>
  792. Mit diesem Hilfs-Device kann ein RSS-Feed per URL abgerufen werden.
  793. Das Ergebnis wird zum einen in entsprechende Readings (s.u.) eingetragen,
  794. zum Anderen k&ouml;nnen die Schlagzeilen (Headlines) noch per GET oder per
  795. bereitgestellter Funktion als Ticker-Daten abgerufen werden.
  796. Die Daten des RSS-Feeds werden dabei jeweils im angegebenen Interval
  797. aktualisiert.
  798. <br><br>
  799. <a name="rssFeeddefine"></a>
  800. <b>Define</b>
  801. <ul>
  802. <code>define &lt;name&gt; rssFeed &lt;url&gt; [interval]</code>
  803. <br><br>
  804. <ul>
  805. url = URL zum RSS-Feed
  806. </ul>
  807. <ul>
  808. interval = Aktualisierungsinterval in Sekunden<br>
  809. minimum Wert sind 600 Sekunden (10 Minuten)<br>
  810. maximum Wert sind 86400 Sekunden (24 Stunden)
  811. </ul>
  812. <br>
  813. Beispiel:
  814. <ul>
  815. <code>define rssGEA rssFeed http://www.gea.de/rss?cat=Region%20Reutlingen&main=true 3600</code>
  816. <br><br>
  817. Damit wird st&uuml;ndlich der RSS-Feed des Reutlinger Generalanzeigers
  818. abgerufen.
  819. </ul>
  820. </ul>
  821. <br>
  822. <a name="rssFeedset"></a>
  823. <b>Set</b>
  824. <ul>
  825. <code>set &lt;name&gt; update</code><br>
  826. Abrufen der Daten vom rssFeed und aktualisieren der Readings
  827. </ul>
  828. <br>
  829. <a name="rssFeedget"></a>
  830. <b>Get</b><br>
  831. <ul>
  832. <code>get &lt;name&gt; ticker</code><br>
  833. Abrufen der zuletzt gelesenen Schlagzeilen im gew&uuml;nschten
  834. Format (s. Attribute)
  835. </ul>
  836. <br>
  837. <a name="rssFeedattr"></a>
  838. <b>Attribute</b>
  839. <ul>
  840. <li><a name="disabled">disabled</a><br>
  841. Mit diesem Attribut kann das Device deaktiviert (1) werden
  842. bzw. auch wieder aktiviert (0 oder Attribut nicht vorhandn).
  843. Wenn das device deaktiviert ist, sind keine Readings mehr
  844. vorhanden, au&szlig;er state. Au&szlig;erdem werden die Daten nicht mehr
  845. zyklisch aktualisiert und get ticker liefert nur noch die
  846. Information zur&uuml;ck, dass der Ticker nicht mehr aktiv ist
  847. (s. dazu auch Attribut rfDisabledText).
  848. <br>
  849. </li>
  850. <li><a name="rfDisabledText">rfDisabledText</a><br>
  851. Der hier eingetragenee Text wird beim Abruf der Schlagzeilen als einzige
  852. Zeile&nbsp;angezeigt, wenn der rssFeed disabled ist (s. Attribut disabled).
  853. Ist dieses Attribut nicht angegeben, so wird ein Standardtext angezeigt.<br>
  854. Beispiel: <code>attr &lt;name&gt; rfDisabledText Dieser Feed wurde deaktiviert</code>
  855. </li>
  856. <li><a name="rfTickerChars">rfTickerChars</a><br>
  857. Hiermit kann eine Zeichenfolge festgelegt werden, die bei den Schlagzeilen
  858. f&uuml;r den get-Abruf vor und nach jeder Schlagzeile, wie bei einem Nachrichten-Ticker
  859. angef&uuml;gt wird.
  860. Beispiel: <code>attr &lt;name&gt; rfTickerChars +++</code>
  861. <br>
  862. Ergebnis: <code>+++ Dies ist eine Beispiel-Schlagzeile +++</code>
  863. <br>
  864. Diese Zeichenkette wird auch als Trenner für die Marquee-Ticker-Daten verwendet.
  865. <br>
  866. </li>
  867. <li><a name="rfMaxLines">rfMaxLines</a><br>
  868. Bestimmt, wieviele Schlagzeilen maximal aus dem Feed extrahiert werden sollen.<br>
  869. Sind weniger Nachrichten-Elemente im Feed enthalten, als &uuml;ber rfMaxLines angegeben,
  870. so werden eben nur so viele Schlagzeilen extrahiert, wie vorhanden sind.<br>
  871. Ist dieses Attribut nich angegeben, so wird daf&uuml;r der Standard-Wert 10 angenommen.<br>
  872. Beispiel: <code>attr &lt;name&gt; rfMaxLines 15</code>
  873. <br>
  874. </li>
  875. <li><a name="rfDisplayTickerReadings">rfDisplayTickerReadings</a><br/>
  876. Wenn dieses Attribut gesetzt ist werden 2 zus&auml;tzliche Readings erzeugt, die
  877. die Tickerdaten einmal f&uuml;r s.g. "Toast"-Ticker (der Inhalt ist der selbe,
  878. wie die Ausgabe von rssFeedGetTicker()) und einmal f&uuml;r s.g. "Marquee"-Ticker, also
  879. in einer einzigen Zeile.
  880. <br>
  881. </li>
  882. <li><a name="rfEncode">rfEncode</a><br>
  883. Hier kann eine Encoding-Methode (Bspw. utf8) angegeben werden.
  884. Die Texte die aus dem Feed extrahiert werden (title, descripton, ...)
  885. werden dann vor der Zuwesung an die Readings mittels encode (Perl core-Module Encode)
  886. enkodiert. Fehlt dieses Attribut, so findet keine umkodierung statt.
  887. Das kann u.U. notwendig sein, wenn in den zur&uuml;ckgelieferten Feed-Daten s.g. wide Characters
  888. enthalten sind. Dies kann evtl. dazu f&uuml;hren, das u.a. die Darstellung in FHEMWEB nicht mehr
  889. korrekt erfolgt.
  890. Dies betrifft auch das Ergebnis von rssFeedFunctions, bzw. get ticker.<br/>
  891. Dieses Attribut wird beim ersten define per default auf utf8 gesetzt.
  892. <br>
  893. </li>
  894. <li><a name="rfReadings">rfReadings</a><br>
  895. &Uuml;ber dieses Attribut kann angegeben werden, welche Daten aus dem RSS-Feed in
  896. Readings extrahiert werden sollen. Das Attribut ist als Komma getrennte Liste
  897. anzugeben.<br>
  898. Zur Auswahl stehen dabei folgende m&ouml;glichen Werte:
  899. <ul>
  900. <li>title = Titelzeile<br>
  901. Dies erzeugt ein Reading f&uuml;r den Feed-Titel und f&uuml;r jedes
  902. Nachrichten-Element aus dem Feed.<br>
  903. </li>
  904. <li>description = Beschreibungstext
  905. Dies erzeugt ein Reading f&uuml;r die Feed-Beschreibung, bzw.
  906. f&uuml;r den Beschreibungstext jeden Nachrichten-Eelements.<br>
  907. </li>
  908. <li>encodedContent = content:encoded Abschnitt<br/>
  909. Sofern vorhanden ist in diesem Abschnitt quasi ein Langtext
  910. der Nachrihtenmeldung enthalten.
  911. <br/>
  912. </li>
  913. <li>pubDate = Zeitpunkt der Ver&ouml;ffentlichung des Feeds, bzw. der einzelnen
  914. Nachrichten-Elemente
  915. <br>
  916. </li>
  917. <li>link = Link zum Feed, bzw. zum einzelnen Nachrichten-Element auf
  918. der Homepage des Feeds.
  919. <br>
  920. </li>
  921. <li>buildDate = Zeitpunkt der letzten aktualisierung der Feed-Daten
  922. vom Feed-Betreiber.
  923. <br>
  924. </li>
  925. <li>imageURl = URL zum ggf. vorhandenen Bild eines Nachrichten-Elements,
  926. bzw. zum Nachrichten-Feed.
  927. <br>
  928. </li>
  929. <li>imageTitle = Titel eines ggf. zum Feed oder Nachrichten-Element
  930. vorhandenen Bildes.
  931. <br>
  932. </li>
  933. </ul>
  934. Ist Dieses Attribut nicht vorhanden, so werden die Werte "title,description,pubDate" als
  935. Voreinstellung angenommen. Beim ersten Anlegen des Device wird das Attribut automatisch
  936. erste einmal mit genau dieser Voreinstellung belegt.
  937. <br>
  938. </li>
  939. <li><a name="rfCustomTextPrepFn">rfCustomTextPrepFn</a><br>
  940. Hier kann eine Funktion angegeben werden, die bspw. in 99_myUtils.pm
  941. definiert wird. In dieser Funktion k&ouml;nnen Textinhalte vor dem
  942. Setzen der Readings, bzw. Tickerzeilen beliebig modifiziert werden.
  943. Der Funktion wird dabei zum Einen eine Kennung für den Text &uuml;bergeben und zum
  944. Anderen der Text selbst. Zur&uuml;ckgegeben wird dann der modifizierte Text.
  945. <br/>
  946. M&ouml;gliche Kennungen sind dabei (s.a. rfReadings)<br>
  947. <ul>
  948. <li>feedTitle</li>
  949. <li>feedDescription</li>
  950. <li>imageTitle</li>
  951. <li>desctiption</li>
  952. <li>encodedContent</li>
  953. </ul>
  954. <br/>
  955. Beispiel f&uuml;r 99_myUtils.pm:
  956. <pre>
  957. #Text-Modifikation für rssFeedDevices
  958. sub rssFeedPrep($$)
  959. {
  960. my($texttype,$text) = @_;
  961. #Länge von descriptions auf maximal 50 begrenzen
  962. my $tLn=length $text;
  963. $text=substr($text,0,47).'...' if ($tLn >50 && ($texttype=~/description/));
  964. #Filtern von texten, die fälschlicherweise auf HASH(xxxxxx) stehen
  965. #von beliebigen Texten
  966. return ' ' if ($text=~/HASH\(.*\)/);
  967. #Setzen eines eigenen Titels für den Feed
  968. return 'Mein eigener Feed-Titel' if ($texttype =~/feedTitle/);
  969. #jetzt noch den modifizierten Text zurück geben
  970. return $text;
  971. }
  972. </pre>
  973. zur Verwendung muss das Attribut noch entsprechend gesetzt werden:<br/>
  974. <code>attr &lt;rssFeedDevice&gt; rfCustomTextPrepFn rssFeedPrep</code>
  975. <br/>
  976. </li>
  977. <li>
  978. <a name="rfReadings">rfAllReadingsEvents</a><br/>
  979. Wenn dieses Attribut auf 1 gesetzt wird, so werden für ALLE Readings,
  980. die w&auml;hrend des Feed-Updates erzeugt werden auch entsprechende Events
  981. generiert (abh. von den event-on-... Attributen).
  982. Von Haus aus werden, v.a. f&uuml;r die Readings mit den Feed-Daten keine
  983. Events generiert.
  984. </li>
  985. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  986. </ul>
  987. <br>
  988. <a name="rssFeedfunctions"></a>
  989. <b>Funktionen</b>
  990. <ul>
  991. <li>rssFeedGetTicker<br>
  992. Diese Funktion gibt die ermittelten und formatierten Schlagzeilen als Zeichenkette
  993. zur&uuml;ck. Die einzelnen Schlagzeilen sind dabei durch Zeilenvorschub getrenn.
  994. Dieses Ergebnis kann bspw. in einem InfoPanel f&uuml;r einen Ticker verwendet werden.
  995. Der Funktion muss dazu der Name eines rssFeed-Devices &uuml;bergeben werden.
  996. Die Ausgabe ist praktisch die selbe wie das Ergebnis, das bei <code>get ticker</code>
  997. geliefert wird.<br>
  998. Syntax: <code> rssFeedGetTicker(&lt;rssFeedDevice&gt;)</code><br>
  999. </li>
  1000. </ul><br>
  1001. <a name="rssFeedreadings"></a>
  1002. <b>Readings</b>
  1003. <ul>
  1004. Je nach Auswahl der Attribute werden verschiedene Readings bereitgestellt.
  1005. Diese Readings sind teilweise mit einem Pr&auml;fix versehen um sie bspw. dem Feed
  1006. selbst oder einem Nachrichten-Element zuozuordnen.
  1007. </ul>
  1008. <ul>
  1009. <br>
  1010. <li><code>Nxx_</code><br>
  1011. Diese Readings beziehen sich alle auf die einzelnen Nachrichten-Elemente, wobei
  1012. <code>xx</code> den Index des jeweiligen Nachrichten-Elements angibt.
  1013. <br>
  1014. Beispiel f&uuml;r die Readings eines Nachrichten-Elements:<br>
  1015. <ul>
  1016. <code> N00_title </code><br/>
  1017. <code> N00_descripton </code><br/>
  1018. <code> N00_pubDate </code><br/>
  1019. </ul>
  1020. </li>
  1021. <li><code>f_</code><br>
  1022. Diese Readings beziehen sich alle auf den Nachrichten-Feed selbst.
  1023. <br>
  1024. Beispiel f&uuml;r die Readings des Nachrichten-Feeds<br>
  1025. <ul>
  1026. <code> f_title </code><br/>
  1027. <code> f_descripton </code><br/>
  1028. <code> f_buildDate </code><br/>
  1029. </ul>
  1030. </li>
  1031. <li><code>preparedLines</code><br>
  1032. Dieses Reading gibt an, wie viele Schlagzeilen tats&auml;chlich beim letzten
  1033. update aus dem Nachrichten-Feed extrahiert wurden.
  1034. </li>
  1035. <li>
  1036. <code>tickerToast</code><br/>
  1037. Dieses Reading ent&auml; die selben Daten, wie sie von der rssFeedGetTicker()
  1038. Funktion zur&uuml;ckgeliefert werden (if attribute rfDisplayTickerReadings is set)
  1039. <br>
  1040. Beispiel: <code>+++ Headline 1 +++ \n +++ Headline 2 +++ \n +++ Headline 3 +++ </code>
  1041. </li>
  1042. <li>
  1043. <code>tickerMarquee</code><br/>
  1044. Dieses Reading enth&auml;lt die Tickerdaten f&uuml;r "marquee"-artige Ticker,
  1045. also auf einer Zeile (if attribute rfDisplayTickerReadings is set)
  1046. <br>
  1047. Beispiel: <code>Headline 1 +++ Hadline 2 +++ Headline 3 +++</code>
  1048. </li>
  1049. <li><code>gzippedFeed</code><br>
  1050. Manche Feeds werden in gezippter (gzip) Form ausgeliefert. Das wird vom
  1051. Modul automatisch erkannt und die Daten im Bedarfsfall dekomprimiert.
  1052. Wurde beim letzten update der Feed in gezippter Form ausgeliefert, so wird
  1053. dieses Reading auf 1 gesetzt, andernfalls auf 0.
  1054. </li>
  1055. <li><code>state</code><br>
  1056. Dieses Reading gibt, wenn das Device nicht disabled ist, den Zeitpunkt
  1057. der letzten aktualisierung mittels update an, egal ob automatisch oder
  1058. manuell ausgel&ouml;st. Ist das device disabled, steht genau das im Reading.
  1059. Beim Anlegegen des Device mittels define findet das erste Aktualisieren
  1060. der Daten verz&ouml;gert statt. W&auml;hrend dieser Verz&ouml;gerung steht der state
  1061. auf "defined".
  1062. </li>
  1063. </ul><br>
  1064. </ul>
  1065. =end html_DE
  1066. =cut