Aktuelles TV-Programm in FHEM

Begonnen von Kuzl, 20 Oktober 2014, 20:41:43

Vorheriges Thema - Nächstes Thema

ch.eick

Sooo, ich mach mal für heute schluss....

$ date;time perl /opt/fhem/tv/tv.pl dmy_TV parse_next;date
Di 12. Mär 18:32:37 CET 2019
real    1m13.801s                        <=== Nur die aktuellen TV Sendungen (parse_next)
user    0m17.130s
sys     0m0.860s
Di 12. Mär 18:33:51 CET 2019

$ date;time perl /opt/fhem/tv/tv.pl dmy_TV parse;date
Di 12. Mär 18:35:04 CET 2019
real    2m2.138s                        <=== Und hier alle TV Sendungen (parse)
user    0m17.370s
sys     0m0.800s
Di 12. Mär 18:37:06 CET 2019

Nun könnte man einmal am Tag alle Sendungen parsen und dazwischen z.B. alle 15 Minuten die aktuellen Sendungen mit dem Parameter parse_next.
Der zeitliche Unterschied auf meinem RPi 2 ist beachtlich, wenn man bedingt dass es zu beginn ca 8 Minuten gedauert hat.

Hier nun der geänderte Code für tv.pl

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Date::Parse;
use Encode qw(encode_utf8 decode_utf8);
use XML::Bare 0.53 qw(forcearray);
use Data::Dumper;

my $channelFilter = qr/^(?:ZDFneo|ARD|ZDF|RTL|Sat1|RTL2|Pro7|WELT|ntv|3sat|Vox|Kabel|Sixx)/;
my $timeAdjust = 0;

#my $channelFilter = qr/^(?:ARD|ZDF|Sat1|RTL|RTL2|Pro7|DMax|Vox|Kabel)/;
#my $channelFilter = qr/^(?:ARD|ZDF|SAT\.1|RTL$|RTL II|PRO 7|DMAX|VOX|KABEL 1)/;
#my $timeAdjust = 86400;


my $redt = qr/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(?:\s+([+-]\d{4}))?$/;


sub xmltv2epoch($)
{
  my $dt = shift;
 
  if ($dt =~ $redt)
  {
    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 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 filterText($)
{
  my $text = shift;
 
  $text =~ s/["`;'\r]//g;
  $text =~ s/[\n]/<br>/g;
 
  return $text;
}

sub tvParse($$)
{
#  my $device = shift;
  my ($device, $mode) = @_;

  my $obj = XML::Bare->new(file => '/opt/fhem/tv/rytecDE_Basic');
  my $xml = $obj->parse();
  my $lastChannel = '';
  my $reading = '';
  my $i = 0;
  my $n = 0;
  my $primeTime = substr(FmtDateTime(time() - $timeAdjust), 0, 11).'20:14:00';
  my $sendTelnet = '';
  my $sendTelnetLarge = '';

  if (!$@)
  {
    foreach (@{forcearray($xml->{'tv'}{'programme'})})
    {
      if ($_->{'channel'}{'value'} =~ $channelFilter)
      {

        my $stop = str2time(xmltv2epoch($_->{'stop'}{'value'}));

        # filter old stuff
        if (($stop + $timeAdjust) >= time())
        {
          if ($lastChannel ne $_->{'channel'}{'value'})
          {
            $lastChannel = $_->{'channel'}{'value'};
            $reading = $_->{'channel'}{'value'};
            $reading =~ s/[\.\s]//g;
            $reading =~ s/de$//;
            $i = 0;
            $n = 0;
#            print "Sender: ".$reading."\n\n";
          }

          if ($i < 3)
          {
            my $fi = sprintf("%03d", $i);
            my $start = str2time(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, 5);
#            $readingValue = substr(FmtDateTime($start), 11, 8);
            $sendTelnet .= ";setreading $device $readingName $readingValue";
           
            $readingName = 'next_'.$reading.'_'.$fi.'_edate';
            $readingValue = substr(FmtDateTime($stop), 0, 10);
            $sendTelnet .= ";setreading $device $readingName $readingValue";
           
            $readingName = 'next_'.$reading.'_'.$fi.'_etime';
            $readingValue = substr(FmtDateTime($stop), 11, 5);
#            $readingValue = substr(FmtDateTime($stop), 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";

#            print "next: ".$sendTelnet."\n\n";           
#            my $result = `perl /opt/fhem/fhem.pl 7072 "$sendTelnet"`;

            $sendTelnetLarge .= $sendTelnet.";";

            $i++;
          }
         
# If mode parse_next then skip prime time
          if ($n < 3 && $mode ne 'parse_next')
          {
            my $start = str2time(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, 5);
#              $readingValue = substr(FmtDateTime($start), 11, 8);
              $sendTelnet .= ";setreading $device $readingName $readingValue";
             
              $readingName = 'prime_'.$reading.'_'.$fn.'_edate';
              $readingValue = substr(FmtDateTime($stop), 0, 10);
              $sendTelnet .= ";setreading $device $readingName $readingValue";
             
              $readingName = 'prime_'.$reading.'_'.$fn.'_etime';
              $readingValue = substr(FmtDateTime($stop), 11, 5);
#              $readingValue = substr(FmtDateTime($stop), 11, 8);
              $sendTelnet .= ";setreading $device $readingName $readingValue";
             
              $readingName = 'prime_'.$reading.'_'.$fn.'_title';
              $readingValue = filterText(@{forcearray($_->{'title'})}[0]->{'value'});
              $sendTelnet .= ";setreading $device $readingName $readingValue";
             
              #print $readingValue."\n";
             
              $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";

#              print "prime: ".$sendTelnet."\n\n";             
#              my $result = `perl /opt/fhem/fhem.pl 7072 "$sendTelnet"`;

              $sendTelnetLarge .= $sendTelnet.";";
                           
              $n++;
            }
          }
        }
      }
    }

#   print "\n\n".$sendTelnetLarge."\n\n";
    system('/opt/fhem/fhem.pl 7072 "'.$sendTelnetLarge.'"');

#    print "\n\n".$sendTelnet."\n\n";             
#    system('/opt/fhem/fhem.pl 7072 "'.$sendTelnet.'"');
  }
}


sub tvDownload()
{
  # 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
  my $output = qx(wget http://www.vuplus-community.net/rytec/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;
}


my $d = shift || die "Need a device!\n";
my $m = shift || die "Need a mode!\n";

if ('download' eq $m)
{
  tvDownload();
}
elsif ('parse' eq $m || 'parse_next' eq $m)
{
  tvParse($d,$m);
}

exit;


Viele Grüße
     Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

mumpitzstuff

Okay ich gucke es mir mal an und lasse es auch bei mir laufen. Wenn alles passt, kann ich es ja ins Wiki übernehmen.

ch.eick

#992
Hallo nochmal,

ich hatte dann noch eine blocking Situation mit dem at Kommando.

  • Wenn das at Kommando das Skript tv.pl ausgeführt hat, dann wurde bis zum Ende gewartet.
  • Das Skript lief dann und hat am Ende die setreadings zum FHEM gesendet.
  • Durch den noch laufenden tv.pl Prozessaufruf aus dem at Kommando wurden dann dann die setreadings nicht bearbeitet. (dead lock)
  • Erst nach dem kill vom tv.pl Prozess wurde dann alles problemlos erledigt.

Die Lösung hierfür ist den tv.pl Prozess mit "&" als eigenständigen Prozess laufen zu lassen.
Mit dem Update vom FHEM durch die setreadings ist dann wieder alles syncron am Ende.

Zu beachten ist jedoch, dass FHEM dann den Prozess nicht überwacht. Einen Fehler würde man dann erst feststellen,
wenn die EPG Informationen im dummy nicht aktuell wären.

Hier kommen dann noch die beiden (mit download drei) at definitionen

# Download zwei mal die Woche kurz nach Mitternacht
defmod at_TV_DOWNLOAD at *00:15:00 {if ((1 == $wday) || (4 == $wday)) {system("perl /opt/fhem/tv/tv.pl dmy_TV download")}}

# Das aktuelle Programm alle 15 Minuten weiter rutschen lassen
defmod at_TV_next at +*00:15:00  {system("perl /opt/fhem/tv/tv.pl dmy_TV parse_next &")}

# Das komplette Programm inklusive Primetime aktualisieren
defmod at_TV_prime at *01:17:00 {system("perl /opt/fhem/tv/tv.pl dmy_TV parse &")}


Viele Grüße
   Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

mumpitzstuff

#993
Wenn man die Definitionen genau wie angegeben macht, dann wird das bereits non Blocking ausgeführt und man braucht kein & oder sonstwas (laut Aussage von Fhem Entwickler).

defmod at_TV_UPDATE at +*00:15:00 "perl /opt/fhem/tv/tv.pl dmy_TV parse"

ch.eick

Ich kann nur von meinen Tests Rückschlüsse schließen.
Seit ich es im Hintergrund (mit &) laufen lasse ist soweit alles okay.
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

budy

Ich würde mal sagen, dass es daran liegt, dass du Perl im at über system() aufrufst. Da brauchst du doch gar nicht und dann blockiert es auch nicht.

Gruß,
budy
Debian stretch, FHEM 5.9.
HM-CC-RT-DN, HM-ES-PMSw1-Pl, HM-LC-Dim1TPBU-FM, HMUARTLGW, HMLAN, HM-SEC-KEY, HM-SEC-RHS, HM-SEC-SC-2, HM-SEC-SCo, HM-SEC-SD-2, HM-OU-CFM-TW, div. HUEs, Wifilight, Ring Video Pro

ch.eick

Okay,
Ich bin da auch nur Anwender und hatte mich im Original tv.pl auch schon gewundert warum es am Ende mit system und zwischendurch ohne system aufgerufen wurde. Ich werde es später mal testen.

Gruß
     Christian 
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

ch.eick

Hallo zusammen,

ich hab's nun getestet.

defmod at_TV_next at +*00:15:00  "perl /opt/fhem/tv/tv.pl dmy_TV parse_next"


Budy hat recht, ohne "{system(....&)}"  läuft es auch.

Vielen Dank
      Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

mumpitzstuff

#998
Ich habe im Wiki die Anpassung für den einen Telnet Aufruf übernommen. Das andere muss ich mir noch ansehen, ich hätte das gern abwärtskompatibel.

Warum war diese Änderung notwendig?

$readingValue = substr(FmtDateTime($start), 11, 8 zu 5 geändert);

ch.eick

Hallo,

das war nur um die Urzeit ein wenig kürzer darzustellen. Bei TV-Sendungen benötigt man in der Regel keine Sekunden.

Gruß
    Christian
RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

BillyPbg

Hallo 'mumpitzstuff',
hallo Kommune,

hab da einen kleinen REGEX-Schmerz...

Bei "$channelFilter  = qr/^(?:ARD)" wirft mir das Skript auch die Sendungen vom 'ARD-alpha' mit'rein.
Hat vielleicht jemand eine Lösung für/mit REGEX?

Viele Grüße
BillyPbg

mumpitzstuff

Versuch mal hinten ein $ ran zu hängen.

my $channelFilter = qr/^(?:ARD|ZDF|Sat1|RTL|RTL2|Pro7|DMax|Vox|Kabel)$/;

BillyPbg

Dann kommt gar nichts mehr...

mumpitzstuff

Poste mal die gesamte Zeile von dir, die vorher noch funktioniert hat.

Wolfgang Hochweller

@ch.eick:
Das mit dem Abholen ist mir ja klar; deswegen will ich eigentlich sowas wie TV-Movie , etc. vermeiden.
Ich habe lokal eine DVBViewer/Server Installation laufen ( will ja schliesslich auch im Ausland meine Sender haben ),
dort ist ja alles schon lokal vorhanden.
Aber ich muss mich noch durch das API arbeiten, um gezielt die Informationen zu holen , die ich gerade brauche.
Im allgemeinen ist das das Info zu der Sendung , die jetzt laeuft; auf dem einen Sender,, der gerade eingestellt ist.
Alles andere, wie Info fuer eine bestimmte Zeit, kann ich solange ueber die Standard-EPG-Seite des DVBServers machen.