mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 12:49:34 +00:00
02_RSS.pm added and commandref.html amended
git-svn-id: https://svn.fhem.de/fhem/trunk@1387 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
024ae8e44c
commit
dd56327339
376
fhem/FHEM/02_RSS.pm
Normal file
376
fhem/FHEM/02_RSS.pm
Normal file
@ -0,0 +1,376 @@
|
||||
#
|
||||
#
|
||||
# 02_RSS.pm
|
||||
# written by Dr. Boris Neubert 2012-03-24
|
||||
# e-mail: omega at online dot de
|
||||
#
|
||||
##############################################
|
||||
# $Id: xx $
|
||||
|
||||
package main;
|
||||
use strict;
|
||||
use warnings;
|
||||
use GD;
|
||||
use vars qw(%data);
|
||||
|
||||
# we can
|
||||
# use vars qw(%FW_types); # device types,
|
||||
# use vars qw($FW_RET); # Returned data (html)
|
||||
# use vars qw($FW_wname); # Web instance
|
||||
# use vars qw($FW_subdir); # Sub-path in URL for extensions, e.g. 95_FLOORPLAN
|
||||
# use vars qw(%FW_pos); # scroll position
|
||||
# use vars qw($FW_cname); # Current connection name
|
||||
|
||||
#########################
|
||||
sub
|
||||
RSS_addExtension($$$) {
|
||||
my ($func,$link,$friendlyname)= @_;
|
||||
|
||||
my $url = "/" . $link;
|
||||
$data{FWEXT}{$url}{FUNC} = $func;
|
||||
$data{FWEXT}{$url}{LINK} = $link;
|
||||
$data{FWEXT}{$url}{NAME} = $friendlyname;
|
||||
}
|
||||
|
||||
##################
|
||||
sub
|
||||
RSS_Initialize($) {
|
||||
my ($hash) = @_;
|
||||
$hash->{DefFn} = "RSS_Define";
|
||||
#$hash->{AttrFn} = "RSS_Attr";
|
||||
$hash->{AttrList}= "loglevel:0,1,2,3,4,5 size bg tmin";
|
||||
$hash->{SetFn} = "RSS_Set";
|
||||
|
||||
|
||||
RSS_addExtension("RSS_CGI","rss","RSS");
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
##################
|
||||
sub
|
||||
RSS_readLayout($) {
|
||||
|
||||
my ($hash)= @_;
|
||||
my $filename= $hash->{fhem}{filename};
|
||||
my $name= $hash->{NAME};
|
||||
|
||||
if(open(LAYOUT, $filename)) {
|
||||
my @layout= <LAYOUT>;
|
||||
$hash->{fhem}{layout}= join("", @layout);
|
||||
close(LAYOUT);
|
||||
} else {
|
||||
$hash->{fhem}{layout}= ();
|
||||
Log 1, "RSS $name: Cannot open $filename";
|
||||
}
|
||||
}
|
||||
|
||||
##################
|
||||
sub
|
||||
RSS_Define($$) {
|
||||
|
||||
my ($hash, $def) = @_;
|
||||
|
||||
my @a = split("[ \t]+", $def);
|
||||
|
||||
return "Usage: define <name> RSS jpg hostname filename" if(int(@a) != 5);
|
||||
my $name= $a[0];
|
||||
my $style= $a[2];
|
||||
my $hostname= $a[3];
|
||||
my $filename= $a[4];
|
||||
|
||||
$hash->{fhem}{style}= $style;
|
||||
$hash->{fhem}{hostname}= $hostname;
|
||||
$hash->{fhem}{filename}= $filename;
|
||||
|
||||
RSS_readLayout($hash);
|
||||
|
||||
$hash->{STATE} = $name;
|
||||
return undef;
|
||||
}
|
||||
|
||||
##################
|
||||
sub
|
||||
RSS_Set() {
|
||||
|
||||
my ($hash, @a) = @_;
|
||||
my $name = $a[0];
|
||||
|
||||
# usage check
|
||||
my $usage= "Usage: set $name rereadcfg";
|
||||
if((@a == 2) && ($a[1] eq "rereadcfg")) {
|
||||
RSS_readLayout($hash);
|
||||
return undef;
|
||||
} else {
|
||||
return $usage;
|
||||
}
|
||||
}
|
||||
|
||||
####################
|
||||
#
|
||||
sub
|
||||
RSS_getURL($) {
|
||||
my ($hostname)= @_;
|
||||
# http://hostname:8083/fhem
|
||||
return "http://$hostname:" . $defs{$FW_wname}{PORT} . $FW_ME;
|
||||
}
|
||||
|
||||
# ##################
|
||||
# sub
|
||||
# RSS_Attr(@)
|
||||
# {
|
||||
# my @a = @_;
|
||||
# my $attr= $a[2];
|
||||
#
|
||||
# if($a[0] eq "set") { # set attribute
|
||||
# if($attr eq "bgdir") {
|
||||
# }
|
||||
# }
|
||||
# elsif($a[0] eq "del") { # delete attribute
|
||||
# if($attr eq "bgdir") {
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# return undef;
|
||||
#
|
||||
# }
|
||||
|
||||
##################
|
||||
# list all RSS devices
|
||||
sub
|
||||
RSS_Overview {
|
||||
|
||||
my ($name, $url);
|
||||
my $html= "<body>\n";
|
||||
foreach my $def (sort keys %defs) {
|
||||
if($defs{$def}{TYPE} eq "RSS") {
|
||||
$name= $defs{$def}{NAME};
|
||||
$url= RSS_getURL($defs{$def}{fhem}{hostname});
|
||||
$html.= " <a href='$url/rss/$name.rss'>$name</a><br>\n";
|
||||
}
|
||||
}
|
||||
$html.="</body>";
|
||||
|
||||
return ("text/html; charset=utf-8", $html);
|
||||
}
|
||||
|
||||
##################
|
||||
sub
|
||||
RSS_splitRequest($) {
|
||||
|
||||
# http://hostname:8083/fhem/rss
|
||||
# http://hostname:8083/fhem/rss/myDeviceName.rss
|
||||
# http://hostname:8083/fhem/rss/myDeviceName.jpg
|
||||
# |--------- url ----------| |---name --| ext
|
||||
|
||||
my ($request) = @_;
|
||||
|
||||
if($request =~ /^.*\/rss$/) {
|
||||
# http://localhost:8083/fhem/rss
|
||||
return (undef,undef); # name, ext
|
||||
} else {
|
||||
# http://hostname:8083/fhem/rss/myDeviceName.rss
|
||||
# http://hostname:8083/fhem/rss/myDeviceName.jpg
|
||||
my $call= $request;
|
||||
$call =~ s/^.*\/rss\/([^\/]*)$/$1/;
|
||||
my $name= $call;
|
||||
$name =~ s/^(.*)\.(jpg|rss)$/$1/;
|
||||
my $ext= $call;
|
||||
$ext =~ s/^$name\.(.*)$/$1/;
|
||||
return ($name,$ext);
|
||||
}
|
||||
}
|
||||
|
||||
##################
|
||||
sub
|
||||
RSS_returnRSS($) {
|
||||
my ($name) = @_;
|
||||
|
||||
my $url= RSS_getURL($defs{$name}{fhem}{hostname});
|
||||
|
||||
my $code= "<rss version='2.0' xmlns:media='http://search.yahoo.com/mrss/'><channel><title>$name</title><ttl>1</ttl><item><media:content url='$url/rss/$name.jpg' type='image/jpeg'/></item></channel></rss>";
|
||||
|
||||
return ("application/xml; charset=utf-8", $code);
|
||||
}
|
||||
|
||||
##################
|
||||
# Library
|
||||
##################
|
||||
|
||||
sub
|
||||
RSS_color {
|
||||
my ($S,$rgb)= @_;
|
||||
my @d= split("", $rgb);
|
||||
return $S->colorResolve(hex("$d[0]$d[1]"),hex("$d[2]$d[3]"),hex("$d[4]$d[5]"));
|
||||
}
|
||||
|
||||
sub
|
||||
RSS_itemText {
|
||||
my ($S,$x,$y,$text,%params)= @_;
|
||||
if($x<1) { $x*= $S->width; }
|
||||
if($y<1) { $y*= $S->height; }
|
||||
$S->stringFT(RSS_color($S,$params{rgb}),$params{font},$params{pt},0,$x,$y,$text);
|
||||
}
|
||||
|
||||
sub
|
||||
RSS_itemTime {
|
||||
my ($S,$x,$y,%params)= @_;
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
|
||||
RSS_itemText($S,$x,$y,sprintf("%02d:%02d", $hour, $min),%params);
|
||||
}
|
||||
|
||||
|
||||
##################
|
||||
sub
|
||||
RSS_evalLayout($$@) {
|
||||
my ($S,$name,$layout)= @_;
|
||||
|
||||
my @layout= split("\n", $layout);
|
||||
|
||||
my %params;
|
||||
$params{font}= "Arial";
|
||||
$params{pt}= 12;
|
||||
$params{rgb}= "ffffff";
|
||||
|
||||
my ($x,$y, $text);
|
||||
|
||||
my $cont= "";
|
||||
foreach my $line (@layout) {
|
||||
# kill trailing newline
|
||||
chomp $line;
|
||||
# kill comments and blank lines
|
||||
$line=~ s/\#.*$//;
|
||||
$line=~ s/\s+$//;
|
||||
$line= $cont . $line;
|
||||
if($line=~ s/\\$//) { $cont= $line; undef $line; }
|
||||
next unless($line);
|
||||
$cont= "";
|
||||
#Log 5, "$name: evaluating >$line<";
|
||||
# split line into command and definition
|
||||
my ($cmd, $def)= split("[ \t]+", $line, 2);
|
||||
#Log 5, "CMD= \"$cmd\", DEF= \"$def\"";
|
||||
if($cmd eq "rgb") {
|
||||
$params{rgb}= $def;
|
||||
} elsif($cmd eq "font") {
|
||||
$params{font}= $def;
|
||||
} elsif($cmd eq "pt") {
|
||||
$params{pt}= $def;
|
||||
} elsif($cmd eq "text") {
|
||||
($x,$y,$text)= split("[ \t]+", $def, 3);
|
||||
my $txt= AnalyzePerlCommand(undef, $text);
|
||||
#Log 5, "$name: ($x,$y) $txt";
|
||||
RSS_itemText($S,$x,$y,$txt,%params);
|
||||
} elsif($cmd eq "time") {
|
||||
($x,$y)= split("[ \t]+", $def, 2);
|
||||
RSS_itemTime($S,$x,$y,%params);
|
||||
} else {
|
||||
Log 1, "$name: Illegal command $cmd in layout definition.";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
##################
|
||||
sub
|
||||
RSS_returnJPEG($) {
|
||||
my ($name)= @_;
|
||||
|
||||
my ($width,$height)= split(/x/, AttrVal($name,"size","800x600"));
|
||||
|
||||
#
|
||||
# increase counter
|
||||
#
|
||||
if(defined($defs{$name}{fhem}) && defined($defs{$name}{fhem}{counter})) {
|
||||
$defs{$name}{fhem}{counter}++;
|
||||
} else {
|
||||
$defs{$name}{fhem}{counter}= 1;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# create the image
|
||||
#
|
||||
my $S= GD::Image->newTrueColor($width,$height);
|
||||
$S->colorAllocate(0,0,0); # black is the background
|
||||
|
||||
#
|
||||
# set the background
|
||||
#
|
||||
my $bgdir= AttrVal($name,"bg","");
|
||||
my $bgnr= 0; # item number
|
||||
# check if background directory is set
|
||||
goto SKIPBG unless($bgdir ne "");
|
||||
# check if at least tmin seconds have passed
|
||||
my $t0= 0;
|
||||
my $tmin= AttrVal($name,"tmin",0);
|
||||
if(defined($defs{$name}{fhem}) && defined($defs{$name}{fhem}{t})) {
|
||||
$t0= $defs{$name}{fhem}{t};
|
||||
}
|
||||
my $t1= time();
|
||||
if($t1-$t0>= $tmin) {
|
||||
$defs{$name}{fhem}{t}= $t1;
|
||||
if(defined($defs{$name}{fhem}) && defined($defs{$name}{fhem}{bgnr})) {
|
||||
$bgnr= $defs{$name}{fhem}{bgnr}+1;
|
||||
}
|
||||
}
|
||||
# detect pictures
|
||||
goto SKIPBG unless(opendir(BGDIR, $bgdir));
|
||||
my @bgfiles= grep {$_ !~ /^\./} readdir(BGDIR);
|
||||
closedir(BGDIR);
|
||||
# get item number
|
||||
if($#bgfiles>=0) {
|
||||
if($bgnr > $#bgfiles) { $bgnr= 0; }
|
||||
$defs{$name}{fhem}{bgnr}= $bgnr;
|
||||
my $bgfile= $bgdir . "/" . $bgfiles[$bgnr];
|
||||
my $bg= newFromJpeg GD::Image($bgfile);
|
||||
my ($bgwidth,$bgheight)= $bg->getBounds();
|
||||
$S->copyResized($bg,0,0,0,0,$width,$height,$bgwidth,$bgheight);
|
||||
}
|
||||
SKIPBG:
|
||||
|
||||
#
|
||||
# evaluate layout
|
||||
#
|
||||
RSS_evalLayout($S, $name, $defs{$name}{fhem}{layout});
|
||||
|
||||
#
|
||||
# return jpeg image
|
||||
#
|
||||
return ("image/jpeg; charset=utf-8", $S->jpeg);
|
||||
}
|
||||
|
||||
##################
|
||||
#
|
||||
# here we answer any request to http://host:port/fhem/rss and below
|
||||
sub
|
||||
RSS_CGI(){
|
||||
|
||||
my ($request) = @_; # /rss or /rss/name.rss or /rss/name.jpg
|
||||
|
||||
my ($name,$ext)= RSS_splitRequest($request); # name, ext (rss, jpg)
|
||||
|
||||
if(defined($name)) {
|
||||
if($ext eq "") {
|
||||
return("text/plain; charset=utf-8", "Illegal extension.");
|
||||
}
|
||||
if(!defined($defs{$name})) {
|
||||
return("text/plain; charset=utf-8", "Unknown RSS device: $name");
|
||||
}
|
||||
|
||||
if($ext eq "jpg") {
|
||||
return RSS_returnJPEG($name);
|
||||
} elsif($ext eq "rss") {
|
||||
return RSS_returnRSS($name);
|
||||
}
|
||||
} else {
|
||||
return RSS_Overview();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
|
||||
1;
|
||||
|
||||
|
@ -112,6 +112,7 @@
|
||||
<a href="#RFXCOM">RFXCOM</a>
|
||||
<a href="#RFXMETER">RFXMETER</a>
|
||||
<a href="#RFXX10REC">RFXX10REC</a>
|
||||
<a href="#RSS">RSS</a>
|
||||
<a href="#SCIVT">SCIVT</a>
|
||||
<a href="#SISPM">SISPM</a>
|
||||
<a href="#SIS_PMS">SIS_PMS</a>
|
||||
@ -5089,6 +5090,164 @@ Attributes:<br>
|
||||
</ul>
|
||||
<br>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<a name="RSS"></a>
|
||||
<h3>RSS</h3>
|
||||
<ul>
|
||||
Provides a freely configurable RSS feed.<p>
|
||||
|
||||
Currently a media RSS feed delivering status pictures in JPEG format is supported. This media
|
||||
RSS feed can be used to feed a status display to a network-enabled photo frame.<p>
|
||||
|
||||
You need to have the perl module <code>GD</code> installed. This module is most likely not
|
||||
available for small systems like Fritz!Box.<p>
|
||||
|
||||
RSS is an extension to <a href="#FHEMWEB">FHEMWEB</a>. You must install FHEMWEB to use RSS.</p>
|
||||
|
||||
<a name="RSSdefine"></a>
|
||||
<b>Define</b>
|
||||
<ul>
|
||||
<code>define <name> RSS jpg <hostname> <filename></code><br><br>
|
||||
|
||||
Defines the RSS feed. <code>jpg</code> is a fixed literal to allow for future
|
||||
extensions. <code><hostname></code> is the hostname of the fhem server as
|
||||
seen from the consumer of the RSS feed. <code><filename></code> is the
|
||||
name of the file that contains the <a href="RSSlayout">layout definition</a>.<p>
|
||||
|
||||
Examples:
|
||||
<ul>
|
||||
<code>define FrameRSS RSS jpg host.example.org /etc/fhem/layout</code><br>
|
||||
<code>define MyRSS RSS jpg 192.168.1.222 /var/fhem/conf/layout.txt</code><br>
|
||||
</ul>
|
||||
<br>
|
||||
</ul>
|
||||
|
||||
<a name="RSSset"></a>
|
||||
<b>Set</b>
|
||||
<ul>
|
||||
<code>set <name> rereadcfg</code>
|
||||
<br><br>
|
||||
Rereads the <a href="RSSlayout">layout definition</a> from the file. Useful to enable
|
||||
changes in the layout on-the-fly.
|
||||
<br><br>
|
||||
</ul>
|
||||
|
||||
<a name="RSSattr"></a>
|
||||
<b>Attributes</b>
|
||||
<br><br>
|
||||
<ul>
|
||||
<li>size<br>The dimensions of the JPEG picture in the format
|
||||
<code><width>x<height></code>.</li><br>
|
||||
<li>bg<br>The directory that contains the background pictures (must be in JPEG format).</li><br>
|
||||
<li>tmin<br>The background picture is shown at least <code>tmin</code> seconds,
|
||||
no matter how frequently the RSS feed consumer accesses the page.</li><br>
|
||||
</ul>
|
||||
<br><br>
|
||||
|
||||
<b>Usage information</b>
|
||||
<br><br>
|
||||
<ul>
|
||||
If a least one RSS feed is defined, the menu entry <code>RSS</code> appears in the FHEMWEB
|
||||
side menu. If you click it you get a list of all defined RSS feeds. The URL of any such is
|
||||
RSS feed is <code>http://hostname:port/fhem/rss/name.rss</code> with <code>hostname</code> and
|
||||
<code>name</code> from the RSS feed's <a href="RSSdefine">definition</a> and the <code>port</code>
|
||||
(usually 8083) and literal <code>/fhem</code> from the underlying <a href="#FHEMWEB">FHEMWEB</a>
|
||||
definition.<p>
|
||||
|
||||
Example:
|
||||
<ul><code>http://host.example.org:8083/fhem/rss/FrameRSS.rss</code></ul><p>
|
||||
|
||||
The media RSS feed points to a dynamically generated JPEG picture. The URL of the JPEG picture
|
||||
belonging to the RSS feed is <code>http://hostname:port/fhem/rss/name.jpg</code>, i.e. the URL
|
||||
of the RSS feed with the extension <code>rss</code> changed to <code>jpg</code>.<p>
|
||||
|
||||
Example:
|
||||
<ul><code>http://host.example.org:8083/fhem/rss/FrameRSS.jpg</code></ul><p>
|
||||
|
||||
To render the JPEG picture the current, or, if <code>tmin</code> seconds have elapsed, the next
|
||||
JPEG picture from the directory <code>bg</code> is chosen and scaled to the dimensions given
|
||||
in <code>size</code>. The background is black if no usable JPEG picture can be found. Next the
|
||||
script in the <a href="RSSlayout">layout definition</a> is used to superimpose items on
|
||||
the background.<p>
|
||||
|
||||
You can directly access the URL of the JPEG picture in your browser. Reload the page to see
|
||||
how it works.<p>
|
||||
|
||||
The media RSS feed advertises to refresh after 1 minute (ttl). Some photo frames ignore it and
|
||||
use their preset refresh rate. Go for a photo frame with an adjustable refresh rate (e.g
|
||||
every 5 seconds) if you have the choice!<p>
|
||||
|
||||
This is how the fhem config part might look like:<p>
|
||||
<code>
|
||||
define ui FHEMWEB 8083 global<br><br>
|
||||
|
||||
define FrameRSS RSS jpg host.example.org /etc/fhem/layout<br>
|
||||
attr FrameRSS size 800x600<br>
|
||||
attr FrameRSS bg /usr/share/pictures<br>
|
||||
attr FrameRSS tmin 10<br>
|
||||
</code>
|
||||
|
||||
</ul>
|
||||
|
||||
<a name="RSSlayout"></a>
|
||||
<b>Layout definition</b>
|
||||
<br><br>
|
||||
<ul>
|
||||
The layout definition is a script for placing items on the background. It is read top-down.
|
||||
It consists of layout control commands and items placement commands. Layout control
|
||||
commands define the appearance of subsequent items. Item placement commands actually
|
||||
render items.<p>
|
||||
|
||||
Everything after a # is treated as a comment and ignored. You can fold long lines by
|
||||
putting a \ at the end.<p>
|
||||
|
||||
<i>Layout control commands</i>
|
||||
<ul>
|
||||
<li>font <font><br>Sets the font. <font> is the name of a TrueType font (e.g.
|
||||
<code>Arial</code>) or the full path to a TrueType font (e.g. <code>/usr/share/fonts/truetype/arial.ttf</code>),
|
||||
whatever works on your system.</li><br>
|
||||
|
||||
<li>rgb <color><br>Sets the color. <color> is a 6-digit hex number, every 2 digits
|
||||
determining the red, green and blue color components as in HTML color codes (e.g.
|
||||
<code>FF0000</code> for red, <code>C0C0C0</code> for light gray).</li><br>
|
||||
|
||||
<li>pt <pt><br>Sets the font size in points.</li><br>
|
||||
</ul>
|
||||
|
||||
<i>Item placement commands</i>
|
||||
<ul>
|
||||
<li>text <x> <y> <text><br>Renders the text <text> at the
|
||||
position (<x>, <y>) using the current font, font size and color.
|
||||
(0,0) is the upper left corner. Coordinates equal or
|
||||
greater than 1 are considered to be pixels, coordinates between 0 and 1 are considered to
|
||||
be relative to the total width or height of the picture. You can use
|
||||
<code>{ <a href="#perl"><perl special></a> }</code> for <text> to fully
|
||||
access device readings and do some programming on the fly. See below for examples.</li><br>
|
||||
|
||||
<li>time <x> <y><br>Renders the current time in HH:MM format.</li><br>
|
||||
</ul>
|
||||
|
||||
This is how a layout definition might look like:<p>
|
||||
<code>
|
||||
font /usr/share/fonts/truetype/arial.ttf # must be a TrueType font<br>
|
||||
rgb c0c0c0 # HTML color notation, RGB<br>
|
||||
pt 48 # font size in points<br>
|
||||
time 0.10 0.90<br>
|
||||
pt 24<br>
|
||||
text 0.10 0.95 { ReadingsVal("MyWeather","temperature","?"). "°C" }<br>
|
||||
</code>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
@ -5177,7 +5336,7 @@ Attributes:<br>
|
||||
</ul>
|
||||
<br><br>
|
||||
|
||||
<a name="M232attr"></a>
|
||||
<a name="ECMDattr"></a>
|
||||
<b>Attributes</b>
|
||||
<br><br>
|
||||
<ul>
|
||||
|
Loading…
Reference in New Issue
Block a user