TV Programm: Unterschied zwischen den Versionen
Zeile 370: | Zeile 370: | ||
=== readingsGroups anlegen: === | === readingsGroups anlegen: === | ||
Zuletzt müssen wir uns noch 2 readingsGroups anlegen, damit das aktuelle TV Programm in FHEM auch dargestellt werden kann. Die readingsGroups müssen, wie zuvor die at | Zuletzt müssen wir uns noch 2 readingsGroups anlegen, damit das aktuelle TV Programm in FHEM auch dargestellt werden kann. Die readingsGroups müssen, wie zuvor die at Devices, als Raw Import importiert werden!: | ||
Aktuelle Sendungen: | Aktuelle Sendungen: |
Version vom 5. Juni 2018, 21:08 Uhr
Sich das aktuelle Fernsehprogramm in FHEM anzeigen zu lassen, ist leider gar nicht so einfach. Die einzelnen Anbieter stellen keine entsprechenden Schnittstellen zur Verfügung, um auf einfache Art und Weise das aktuelle Fernsehprogramm für beliebige Sender einlesen und darstellen zu können. Mit ein paar Tricks funktioniert es aber trotzdem.
Hierfür gibt es gleich mehrere Ansätze:
- Im einfachsten Fall bindet man sich ein iframe in die FHEM Weboberfläche ein. Einige Anbieter bieten sogar einen personalisierten Zugriff, so das man sich eine Übersicht nur mit den gewünschten Sendern zusammen stellen kann.
- Es besteht die Möglichkeit EPG Daten in einem speziellen xmltv Format in die FHEM Installation zu laden (enthält das Programm für 6-7 Tage), diese XML Datei zu parsen und dann in FHEM z.B. über eine readingsGroup darzustellen.
- Für Linux und auch Windows sind Tools verfügbar, mit denen man die Seiten von verschiedenen TV Programmanbietern grabben und daraus eine XML Datei im xmltv Format erstellen kann (enthält das Programm von 1-14 Tagen je nach Anbieter). Einer der bekanntesten Vertreter ist WebGrab++. Diese XML Datei kann dann wieder in FHEM eingelesen und angezeigt werden z.B. über eine readingsGroup. Das Parsen der Daten ist mit einem sehr hohen Traffic verbunden, so das hier die vorher erwähnten Methoden vorzuziehen sind.
- Es gibt Webseiten, die das TV Programm als rss zur Verfügung stellen. Darüber hinaus gibt es Services die online rss zu json konvertieren. Kombiniert man nun beides, dann kann man mit httpmod das Ganze mit wenigen Zeilen einlesen.
- Über httpmod könnte man eine Webseite eines TV Programmanbieters zyklisch einlesen und die für FHEM notwendigen Daten extrahieren. Von dieser Methode ist dringend abzuraten, da diese einen enormen Traffic sowohl für einen selbst, als auch für den Anbieter bedeutet. Aus diesem Grund soll diese Methode hier auch nicht dargestellt werden.
Variante 1 (iframe):
define wl_TV weblink iframe <Webseite des TV Programmanbieters z.B. http://www.klack.de/fernsehprogramm/was-laeuft-gerade/0/0/all.html> attr wl_TV htmlattr width="1024" height="768"
Das Attribut legt die Größe des iframes fest und kann beliebig angepasst werden.
Variante 2 (Download der EPG Daten):
Dieser Ansatz ist bereits etwas komplizierter, aber immer noch sehr einfach einzubinden.
Vorbereitungen:
Fehlende Perl Module installieren:
sudo apt-get install libxml-bare-perl libdatetime-perl wget xz-utils
Die ersten beiden Bibliotheken werden benötigt, um die XML Datei zu parsen. wget wird benötigt um die Datei zu downloaden und xz enthält den Unpacker für die runtergeladene Datei.
Pfad für den Download anlegen und mit den entsprechenden Rechten versehen:
sudo mkdir /opt/fhem/tv sudo chown fhem:dialout /opt/fhem/tv
In diesem Verzeichnis soll später die mit wget runtergeladene XML Datei landen.
99_myUtils.pm erweitern:
Dieser Code kann einfach in die Zwischenablage kopiert und in die Datei 99_myUtils.pm eingefügt werden.
sub rgUnfold($$) { my ($device, $reading) = @_; my $title = ReadingsVal($device, $reading.'title', 'na'); my $desc = ReadingsVal($device, $reading.'stitle', 'na')."\n\n". ReadingsVal($device, $reading.'desc', 'na'); $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g; $desc =~ s/(.{1,65}|\S{66,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g; $desc =~ s/[\r\'\"]/ /g; $desc =~ s/[\n]|\\n/<br>/g; return "<a href=\"#!\" onclick=\"FW_okDialog('".$desc."')\">".$title."</a>"; } sub xmltv2epoch($) { my $dt = shift; if ($dt =~ /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(?:\s+([+-]\d{4}))?$/) { if (defined($7)) { return $1.'-'.$2.'-'.$3.' '.$4.':'.$5.':'.$6.' '.$7; } else { return $1.'-'.$2.'-'.$3.' '.$4.':'.$5.':'.$6; } } return '2000-01-01 00:00:00'; } sub tvParse($) { use utf8; use Date::Parse; use Encode qw(encode_utf8 decode_utf8); use XML::Bare qw(forcearray); my $device = shift; my $hash = $defs{$device}; my $obj = XML::Bare->new(file => '/opt/fhem/tv/rytecDE_Basic'); my $xml = $obj->simple(); my $start; my $stop; my $i = 0; my $fi = '000'; my $lastChannel = ''; my $reading = ''; if (!$@) { # clear all old internals delete($hash->{helper}); readingsBeginUpdate($hash); foreach (@{forcearray($xml->{tv}{programme})}) { # channel filter if ($_->{'channel'} =~ /^(?:ARD\.|ZDF\.|Sat1\.|RTL\.|RTL2\.|Pro7\.|DMax\.|Vox\.|Kabel\.)/) { $stop = str2time(xmltv2epoch($_->{'stop'})); # filter old stuff if ($stop >= time()) { if ($lastChannel ne $_->{'channel'}) { $lastChannel = $_->{'channel'}; $reading = $_->{'channel'}; $reading =~ s/\..*$//; $i = 0; $hash->{helper}{$reading.'_lastIndex'} = 0; } # limit number of readings next if ($i > 75); $fi = sprintf("%03d", $i); $start = str2time(xmltv2epoch($_->{'start'})); $hash->{helper}{$reading.'_'.$fi.'_bdate'} = substr(FmtDateTime($start), 0, 10); $hash->{helper}{$reading.'_'.$fi.'_btime'} = substr(FmtDateTime($start), 11, 8); $hash->{helper}{$reading.'_'.$fi.'_edate'} = substr(FmtDateTime($stop), 0, 10); $hash->{helper}{$reading.'_'.$fi.'_etime'} = substr(FmtDateTime($stop), 11, 8); $hash->{helper}{$reading.'_'.$fi.'_title'} = encode_utf8($_->{'title'}{'content'}); if (exists($_->{'sub-title'}{'content'})) { $hash->{helper}{$reading.'_'.$fi.'_stitle'} = encode_utf8($_->{'sub-title'}{'content'}); } else { $hash->{helper}{$reading.'_'.$fi.'_stitle'} = 'na'; } if (exists($_->{'desc'}{'content'})) { $hash->{helper}{$reading.'_'.$fi.'_desc'} = encode_utf8($_->{'desc'}{'content'}); } else { $hash->{helper}{$reading.'_'.$fi.'_desc'} = 'na'; } if ($i < 3) { readingsBulkUpdate($hash, 'next_'.$reading.'_'.$fi.'_bdate', substr(FmtDateTime($start), 0, 10)); readingsBulkUpdate($hash, 'next_'.$reading.'_'.$fi.'_btime', substr(FmtDateTime($start), 11, 8)); readingsBulkUpdate($hash, 'next_'.$reading.'_'.$fi.'_edate', substr(FmtDateTime($stop), 0, 10)); readingsBulkUpdate($hash, 'next_'.$reading.'_'.$fi.'_etime', substr(FmtDateTime($stop), 11, 8)); readingsBulkUpdate($hash, 'next_'.$reading.'_'.$fi.'_title', encode_utf8($_->{'title'}{'content'})); if (exists($_->{'sub-title'}{'content'})) { readingsBulkUpdate($hash, 'next_'.$reading.'_'.$fi.'_stitle', encode_utf8($_->{'sub-title'}{'content'})); } else { readingsBulkUpdate($hash, 'next_'.$reading.'_'.$fi.'_stitle', 'na'); } if (exists($_->{'desc'}{'content'})) { readingsBulkUpdate($hash, 'next_'.$reading.'_'.$fi.'_desc', encode_utf8($_->{'desc'}{'content'})); } else { readingsBulkUpdate($hash, 'next_'.$reading.'_'.$fi.'_desc', 'na'); } } $i++; } } } readingsBulkUpdate($hash, 'state', 'parsed'); readingsEndUpdate($hash, 0); } return undef; } sub tvDownload() { my $output = qx(wget http://rytecepg.ipservers.eu/epg_data/rytecDE_Basic.xz -O /opt/fhem/tv/rytecDE_Basic.xz 2>&1); #print $output; $output = qx(xz -df /opt/fhem/tv/rytecDE_Basic.xz 2>&1); #print $output; } sub tvUpdate($) { my $device = shift; my $hash = $defs{$device}; my @channels = ( 'ARD', 'ZDF', 'Sat1', 'RTL', 'RTL2', 'Pro7', 'DMax', 'Vox', 'Kabel' ); if (exists($hash->{helper})) { readingsBeginUpdate($hash); foreach my $channel (@channels) { my $lastIndex = (exists($hash->{helper}{$channel.'_lastIndex'}) ? $hash->{helper}{$channel.'_lastIndex'} : undef); my $newLastIndex = $lastIndex; my $isNew = 1; if (defined($lastIndex)) { my $i = 0; my $edate = (exists($hash->{helper}{$channel.'_'.sprintf("%03d", $lastIndex).'_edate'}) ? $hash->{helper}{$channel.'_'.sprintf("%03d", $lastIndex).'_edate'} : undef); while (($i < 3) && (defined($edate))) { my $index = sprintf("%03d", $lastIndex); my $etime = (exists($hash->{helper}{$channel.'_'.$index.'_etime'}) ? $hash->{helper}{$channel.'_'.$index.'_etime'} : undef); if ($edate.' '.$etime gt TimeNow()) { my $nindex = sprintf("%03d", $i); if ($lastIndex == $newLastIndex) { $edate = undef; last; } if (1 == $isNew) { $hash->{helper}{$channel.'_lastIndex'} = $lastIndex; $isNew = 0; } readingsBulkUpdate($hash, 'next_'.$channel.'_'.$nindex.'_bdate', $hash->{helper}{$channel.'_'.$index.'_bdate'}); readingsBulkUpdate($hash, 'next_'.$channel.'_'.$nindex.'_btime', $hash->{helper}{$channel.'_'.$index.'_btime'}); readingsBulkUpdate($hash, 'next_'.$channel.'_'.$nindex.'_edate', $edate); readingsBulkUpdate($hash, 'next_'.$channel.'_'.$nindex.'_etime', $etime); readingsBulkUpdate($hash, 'next_'.$channel.'_'.$nindex.'_title', $hash->{helper}{$channel.'_'.$index.'_title'}); readingsBulkUpdate($hash, 'next_'.$channel.'_'.$nindex.'_stitle', $hash->{helper}{$channel.'_'.$index.'_stitle'}); readingsBulkUpdate($hash, 'next_'.$channel.'_'.$nindex.'_desc', $hash->{helper}{$channel.'_'.$index.'_desc'}); $i++; } $lastIndex++; $edate = (exists($hash->{helper}{$channel.'_'.sprintf("%03d", $lastIndex).'_edate'}) ? $hash->{helper}{$channel.'_'.sprintf("%03d", $lastIndex).'_edate'} : undef); } } } readingsBulkUpdate($hash, 'state', 'updated'); readingsEndUpdate($hash, 1); } else { tvParse($device); } } sub tvUpdatePrimetime($) { my $device = shift; my $hash = $defs{$device}; my @channels = ( 'ARD', 'ZDF', 'Sat1', 'RTL', 'RTL2', 'Pro7', 'DMax', 'Vox', 'Kabel' ); if (exists($hash->{helper})) { readingsBeginUpdate($hash); foreach my $channel (@channels) { my $lastIndex = (exists($hash->{helper}{$channel.'_lastIndex'}) ? $hash->{helper}{$channel.'_lastIndex'} : undef); my $newLastIndex = $lastIndex; if (defined($lastIndex)) { my $i = 0; my $bdate = (exists($hash->{helper}{$channel.'_'.sprintf("%03d", $lastIndex).'_bdate'}) ? $hash->{helper}{$channel.'_'.sprintf("%03d", $lastIndex).'_bdate'} : undef); while (($i < 3) && (defined($bdate))) { my $index = sprintf("%03d", $lastIndex); my $btime = (exists($hash->{helper}{$channel.'_'.$index.'_btime'}) ? $hash->{helper}{$channel.'_'.$index.'_btime'} : undef); my $timeNow = substr(TimeNow(), 0, 11).'20:14:00'; if ($bdate.' '.$btime gt $timeNow) { my $nindex = sprintf("%03d", $i); if ($lastIndex == $newLastIndex) { $bdate = undef; last; } readingsBulkUpdate($hash, 'prime_'.$channel.'_'.$nindex.'_bdate', $bdate); readingsBulkUpdate($hash, 'prime_'.$channel.'_'.$nindex.'_btime', $btime); readingsBulkUpdate($hash, 'prime_'.$channel.'_'.$nindex.'_edate', $hash->{helper}{$channel.'_'.$index.'_edate'}); readingsBulkUpdate($hash, 'prime_'.$channel.'_'.$nindex.'_etime', $hash->{helper}{$channel.'_'.$index.'_etime'}); readingsBulkUpdate($hash, 'prime_'.$channel.'_'.$nindex.'_title', $hash->{helper}{$channel.'_'.$index.'_title'}); readingsBulkUpdate($hash, 'prime_'.$channel.'_'.$nindex.'_stitle', $hash->{helper}{$channel.'_'.$index.'_stitle'}); readingsBulkUpdate($hash, 'prime_'.$channel.'_'.$nindex.'_desc', $hash->{helper}{$channel.'_'.$index.'_desc'}); $i++; } $lastIndex++; $bdate = (exists($hash->{helper}{$channel.'_'.sprintf("%03d", $lastIndex).'_bdate'}) ? $hash->{helper}{$channel.'_'.sprintf("%03d", $lastIndex).'_bdate'} : undef); } } } readingsBulkUpdate($hash, 'state', 'updated'); readingsEndUpdate($hash, 1); } }
Dummy Device anlegen:
Dieses Device dient zur Datenhaltung. Hier werden immer die nächsten 3 Sendungen und die 3 Primetime Sendungen des aktuellen Tages als Readings abgelegt. Zusätzlich dazu wird intern eine kleine Datenbank aufgebaut und aktualisiert, damit die große XML Datei nicht ständig neu eingelsen und geparsed werden muss.
define dmy_TV dummy
at Devices anlegen:
4 "at" Devices müssen angelegt werden. Eins für den Download (alle 3 Tage 1x), eins für das Parsen der Daten ins Dummy Device (jeden Tag 1x), eins um die nächsten Sendungen zu filtern (alle 15min) und noch eins um die Primetime Sendungen zu filtern (jeden Tag 1x). Die 4 "at" sind als raw Definitionen kopiert und können auch als solche wieder angelegt werden. Dazu irgend ein Device öffnen, ganz unten auf "Raw definition" klicken und alles entfernen. Den Code von hier einfügen und ausführen und die Devices sind angelegt. Jedes at Device muss separat angelegt werden!
defmod at_TV_DOWNLOAD at *00:15:00 {if ((1 == $wday) || (4 == $wday)) {tvDownload()}}
defmod at_TV_PARSE at *00:30:00 {tvParse('dmy_TV')}
defmod at_TV_UPDATE_PRIME at *00:45:00 {tvUpdatePrimetime('dmy_TV')}
defmod at_TV_UPDATE at +*00:15:00 {tvUpdate('dmy_TV')}
Damit sind die Vorbereitungen abgeschlossen!
Dummy Device mit Daten füllen:
Dieser Vorgang muss nur einmalig gemacht werden, damit sofort Ergebnisse sichtbar sind, da die at Devices (welche danach die Arbeit übernehmen) nur sehr selten gestartet werden und man sonst bis zu 3 Tage warten müsste.
Dazu führt man die at Devices nacheinander einfach aus:
set at_TV_DOWNLOAD execNow set at_TV_PARSE execNow set at_TV_UPDATE_PRIME execNow set at_TV_UPDATE execNow
readingsGroups anlegen:
Zuletzt müssen wir uns noch 2 readingsGroups anlegen, damit das aktuelle TV Programm in FHEM auch dargestellt werden kann. Die readingsGroups müssen, wie zuvor die at Devices, als Raw Import importiert werden!:
Aktuelle Sendungen:
defmod rg_TV readingsGroup <Sender>,<ab>,<Aktuelle Sendung>,<|>,<ab>,<Sendung>,<|>,<ab>,<Sendung>\ dmy_TV:<%tv/ard>,next_ARD_000_btime,<{rgUnfold($DEVICE,'next_ARD_000_')}@next_ARD_000_title>,<|>,next_ARD_001_btime,<{rgUnfold($DEVICE,'next_ARD_001_')}@next_ARD_001_title>,<|>,next_ARD_002_btime,<{rgUnfold($DEVICE,'next_ARD_002_')}@next_ARD_002_title>\ dmy_TV:<%tv/zdf>,next_ZDF_000_btime,<{rgUnfold($DEVICE,'next_ZDF_000_')}@next_ZDF_000_title>,<|>,next_ZDF_001_btime,<{rgUnfold($DEVICE,'next_ZDF_001_')}@next_ZDF_001_title>,<|>,next_ZDF_002_btime,<{rgUnfold($DEVICE,'next_ZDF_002_')}@next_ZDF_002_title>\ dmy_TV:<%tv/sat1>,next_Sat1_000_btime,<{rgUnfold($DEVICE,'next_Sat1_000_')}@next_Sat1_000_title>,<|>,next_Sat1_001_btime,<{rgUnfold($DEVICE,'next_Sat1_001_')}@next_Sat1_001_title>,<|>,next_Sat1_002_btime,<{rgUnfold($DEVICE,'next_Sat1_002_')}@next_Sat1_002_title>\ dmy_TV:<%tv/rtl>,next_RTL_000_btime,<{rgUnfold($DEVICE,'next_RTL_000_')}@next_RTL_000_title>,<|>,next_RTL_001_btime,<{rgUnfold($DEVICE,'next_RTL_001_')}@next_RTL_001_title>,<|>,next_RTL_002_btime,<{rgUnfold($DEVICE,'next_RTL_002_')}@next_RTL_002_title>\ dmy_TV:<%tv/rtl2>,next_RTL2_000_btime,<{rgUnfold($DEVICE,'next_RTL2_000_')}@next_RTL2_000_title>,<|>,next_RTL2_001_btime,<{rgUnfold($DEVICE,'next_RTL2_001_')}@next_RTL2_001_title>,<|>,next_RTL2_002_btime,<{rgUnfold($DEVICE,'next_RTL2_002_')}@next_RTL2_002_title>\ dmy_TV:<%tv/pro7>,next_Pro7_000_btime,<{rgUnfold($DEVICE,'next_Pro7_000_')}@next_Pro7_000_title>,<|>,next_Pro7_001_btime,<{rgUnfold($DEVICE,'next_Pro7_001_')}@next_Pro7_001_title>,<|>,next_Pro7_002_btime,<{rgUnfold($DEVICE,'next_Pro7_002_')}@next_Pro7_002_title>\ dmy_TV:<%tv/dmax>,next_DMax_000_btime,<{rgUnfold($DEVICE,'next_DMax_000_')}@next_DMax_000_title>,<|>,next_DMax_001_btime,<{rgUnfold($DEVICE,'next_DMax_001_')}@next_DMax_001_title>,<|>,next_DMax_002_btime,<{rgUnfold($DEVICE,'next_DMax_002_')}@next_DMax_002_title>\ dmy_TV:<%tv/vox>,next_Vox_000_btime,<{rgUnfold($DEVICE,'next_Vox_000_')}@next_Vox_000_title>,<|>,next_Vox_001_btime,<{rgUnfold($DEVICE,'next_Vox_001_')}@next_Vox_001_title>,<|>,next_Vox_002_btime,<{rgUnfold($DEVICE,'next_Vox_002_')}@next_Vox_002_title>\ dmy_TV:<%tv/kabel1>,next_Kabel_000_btime,<{rgUnfold($DEVICE,'next_Kabel_000_')}@next_Kabel_000_title>,<|>,next_Kabel_001_btime,<{rgUnfold($DEVICE,'next_Kabel_001_')}@next_Kabel_001_title>,<|>,next_Kabel_002_btime,<{rgUnfold($DEVICE,'next_Kabel_002_')}@next_Kabel_002_title> attr rg_TV alias Aktuelles TV-Programm attr rg_TV cellStyle { \ 'r:1,c:1' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"',\ 'r:1,c:2' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"',\ 'r:1,c:3' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"',\ 'r:1,c:5' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"',\ 'r:1,c:6' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"',\ 'r:1,c:8' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"',\ 'r:1,c:9' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"'\ } attr rg_TV group TV Programm attr rg_TV nonames 1 attr rg_TV style style="font-size:16px;;"
Primetime Sendungen:
defmod rg_TV_PRIME readingsGroup <Sender>,<ab>,<Sendung>,<|>,<ab>,<Sendung>,<|>,<ab>,<Sendung>\ dmy_TV:<%tv/ard>,prime_ARD_000_btime,<{rgUnfold($DEVICE,'prime_ARD_000_')}@prime_ARD_000_title>,<|>,prime_ARD_001_btime,<{rgUnfold($DEVICE,'prime_ARD_001_')}@prime_ARD_001_title>,<|>,prime_ARD_002_btime,<{rgUnfold($DEVICE,'prime_ARD_002_')}@prime_ARD_002_title>\ dmy_TV:<%tv/zdf>,prime_ZDF_000_btime,<{rgUnfold($DEVICE,'prime_ZDF_000_')}@prime_ZDF_000_title>,<|>,prime_ZDF_001_btime,<{rgUnfold($DEVICE,'prime_ZDF_001_')}@prime_ZDF_001_title>,<|>,prime_ZDF_002_btime,<{rgUnfold($DEVICE,'prime_ZDF_002_')}@prime_ZDF_002_title>\ dmy_TV:<%tv/sat1>,prime_Sat1_000_btime,<{rgUnfold($DEVICE,'prime_Sat1_000_')}@prime_Sat1_000_title>,<|>,prime_Sat1_001_btime,<{rgUnfold($DEVICE,'prime_Sat1_001_')}@prime_Sat1_001_title>,<|>,prime_Sat1_002_btime,<{rgUnfold($DEVICE,'prime_Sat1_002_')}@prime_Sat1_002_title>\ dmy_TV:<%tv/rtl>,prime_RTL_000_btime,<{rgUnfold($DEVICE,'prime_RTL_000_')}@prime_RTL_000_title>,<|>,prime_RTL_001_btime,<{rgUnfold($DEVICE,'prime_RTL_001_')}@prime_RTL_001_title>,<|>,prime_RTL_002_btime,<{rgUnfold($DEVICE,'prime_RTL_002_')}@prime_RTL_002_title>\ dmy_TV:<%tv/rtl2>,prime_RTL2_000_btime,<{rgUnfold($DEVICE,'prime_RTL2_000_')}@prime_RTL2_000_title>,<|>,prime_RTL2_001_btime,<{rgUnfold($DEVICE,'prime_RTL2_001_')}@prime_RTL2_001_title>,<|>,prime_RTL2_002_btime,<{rgUnfold($DEVICE,'prime_RTL2_002_')}@prime_RTL2_002_title>\ dmy_TV:<%tv/pro7>,prime_Pro7_000_btime,<{rgUnfold($DEVICE,'prime_Pro7_000_')}@prime_Pro7_000_title>,<|>,prime_Pro7_001_btime,<{rgUnfold($DEVICE,'prime_Pro7_001_')}@prime_Pro7_001_title>,<|>,prime_Pro7_002_btime,<{rgUnfold($DEVICE,'prime_Pro7_002_')}@prime_Pro7_002_title>\ dmy_TV:<%tv/dmax>,prime_DMax_000_btime,<{rgUnfold($DEVICE,'prime_DMax_000_')}@prime_DMax_000_title>,<|>,prime_DMax_001_btime,<{rgUnfold($DEVICE,'prime_DMax_001_')}@prime_DMax_001_title>,<|>,prime_DMax_002_btime,<{rgUnfold($DEVICE,'prime_DMax_002_')}@prime_DMax_002_title>\ dmy_TV:<%tv/vox>,prime_Vox_000_btime,<{rgUnfold($DEVICE,'prime_Vox_000_')}@prime_Vox_000_title>,<|>,prime_Vox_001_btime,<{rgUnfold($DEVICE,'prime_Vox_001_')}@prime_Vox_001_title>,<|>,prime_Vox_002_btime,<{rgUnfold($DEVICE,'prime_Vox_002_')}@prime_Vox_002_title>\ dmy_TV:<%tv/kabel1>,prime_Kabel_000_btime,<{rgUnfold($DEVICE,'prime_Kabel_000_')}@prime_Kabel_000_title>,<|>,prime_Kabel_001_btime,<{rgUnfold($DEVICE,'prime_Kabel_001_')}@prime_Kabel_001_title>,<|>,prime_Kabel_002_btime,<{rgUnfold($DEVICE,'prime_Kabel_002_')}@prime_Kabel_002_title>\ attr rg_TV_PRIME alias TV-Programm Primetime attr rg_TV_PRIME cellStyle { \ 'r:1,c:1' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"',\ 'r:1,c:2' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"',\ 'r:1,c:3' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"',\ 'r:1,c:5' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"',\ 'r:1,c:6' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"',\ 'r:1,c:8' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"',\ 'r:1,c:9' => 'style="color:yellow;;text-align:center;;font-weight:bold;;"'\ } attr rg_TV_PRIME group TV Programm attr rg_TV_PRIME nonames 1 attr rg_TV_PRIME style style="font-size:16px;;"
Die Icons der readingsGroups müsst ihr natürlich anpassen! Ladet euch einfach irgendwo die Senderlogos runter und speichert diese unter /opt/fhem/www/images/default. Vergesst bitte nicht die entsprechenden Rechte zu setzen:
sudo chown fhem:dialout *.png
Variante 3 (EPG Daten selbst erstellen):
Vorbereitungen:
Mono und screen installieren:
cd ~ sudo apt-get install mono-runtime libmono-system-data4.0-cil libmono-system-web4.0-cil screen
WebGrab++ downloaden:
wget http://www.webgrabplus.com/sites/default/files/download/SW/V2.1.0/WebGrabPlus_V2.1_install.tar.gz
WebGrab++ entpacken:
tar -zxvf WebGrabPlus_V2.0.tar.gz
WebGrab++ installieren:
cd .wg++ install.sh
Nun müssen zuerst einmal die Konfigurationsdateien angepasst werden:
sudo nano WebGrab++.config.xml
Diese Settings können z.B. verwendet werden:
<filename>guide.xml</filename> <mode>n</mode> <postprocess grab="y" run="y">rex</postprocess> <user-agent>Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0</user-agent> <logging>on</logging> <retry time-out="15">5</retry> <timespan>6</timespan> <update>i</update>
Dann müssen noch die Channels eingetragen werden. Diese Channels können von der Webseite von WebGrab++ kopiert werden. Hier einmal Beispielhaft eine Zeile:
<channel update="i" site="tvmovie.de" site_id="ard" xmltv_id="ARD">ARD</channel>
Jetzt die Datei speichern und schliessen.
Jetzt muss noch die Datei für die Nachbearbeitung angepasst werden:
cd rex sudo nano rex.config.xml
Hier können diese Settings verwendet werden:
<sub-title>{Episode: 'episode' }'subtitle'</sub-title> <desc>'description'{\nProduced in: 'productiondate'. }{\nCategory: 'category(, )'. }{\nActors: 'actor(, )'}{\nDirector: 'director(, )'}{\nPresenter: 'presenter(, )'}</desc> <credits></credits> <episode-num></episode-num> <date></date> <category></category> <review>{Ratings: 'rating(, )'.}</review> <rating></rating>
Datei wieder abspeichern und schliessen.
EPG Daten grabben und aufbereiten:
Bitte vorsichtig sein, das grabben und aufbereiten der Daten kann extrem lange dauern. Fangt am besten mit einem oder 2 Sendern an, um einen ersten Eindruck zu bekommen.
cd ~/.wg++ ./run.sh
WebGrab++ in Crontab einbinden:
Einfach nur das Script aufzurufen hat bei mir nicht funktioniert. Ich habe deshalb screen verwenden müssen.
0 30 * * 1,4 /usr/bin/screen -dmS webgrab /home/<user z.B. pi>/.wg++/run.sh
Damit wird der Vorgang alle 3-4 Tage gestartet und generiert das Programm der nächsten Woche. Die entstandene datei könnte dann über Variante 2 weiter verarbeitet werden.
Variante 4 (RSS Daten einlesen):
Zuerst muss ein Service gefunden werden, der RSS zu JSON Daten konvertieren kann. Anbieten würde sich hier z.B. www.rss2json.com. Hier kann man sich kostenlos anmelden und einen API Key generieren.
httpmod Device anlegen:
Vergesst bitte nicht im unten stehenden Code euren API Key einzutragen!
defmod TV_JETZT_HAUPTSENDER HTTPMOD https://api.rss2json.com/v1/api.json?rss_url=http%3A%2F%2Fwww.texxas.de%2Ftv%2FhauptsenderJetzt.xml&api_key=<dein API Key>&order_by=pubDate&order_dir=asc&count=100 300 attr TV_JETZT_HAUPTSENDER userattr get01Name get01URL getEncode readingEncode attr TV_JETZT_HAUPTSENDER disable 1 attr TV_JETZT_HAUPTSENDER extractAllJSON 1 attr TV_JETZT_HAUPTSENDER get01Name update attr TV_JETZT_HAUPTSENDER get01URL https://api.rss2json.com/v1/api.json?rss_url=http%3A%2F%2Fwww.texxas.de%2Ftv%2FhauptsenderJetzt.xml&api_key=<dein API Key>&order_by=pubDate&order_dir=asc&count=100 attr TV_JETZT_HAUPTSENDER getEncode UTF-8 attr TV_JETZT_HAUPTSENDER readingEncode UTF-8 attr TV_JETZT_HAUPTSENDER timeout 10
www.texxas.de bietet weitere rss an, die man ebenfalls einbinden könnte. Wie man daraus dann eine readingsGroup erstellt, muss ich leider schuldig bleiben, ich habe diesen Ansatz nicht weiter verfolgt. Funktionieren würde er aber und das Download Volumen ist bei jeder Abfrage nur einige wenige kb.