Autor Thema: Fernsehprogramm DOIF (aktuell und primetime | non blocking | minimaler traffic)  (Gelesen 14418 mal)

Offline mumpitzstuff

  • Developer
  • Hero Member
  • ****
  • Beiträge: 1974
Ich habe mich mal hingesetzt und ein DOIF generiert, das die aktuellen Fernsehdaten einer Woche als xml von einem Server lädt (das DOIF macht das 1x alle 3-4 Tage) und daraus eine Programmzeitschrift generiert. Sowohl der Download als auch die Generierung geschehen non blocking. Es werden 2 Dinge generiert. Zum Einen die nächsten 3 Sendungen ab jetzt und zum Anderen die 3 Sendungen ab 20:15 Uhr. Die einzelnen Sendungen sind anklickbar und zeigen dann eine detaillierte Beschreibung zu der Sendung.

Nachdem das DOIF erstellt wurde, dauert es 5min bis die aktuellen Sendungen sichtbar werden. Die Prime Sendungen sind nach weiteren 5 Minuten sichtbar. Wenn die Prime Sendungen zwischen 20:15 Uhr und 0:00 aktualisiert werden, dann laufen sie quasi mit, da keine veralteten Sendungen angezeigt werden. Erst nach 0:30 werden dann die wirklichen Prime Sendungen des nächsten Tages (20:15 Uhr Sendungen) angezeigt.

Es gibt genau eine Vorbedingung, damit das DOIF funktioniert (alle Dinge ab 2. sind optional).

1.) XML::Bare muss mind. in der Version 0.53 installiert sein. Das kann man z.B. hiermit erledigen:

sudo apt-get install libxml-bare-perl
2.) Will man sich die Senderlogos anzeigen lassen, dann muss das Verzeichnis "/opt/fhem/www/images/default/tv" erstellt und die Rechte so gesetzt sein, das FHEM darauf zugreifen kann. Danach muss man die Senderlogos als PNGs in dieses Verzeichnis kopieren und ebenfalls die entsprechenden Rechte setzen. Die Dateien müssen die richtigen Namen besitzen! Diese kann man in der ersten Spalte der Darstellung sehen. Steht hier zum Beispiel "tv/ard" dann muss die Datei "/opt/fhem/www/images/default/tv/ard.png" heissen. Eine Quelle dafür ist z.B. (meine Logos kann ich leider aus rechtlichen Gründen hier nicht zur Verfügung stellen, aber höflich per PM fragen funktioniert vielleicht...):

https://github.com/3PO/Senderlogos/archive/master.zip

https://github.com/picons/picons/archive/master.zip

https://de.wikipedia.org/wiki/Liste_deutschsprachiger_Fernsehsender

SVG Logos gibt es z.B. hier (habe ich noch nie verwendet, sollte aber auch gehen):

https://commons.wikimedia.org/wiki/Category:SVG_logos_of_television_channels_and_networks?uselang=de

Ansonsten gibt es diverse Programmezeitschriften online, bei denen man sich die Bilder der Sender runterladen kann.

3.) Wenn man Sender hinzufügen möchte, dann kann man sich die original xml Dateien runterladen und die entsprechenden Sender raus suchen.

http://rytecepg.dyndns.tv/epg_data/

Danach muss man folgende Dinge anpassen (wenn man einen Sender entfernen möchte, muss man die entsprechenden Dinge ebenfalls anpassen):
a) Die Variable $_channelFilter.
b) Im Attribut uiTable muss man 2 Zeilen hinzufügen: "TPL_TV($SELF,next,<sender name>,<logo name>)" und weiter unten "TPL_TV($SELF,prime,<sender name>,<logo name>)"
c) Danach muss man noch die Formatierung ebenfalls im Attribut uiTable anpassen. Diese beginnen mit $TR und $TD.

Die xml Daten stellen jede Menge weiterer Sender zur Verfügung.

Unten habe ich auch mal ein Testscript dl.pl angehangen, womit man seinen channelfilter erst einmal überprüfen kann. Einfach den channelfilter im Script anpassen und ausführen und man sieht das Ergebnis erst einmal in einer Testdatei und kann, wenn alles funktioniert, das Regex ins DOIF übertragen. Es ist wichtig, das man immer den Text aus der id nimmt!

<channel id="ARD.de">
4.) Es stehen 2 Templates zur Verfügung. TPL_TV wird normalerweise verwendet und stellt das Programmlogo und 3 Sendezeiten dar. Darüber hinaus kann auch TPL_TVSET verwendet werden. Hier kann durch ein Klick auf das Programmlogo ein set Befehl an ein beliebiges FHEM Device geschickt werden, um z.B. den Fernsehsender aus FHEM heraus zu wechseln.

Beispiel:
TPL_TV($SELF,next,ARD,ard)kann ersetzt werden durch:
TPL_TVSET($SELF,next,ARD,ard,irblasterdevice,send IR_SAT_DasErste)
5.) Wenn man andere Sender oder mehr als die vorhandenen haben möchte, kann man z.B. hier sehen was es sonst noch alles gibt:

http://rytecepg.dyndns.tv/epg_data/

Im DOIF werden nur die beiden Dateien rytecDE_Basic.xz und rytecDE_Common.xz geladen und gemerged. Das bdedeutet, das man aktuell nur Sender aus diesen beiden Dateien anzeigen lassen kann. Es gibt aber die Möglichkeit weitere Dateien zu mergen und dann ebenfalls anzeigen zu lassen wie z.B. rytecDE_SportMovies.xz.

Dazu muss man einfach die Funktion "sub tvDownloadMerge()" suchen und diese ersetzen:

  sub tvDownloadMerge()
  {
    my $output = '';
   
    # other server
    # http://www.xmltvepg.nl/rytecDE_Basic.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz
    # http://www.xmltvepg.nl/rytecDE_Common.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_Common.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Common.xz 2>&1);
   
    tvMerge($_dataFile, $_path.'rytecDE_Common');

    # download and merge other files here if needed
   
    return $output;
  }

durch

  sub tvDownloadMerge()
  {
    my $output = '';
   
    # other server
    # http://www.xmltvepg.nl/rytecDE_Basic.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz
    # http://www.xmltvepg.nl/rytecDE_Common.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_Common.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_Common.xz 2>&1);
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz -O /opt/fhem/rytecDE_SportMovies.xz 2>&1);
    $output .= qx(xz -df /opt/fhem/rytecDE_SportMovies.xz 2>&1);
   
    tvMerge($_dataFile, $_path.'rytecDE_Common');
    tvMerge($_dataFile, $_path.'rytecDE_SportMovies');

    # download and merge other files here if needed
   
    return $output;
  }

ersetzen. Das Spiel lässt sich beliebig fortsetzen.


defmod doif_TEST DOIF subs\
{\
  use utf8;;\
  use Date::Parse;;\
  # sudo apt-get install libxml-bare-perl\
  use XML::Bare 0.53 qw(forcearray);;\
  use Blocking;;\
  #use Encode qw(encode_utf8 decode_utf8);;\
  \
  ### CONFIG AREA ###\
  $_channelFilter = qr/^(?:ARD\.|ZDF\.|Sat1\.|RTL2?\.|Pro(?:7|SiebenMaxx)\.|DMax\.|Vox\.|Kabel(?:EinsClassic|EinsDoku)?\.|ntv\.|Sixx\.|TLC\.|N24Doku\.|SonyEntertainmentTV\.|AandE\.|TNT(?:Serie|Film)\.|AnimalPlanet\.|History\.|Kinowelt\.|NatGeoHD\.|PLANET\.|Silverline\.|13thStreet\.|AXN\.|SciFi\.)/;;\
  # telnet port must not be password protected (open)\
  # this is used as fallback if telnet port cannot created automatically\
  $_telnetPort = 7072;;\
  # can be used to adjust the program times (mostly not needed!)\
  $_timeAdjust = 0;;\
  $_path = '/opt/fhem/';;\
  $_dataFile = $_path.'rytecDE_Basic';;\
  # enable/disable unused channel filtering on filemerge (enabled = small file = faster)\
  $_filterChannels = 1;;\
  # enable/disable updates based on starttimes (enabled = update channels only if needed = faster)\
  $_updateBasedOnStarttimes = 1;;\
  # enable/disable use of Time::Piece (timepiece is faster but not instaled on some systems)\
  $_timepiece = 0;;\
  \
  # internal variables\
  $_startTimes = ();;\
  \
  \
  sub filterText($)\
  {\
    my $text = shift;;\
\
    $text =~ s/[\x{0022}\x{0060}\x{003b}\x{0027}\"\`;;\'\r]//g;;\
    #$text =~ s/[\"\`;;\'\r]//g;;\
    $text =~ s/[\n]/<br>/g;;\
\
    return $text;;\
  }\
  \
  sub xmltv2epoch($)\
  {\
    my $t = shift;;\
\
    if ($_timepiece)\
    {\
      use Time::Piece;;\
      \
      # fast version\
      return Time::Piece->strptime($t, '%Y%m%d%H%M%S %z')->epoch;;\
    }\
    else\
    {\
      # slow but compatible version\
      substr($t, 8, 0) = 'T';;\
\
      return str2time($t);;\
    }\
  }\
\
  sub FmtDateTime($)\
  {\
    my @t = localtime(shift);;\
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d", $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0]);;\
  }\
  \
  sub createTelnet($)\
  {\
    my $device = shift;;\
    my $telnet = undef;;\
    \
    foreach my $d (sort keys %::defs) \
    { \
      next if ($d !~ /telnetForTvUpdateFn_\d+/);;\
      my $h = $::defs{$d};;\
      next if (!$h->{TYPE} || $h->{TYPE} ne 'telnet' || $h->{SNAME});;\
      next if (::AttrVal($d, 'allowfrom', '127.0.0.1') ne '127.0.0.1');;\
      next if ($h->{DEF} !~ /^\d+( global)?$/);;\
      next if ($h->{DEF} =~ /IPV6/);;\
\
      $telnet = $d;;\
      last;;\
    }    \
    \
    if (!defined($telnet))\
    {\
      $telnet = 'telnetForTvUpdateFn_'.time();;\
      my $ret = ::CommandDefine(undef, "-temporary $telnet telnet 0");;\
    \
      if (defined($ret))\
      {\
        ::Log3 $device, 1, $device.': Cannot create telnet port ('.$ret.')';;\
        return undef;;\
      }\
    \
      $::attr{$telnet}{room} = 'hidden';;\
      $::attr{$telnet}{allowfrom} = '127.0.0.1';;\
    }\
    \
    return $::defs{$telnet}{PORT};;\
  }\
\
  sub tvParse($$$)\
  {\
    my ($device, $mode, $port) = @_;;\
    my $obj;;\
    my $xml;;\
    my $lastChannel = '';;\
    my $reading = '';;\
    my $i = 999;;\
    my $n = 999;;\
    my $k = 0;;\
    my $primeTime = substr(FmtDateTime(time() + $_timeAdjust), 0, 11).'20:14:00';;\
    my $sendTelnet = '';;\
    \
    $obj = XML::Bare->new(file => $_dataFile);;\
    $xml = $obj->parse();;\
\
    if (!$@)\
    {\
      my $old = time() + $_timeAdjust;;\
\
      foreach (@{forcearray($xml->{'tv'}{'programme'})})\
      {\
        if ((0 != $_filterChannels) ||\
            ($_->{'channel'}{'value'} =~ $_channelFilter))\
        {\
          my $stop = xmltv2epoch($_->{'stop'}{'value'});;\
\
          # filter old stuff\
          if ($stop > $old)\
          {\
            if ($lastChannel ne $_->{'channel'}{'value'})\
            {\
              $lastChannel = $_->{'channel'}{'value'};;\
              $reading = $_->{'channel'}{'value'};;\
              $reading =~ s/[\.\s]//g;;\
              $reading =~ s/de$//;;\
              $n = 0;;\
               \
              if ((0 == $_updateBasedOnStarttimes) || !exists($_startTimes{$reading}) || ($_startTimes{$reading} <= $old))\
              {\
                $i = 0;;\
\
                if (0 != $_updateBasedOnStarttimes)\
                {\
                  $_startTimes{$reading} = $stop;;\
                }\
              }\
              else\
              {\
                ::Log3 $device, 4, $device.': '.$reading.' is blocked because actual program is not finished (start: '.$_startTimes{$reading}.', old: '.$old.').';;\
              }\
            }\
\
            if ($i < 3 && 'next' eq $mode)\
            {\
              my $fi = sprintf("%03d", $i);;\
              my $start = xmltv2epoch($_->{'start'}{'value'});;\
              my $readingName;;\
              my $readingValue;;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_bdate';;\
              $readingValue = substr(FmtDateTime($start), 0, 10);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_btime';;\
              $readingValue = substr(FmtDateTime($start), 11, 8);;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_title';;\
              $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_stitle';;\
              if (exists($_->{'sub-title'}{'value'}))\
              {\
                $readingValue = filterText($_->{'sub-title'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $readingName = 'next_'.$reading.'_'.$fi.'_desc';;\
              if (exists($_->{'desc'}{'value'}))\
              {\
                $readingValue = filterText($_->{'desc'}{'value'});;\
              }\
              else\
              {\
                $readingValue = 'na';;\
              }\
              $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
              $k++;;\
              $i++;;\
            }\
\
            if ($n < 3 && 'prime' eq $mode)\
            {\
              my $start = xmltv2epoch($_->{'start'}{'value'});;\
              my $fmtStart = FmtDateTime($start);;\
              my $bdate = substr($fmtStart, 0, 10);;\
              my $btime = substr($fmtStart, 11, 8);;\
\
              if ($bdate.' '.$btime gt $primeTime)\
              {\
                my $fn = sprintf("%03d", $n);;\
                my $readingName;;\
                my $readingValue;;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_bdate';;\
                $readingValue = substr(FmtDateTime($start), 0, 10);;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_btime';;\
                $readingValue = substr(FmtDateTime($start), 11, 8);;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_title';;\
                $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});;\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_stitle';;\
                if (exists($_->{'sub-title'}{'value'}))\
                {\
                  $readingValue = filterText($_->{'sub-title'}{'value'});;\
                }\
                else\
                {\
                  $readingValue = 'na';;\
                }\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $readingName = 'prime_'.$reading.'_'.$fn.'_desc';;\
                if (exists($_->{'desc'}{'value'}))\
                {\
                  $readingValue = filterText($_->{'desc'}{'value'});;\
                }\
                else\
                {\
                  $readingValue = 'na';;\
                }\
                $sendTelnet .= ";;setreading $device $readingName $readingValue";;\
\
                $k++;;\
                $n++;;\
              }\
            }\
\
            if ($k >= 10)\
            {\
              #::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
              \
              `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
              \
              $k = 0;;\
              $sendTelnet = '';;\
            }\
          }\
        }\
      }\
\
      if ('' ne $sendTelnet)\
      {\
        #::Log3 $device, 5, $device.': '.encode_utf8($sendTelnet);;\
        \
        `perl /opt/fhem/fhem.pl $port "$sendTelnet"`;;\
      }\
    }\
    \
    return %{$_startTimes};;\
  }\
  \
  sub tvMerge($;;$)\
  {\
    my ($dstName, $srcName) = @_;;\
    my $fh;;\
    my $dst;;\
    my $src;;\
    my $start = '';;\
    my $channels1 = '';;\
    my $channels1_flt = '';;\
    my $channels2 = '';;\
    my $channels2_flt = '';;\
    my $programms1 = '';;\
    my $programms1_flt = '';;\
    my $programms2 = '';;\
    my $programms2_flt = '';;\
    my $end = '';;\
    my $pos;;\
\
    open($fh, '<', $dstName) or die "Can't open file $!";;\
    read($fh, $dst, -s $fh);;\
    close($fh);;\
\
    if (defined($srcName))\
    {\
      open($fh, '<', $srcName) or die "Can't open file $!";;\
      read($fh, $src, -s $fh);;\
      close($fh);;\
    }\
\
    if (-1 != ($pos = index($dst, '<channel ')))\
    {\
      $start = substr($dst, 0, $pos);;\
    }\
\
    if (-1 != ($pos = rindex($dst, '</programme>')))\
    {\
      $end = substr($dst, $pos + 12);;\
    }\
\
    while ($dst =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $channels1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $channels1 .= $1;;\
      }\
    }\
\
    while ($dst =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
    {\
      if (0 != $_filterChannels)\
      {\
        $_ = $1;;\
\
        if ($2 =~ $_channelFilter)\
        {\
          $programms1_flt .= $_;;\
        }\
      }\
      else\
      {\
        $programms1 .= $1;;\
      }\
    }\
\
    if (defined($srcName))\
    {\
      while ($src =~ /(\s*<channel\s.*?id="(.*?)".*?<\/channel>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $channels2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $channels2 .= $1;;\
        }\
      }\
\
      while ($src =~ /(\s*<programme\s.*?channel="(.*?)".*?<\/programme>)/sg)\
      {\
        if (0 != $_filterChannels)\
        {\
          $_ = $1;;\
\
          if ($2 =~ $_channelFilter)\
          {\
            $programms2_flt .= $_;;\
          }\
        }\
        else\
        {\
          $programms2 .= $1;;\
        }\
      }\
    }\
\
    if (0 != $_filterChannels)\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1_flt.$channels2_flt.$programms1_flt.$programms2_flt.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1_flt.$programms1_flt.$end;;\
      }\
\
      close($fh);;\
    }\
    else\
    {\
      open($fh, '>', $dstName) or die "Can't open file $!";;\
\
      if (defined($srcName))\
      {\
        print $fh $start.$channels1.$channels2.$programms1.$programms2.$end;;\
      }\
      else\
      {\
        print $fh $start.$channels1.$programms1.$end;;\
      }\
\
      close($fh);;\
    }\
  }\
\
  sub tvDownload()\
  {\
    my $output = '';; \
    \
    # other server\
    # http://www.xmltvepg.nl/rytecDE_Basic.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz\
    # http://www.xmltvepg.nl/rytecDE_Common.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz\
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz\
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);;\
\
    if (0 != $_filterChannels)\
    {\
      tvMerge($_dataFile);;\
    }\
    \
    return $output;;\
  }\
\
  sub tvDownloadMerge()\
  {\
    my $output = '';; \
    \
    # other server\
    # http://www.xmltvepg.nl/rytecDE_Basic.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Basic.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_Common.xz\
    # http://www.xmltvepg.nl/rytecDE_Common.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_Common.xz\
    # http://www.vuplus-community.net/rytec/rytecDE_SportMovies.xz\
    # http://www.xmltvepg.nl/rytecDE_SportMovies.xz\
    # http://91.121.106.172/~rytecepg/epg_data/rytecDE_SportMovies.xz\
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Basic.xz -O /opt/fhem/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(xz -df /opt/fhem/rytecDE_Basic.xz 2>&1);;\
    $output .= qx(wget http://www.vuplus-community.net/rytec/rytecDE_Common.xz -O /opt/fhem/rytecDE_Common.xz 2>&1);;\
    $output .= qx(xz -df /opt/fhem/rytecDE_Common.xz 2>&1);;\
    \
    tvMerge($_dataFile, $_path.'rytecDE_Common');;\
\
    # download and merge other files here if needed\
    \
    return $output;;\
  }\
    \
  sub startDownload($)\
  {\
    my $name = shift;;\
    \
    # prevent download spamming\
    if (-e $_dataFile)\
    {\
      my $ftime = ((time() - (stat($_dataFile))[9]) / 60.0 / 60.0 / 24.0);;\
      \
      if ($ftime < 1.0)\
      {\
        ::Log3 $name, 1, $name.': Download of TV data skipped because file is not older than 1 day ('.($ftime).').';;\
        return;;\
      }\
    }\
    \
    if (defined($_blockingcalls{PID_DOWNLOAD}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (download).';;\
\
      ::BlockingKill($_blockingcalls{PID_DOWNLOAD});;\
    }\
\
    $_blockingcalls{PID_DOWNLOAD} = ::BlockingCall('DOIF::doDownload', $name, 'DOIF::endDownload', 300, 'DOIF::abortDownload', $name);;\
  }\
  \
  sub DOIF::doDownload($)\
  {\
    my $name = shift;;\
    my $output = '';;\
    \
    $output = tvDownloadMerge();;\
    \
    return $name.'|'.$output;;\
  }\
  \
  sub DOIF::endDownload($)\
  {\
    my ($name, $output) = split("\\|", shift);;\
    \
    ::Log3 $name, 5, $name.': '.$output;;\
    ::Log3 $name, 4, $name.': Blocking call finished to download tv data.';;\
    \
    delete($_blockingcalls{PID_DOWNLOAD});;\
  }\
  \
  sub DOIF::abortDownload($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_DOWNLOAD});;\
    \
    ::Log3 $name, 1, $name.': Blocking call aborted (download).';;\
  }\
  \
  sub startParse($$)\
  {\
    my ($name, $mode) = @_;;\
    my $port;;\
    \
    if (defined($_blockingcalls{PID_PARSE}))\
    {\
      ::Log3 $name, 3, $name.': Blocking call already running (parse).';;\
\
      ::BlockingKill($_blockingcalls{PID_PARSE});;\
    }\
    \
    $port = createTelnet($name);;\
    $port = $_telnetPort if (!defined($port));;\
    \
    $_blockingcalls{PID_PARSE} = ::BlockingCall('DOIF::doParse', $name.'|'.$mode.'|'.$port, 'DOIF::endParse', 300, 'DOIF::abortParse', $name);;\
  }\
  \
  sub DOIF::doParse($)\
  {\
    my ($name, $mode, $port) = split("\\|", shift);;\
    my $ret = $name;;\
    my %startTimes = tvParse($name, $mode, $port);;\
    \
    foreach (keys(%startTimes))\
    {\
      $ret .= '|'.$_.'|'.$startTimes{$_};;\
    }\
    \
    return $ret;;\
  }\
  \
  sub DOIF::endParse($)\
  {\
    my ($name, @startTimes) = split("\\|", shift);;\
        \
    for (my $i = 0;; $i < (scalar(@startTimes) / 2);; $i += 2)\
    {\
      $_startTimes{$startTimes[$i]} = $startTimes[$i + 1];;\
    }\
    \
    ::Log3 $name, 4, $name.': Blocking call finished to parse tv data.';;\
    \
    delete($_blockingcalls{PID_PARSE});;\
  }\
  \
  sub DOIF::abortParse($)\
  {\
    my $name = shift;;\
    \
    delete($_blockingcalls{PID_PARSE});;\
    \
    ::Log3 $name, 1, $name.': Blocking call aborted (parse).';;\
  }\
}\
init\
{\
  startDownload("$SELF");;\
  set_Exec('init_next', 300, 'startParse("$SELF", "next")');;\
  set_Exec('init_prime', 600, 'startParse("$SELF", "prime")');;\
}\
{\
  if ([00:05|Mo Do])\
  {\
    startDownload("$SELF");;\
  }\
  \
  if ([+00:15])\
  {\
    startParse("$SELF", 'next');;\
  }\
  \
  if ([00:30])\
  {\
    startParse("$SELF", 'prime');;\
  }\
}
attr doif_TEST alias Aktuelles TV-Programm
attr doif_TEST room TEST
attr doif_TEST uiTable {\
  package ui_Table;;\
\
  $SHOWNOSTATE = 1;;\
  $ATTRIBUTESFIRST = 1;;\
  \
  $TR{0,31} = "style='color:yellow;;text-align:center;;font-weight:bold;;font-size:18px'";;\
  $TD{0..29,31..60}{2,4} = "style='font-size:16px;;border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..29,31..60}{0} = "align='center' style='border-right-style:solid;;border-color:#CCCCCC;;border-right-width:1px;;'";;\
  $TD{0..60}{1,3,5,6} = "style='font-size:16px;;'";;\
  $TD{30}{0..6} = "style='border-top-style:solid;;border-bottom-style:solid;;border-color:#CCCCCC;;border-top-width:1px;;border-bottom-width:1px;;'";;\
\
  sub showIcon\
  {\
    my ($icon, $device, $state) = @_;;\
    \
    if (defined($device) && defined($state))\
    {\
      return "<a href=\"$::FW_ME?cmd=set $device $state$::FW_CSRF\">".ICON("tv/$icon")."</a>";;\
    }\
    else\
    {\
      return ICON("tv/$icon");;\
    }\
  }\
  \
  sub unfold\
  {\
    my ($title, $desc) = @_;;\
    \
    $title = 'na' if (!defined($title));;\
    $desc = 'na'."\n\n".'na' if (!defined($desc));;\
    \
    $title =~ s/(.{1,45}|\S{46,})(?:\s[^\S\r\n]*|\Z)/$1<br>/g;;\
    $desc =~ s/<br>/\n/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(&#39;;".$desc."&#39;;)\">".$title."</a>";;\
  }\
}\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo)\
DEF TPL_TV(showIcon("$4",undef,undef)|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
## parameter: device name, mode (next or prime), channel name (see xml data file), icon name (filename of channel logo), device name for set command, command\
DEF TPL_TVSET(showIcon("$4","$5","$6")|substr([$1:$2_$3_000_btime],0,5)|unfold([$1:$2_$3_000_title],[$1:$2_$3_000_stitle]."\n\n".[$1:$2_$3_000_desc])|substr([$1:$2_$3_001_btime],0,5)|unfold([$1:$2_$3_001_title],[$1:$2_$3_001_stitle]."\n\n".[$1:$2_$3_001_desc])|substr([$1:$2_$3_002_btime],0,5)|unfold([$1:$2_$3_002_title],[$1:$2_$3_002_stitle]."\n\n".[$1:$2_$3_002_desc]))\
\
"Sender"|"ab"|"Aktuelle Sendung"|"ab"|"Nächste Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,next,ARD,ard)\
TPL_TV($SELF,next,ZDF,zdf)\
TPL_TV($SELF,next,Sat1,sat1)\
TPL_TV($SELF,next,RTL,rtl)\
TPL_TV($SELF,next,RTL2,rtl2)\
TPL_TV($SELF,next,Pro7,pro7)\
TPL_TV($SELF,next,DMax,dmax)\
TPL_TV($SELF,next,Vox,vox)\
TPL_TV($SELF,next,Kabel,kabel1)\
TPL_TV($SELF,next,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,next,13thStreet,13thstreet)\
TPL_TV($SELF,next,Silverline,silverline)\
TPL_TV($SELF,next,TNTFilm,tntfilm)\
TPL_TV($SELF,next,AXN,axn)\
TPL_TV($SELF,next,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,next,Kinowelt,kinowelt)\
TPL_TV($SELF,next,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,next,Sixx,sixx)\
TPL_TV($SELF,next,TNTSerie,tntserie)\
TPL_TV($SELF,next,SciFi,syfy)\
TPL_TV($SELF,next,ntv,ntv)\
TPL_TV($SELF,next,N24Doku,n24)\
TPL_TV($SELF,next,History,history)\
TPL_TV($SELF,next,PLANET,planet)\
TPL_TV($SELF,next,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,next,AnimalPlanet,animalplanet)\
TPL_TV($SELF,next,NatGeoHD,natgeo)\
TPL_TV($SELF,next,TLC,tlc)\
TPL_TV($SELF,next,AandE,ae)\
"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"|"&nbsp;;"\
"Sender"|"ab"|"Sendung"|"ab"|"Sendung"|"ab"|"Sendung"\
TPL_TV($SELF,prime,ARD,ard)\
TPL_TV($SELF,prime,ZDF,zdf)\
TPL_TV($SELF,prime,Sat1,sat1)\
TPL_TV($SELF,prime,RTL,rtl)\
TPL_TV($SELF,prime,RTL2,rtl2)\
TPL_TV($SELF,prime,Pro7,pro7)\
TPL_TV($SELF,prime,DMax,dmax)\
TPL_TV($SELF,prime,Vox,vox)\
TPL_TV($SELF,prime,Kabel,kabel1)\
TPL_TV($SELF,prime,KabelEinsClassic,kabel1classic)\
TPL_TV($SELF,prime,13thStreet,13thstreet)\
TPL_TV($SELF,prime,Silverline,silverline)\
TPL_TV($SELF,prime,TNTFilm,tntfilm)\
TPL_TV($SELF,prime,AXN,axn)\
TPL_TV($SELF,prime,SonyEntertainmentTV,sonytv)\
TPL_TV($SELF,prime,Kinowelt,kinowelt)\
TPL_TV($SELF,prime,ProSiebenMaxx,pro7maxx)\
TPL_TV($SELF,prime,Sixx,sixx)\
TPL_TV($SELF,prime,TNTSerie,tntserie)\
TPL_TV($SELF,prime,SciFi,syfy)\
TPL_TV($SELF,prime,ntv,ntv)\
TPL_TV($SELF,prime,N24Doku,n24)\
TPL_TV($SELF,prime,History,history)\
TPL_TV($SELF,prime,PLANET,planet)\
TPL_TV($SELF,prime,KabelEinsDoku,kabel1doku)\
TPL_TV($SELF,prime,AnimalPlanet,animalplanet)\
TPL_TV($SELF,prime,NatGeoHD,natgeo)\
TPL_TV($SELF,prime,TLC,tlc)\
TPL_TV($SELF,prime,AandE,ae)
« Letzte Änderung: 06 November 2020, 22:12:00 von Damian »
Gefällt mir Gefällt mir x 3 Zustimmung Zustimmung x 1 Hilfreich Hilfreich x 1 Liste anzeigen

Online Damian

  • Moderator
  • Hero Member
  • ***
  • Beiträge: 8698
Ich setze den Post für ne Weile hoch. Es könnte für den einen oder anderen interessant sein. Es ist offenbar etwas mehr als nur DOIF-DOELSEIF-DOELSE, das, was die meisten unter DOIF verstehen ;)
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF
Gefällt mir Gefällt mir x 1 Liste anzeigen

Offline cwagner

  • Sr. Member
  • ****
  • Beiträge: 668
Ich setze den Post für ne Weile hoch. Es könnte für den einen oder anderen interessant sein. Es ist offenbar etwas mehr als nur DOIF-DOELSEIF-DOELSE, das, was die meisten unter DOIF verstehen ;)
Diese "Adelung" ist für mich gerechtfertigt - ein toller Showcase für die Mächtigkeit von DOIF.

Christian
Raspi 2B+3B: Raspbian 9.11,Perl v5.28.1, FHEM 5.9. 270 Entities in DbLog  für Heizung mit FBH, Solarthermie, kontr. Lüftung mit WRG. Smarthome u.a. HM (CUL), 1-Wire (FT232RL & DS2480B), EnOcean (TCM EPS3), MQTT2. Im Einsatz u.a. DOIF, PID20, Threshold, OWX NewGen; Micropelt IRTV, Volkszähler

Offline amenomade

  • Developer
  • Hero Member
  • ****
  • Beiträge: 7449
Warum der Umweg über Telnet ? Wenn ich nichts übersehen habe, machst Du nur "setreading" Kommandos?

EDIT: ah ok verstanden. Du machst verschiedene Sachen in externalisierten Prozesse.
« Letzte Änderung: 13 Juni 2020, 18:37:30 von amenomade »
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

Offline mumpitzstuff

  • Developer
  • Hero Member
  • ****
  • Beiträge: 1974
Ich habe zuerst versucht die Daten als return zurück zu geben, aber das hat mir das gesamte System abstürzen lassen. Der Weg über Telnet ging dagegen erst einmal problemlos. Ich bin aber noch dran und versuche genau diesen Punkt noch zu optimieren. Vielleicht finde ich noch einen eleganteren Weg.

Offline mumpitzstuff

  • Developer
  • Hero Member
  • ****
  • Beiträge: 1974
Es ist leider nicht möglich auf den separaten Telnet Port zu verzichten. Wenn das Blocking Modul alle Daten auf einmal per Telnet aus dem Fork in den Hauptprozess pushen will, dann geschehen sehr merkwürdige Dinge aufgrund der Menge an Daten. Genaueres konnte ich leider nicht rausbekommen, aber der Datentransfer im Blocking Modul stürzt entweder komplett ab oder überträgt nur einen Teil der Daten. Das endet irgndwann im Datenchaos. Ich muss daher erst einmal bei dieser Variante bleiben. Ich könnte lediglich versuchen, so wie das Blocking Modul auch, eine temporäre Telnet Verbindung zu erstellen und nach der Übertragung wieder zu löschen. Dann muss sich der Anwender nicht darum kümmern.

Offline Invers

  • Hero Member
  • *****
  • Beiträge: 2084
Hi mumpitzstuff. Super Sache. Habe ich so toll noch nicht gesehen. Danke.

Ich habe auch mal probiert.
Bei mir dauerte es lange, bis etwas passierte. Das stört mich aber nicht.

Die Senderlogos sehe ich nicht. Vermutlich, weil Pfad und Dateien nicht existieren.
Verrätst du mir, woher du die geladen hast?
Pi3B Buster | F.-Box 7490 | CUL433 | CUL868 | SDuino + Siro | HM-LAN | 12 x Dect200  | 3 x Heizung FHT + FKont. | KeyMatic + 4 FB | HM Wandtaster 2-fach m. LED | 6 x TKont. TFK-TI | HM-Bew.-Melder aussen + innen | 3 x Smoked. HM-SEC-SD-2

Offline carlos

  • Developer
  • Full Member
  • ****
  • Beiträge: 417
Ich habe sie mir mal von
https://download.avm.de/tv/
geholt und nach /opt/fhem/www/images/tv kopiert.

Funktioniert aber nicht!

Gruß

Carlos
« Letzte Änderung: 14 Juni 2020, 11:23:05 von carlos »
FHEM svn auf Intel NUC mit proxmox,1 UDOO, 3 Raspberry Pi, signalduino, nanoCUL, div. Homematic Komponenten, toom Baumarkt Funksteckdosen, einige sonoffs, hue, shelly

Offline amenomade

  • Developer
  • Hero Member
  • ****
  • Beiträge: 7449
Ich habe sie mir mal von
https://download.avm.de/tv/
geholt und nach /opt/fhem/www/images/tv kopiert.

Funktioniert aber nicht!

Gruß

Carlos

Klar. Wenn Du eine andere Quelle benutzt, musst Du natürlich die Parse Funktion entspr. anpassen.
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

Offline carlos

  • Developer
  • Full Member
  • ****
  • Beiträge: 417
Die werden aber bei mir und bei invers überhaupt nicht angezeigt, da steht z.b. nur "tv/ard".

Gruß

Carlos
« Letzte Änderung: 14 Juni 2020, 12:34:10 von carlos »
FHEM svn auf Intel NUC mit proxmox,1 UDOO, 3 Raspberry Pi, signalduino, nanoCUL, div. Homematic Komponenten, toom Baumarkt Funksteckdosen, einige sonoffs, hue, shelly

Offline Invers

  • Hero Member
  • *****
  • Beiträge: 2084
Genau so ist es leider. Keine Anzeige.
Pi3B Buster | F.-Box 7490 | CUL433 | CUL868 | SDuino + Siro | HM-LAN | 12 x Dect200  | 3 x Heizung FHT + FKont. | KeyMatic + 4 FB | HM Wandtaster 2-fach m. LED | 6 x TKont. TFK-TI | HM-Bew.-Melder aussen + innen | 3 x Smoked. HM-SEC-SD-2

Offline amenomade

  • Developer
  • Hero Member
  • ****
  • Beiträge: 7449
Genau so ist es leider. Keine Anzeige.

Gut... von mir falsch verstanden. Ihr meint die Icons?
Dann macht bitte ein ls -la /opt/fhem/www/images/tv
Und ein "list" vom DOIF kann sowieso nicht schaden.
« Letzte Änderung: 14 Juni 2020, 13:05:22 von amenomade »
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

Offline Invers

  • Hero Member
  • *****
  • Beiträge: 2084
ls: Zugriff auf '/opt/fhem/www/images/tv' nicht möglich: Datei oder Verzeichnis nicht gefunden
p

hätte ich dir aber auch so sagen können. Deshalb fragte ich ja, woher die Icons kommen.
Pi3B Buster | F.-Box 7490 | CUL433 | CUL868 | SDuino + Siro | HM-LAN | 12 x Dect200  | 3 x Heizung FHT + FKont. | KeyMatic + 4 FB | HM Wandtaster 2-fach m. LED | 6 x TKont. TFK-TI | HM-Bew.-Melder aussen + innen | 3 x Smoked. HM-SEC-SD-2

Offline carlos

  • Developer
  • Full Member
  • ****
  • Beiträge: 417
Bei mir 1 zu 1 aus deinem ersten Beitrag kopiert.
Das verzeichnis /opt/fhem/www/images/tv  gab es bei mir nicht.
Da habe ich die logos von AVM hinkopiert.
Gruß

Carlos

FHEM svn auf Intel NUC mit proxmox,1 UDOO, 3 Raspberry Pi, signalduino, nanoCUL, div. Homematic Komponenten, toom Baumarkt Funksteckdosen, einige sonoffs, hue, shelly

Offline Invers

  • Hero Member
  • *****
  • Beiträge: 2084
Ich habe da noch eine Zusatzfrage: Wo finde ich denn die Schreibweise des Senders, wenn ich das DOIF um Tele5 erweitern möchte?
Pi3B Buster | F.-Box 7490 | CUL433 | CUL868 | SDuino + Siro | HM-LAN | 12 x Dect200  | 3 x Heizung FHT + FKont. | KeyMatic + 4 FB | HM Wandtaster 2-fach m. LED | 6 x TKont. TFK-TI | HM-Bew.-Melder aussen + innen | 3 x Smoked. HM-SEC-SD-2

 

decade-submarginal