From 81fcc570b3baeb92e7d3d4f787fe8d617ffebc2e Mon Sep 17 00:00:00 2001
From: hapege <>
Date: Sun, 11 Dec 2022 13:10:59 +0000
Subject: [PATCH] 70_SVDRP.pm: added Plugin support, NextTimer name
git-svn-id: https://svn.fhem.de/fhem/trunk@26838 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
fhem/FHEM/70_SVDRP.pm | 221 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 206 insertions(+), 15 deletions(-)
diff --git a/fhem/FHEM/70_SVDRP.pm b/fhem/FHEM/70_SVDRP.pm
index a1213fa0e..a265dcffb 100755
--- a/fhem/FHEM/70_SVDRP.pm
+++ b/fhem/FHEM/70_SVDRP.pm
@@ -11,6 +11,10 @@
# 1.01.02 bugfix for single-digit NextTimer
# 1.01.03 corrections for german Umlaute
# 1.01.04 fix statusCheckIntervall
+# 1.01.05 added capability to control plugins (PLUG)
+# added name to next timer
+# expicit set for SatIP plugin
+# handle HELP responses
#
########################################################################################
#
@@ -42,7 +46,7 @@ use Blocking;
use Time::HiRes qw(gettimeofday);
use POSIX;
-my $version = "1.01.04";
+my $version = "1.01.05";
my %SVDRP_gets = (
#
@@ -78,7 +82,11 @@ my %SVDRP_defaultsets = (
"connect" => ":noArg",
"PowerOff" => ":noArg",
"ListRecording" => "",
- "GetAll" => ":noArg"
+ "GetAll" => ":noArg",
+ "Plugin" => "",
+ "StreamdevServer" => ":LSTC,DISC",
+ "SatIP" => ":INFO,MODE,LIST,SCAN,STAT,CONT,OPER,ATTA,DETA,TRAC",
+ "Help" => ":noArg"
);
my %SVDRP_defaultsets_unused = (
@@ -94,7 +102,11 @@ my %SVDRP_cmdmap = (
"Channel" => "CHAN",
"DeleteTimer" => "DELT",
"Volume" => "VOLU",
- "ListRecording" => "LSTR"
+ "ListRecording" => "LSTR",
+ "Plugin" => "PLUG",
+ "StreamdevServer" => "PLUG streamdev-server",
+ "SatIP" => "PLUG satip",
+ "Help" => "HELP"
);
my @SVDRP_statusCmds = ("LSTT", "NEXT", "CHAN", "VOLU", "STAT");
@@ -107,6 +119,10 @@ my %SVDRP_data = (
#
);
+my %SVDRP_timers = (
+ #
+);
+
my %SVDRP_result;
my %SVDRPaddattrs;
@@ -364,6 +380,8 @@ sub SVDRP_cleanUp {
#DevIo_CloseDev($hash);
#$hash->{STATE} = "closed";
#$hash->{PARTIAL}="";
+ # reset .sendingcmd to indicate that cmd sending cycle is done
+ readingsSingleUpdate($hash, ".sendingcmd", "0", 1);
return ;
}
@@ -518,8 +536,10 @@ sub SVDRP_parseMessage {
my $parsedmsg = "";
my $code;
my $recording = "";
+ my $plugin = "";
+ my $text="";
- readingsBeginUpdate($hash);
+ #readingsBeginUpdate($hash);
### now we should analyse which message was received, and put it to the right reading
#if ($msg =~ /^22[0|1]/){
@@ -554,9 +574,10 @@ sub SVDRP_parseMessage {
elsif ($msg =~ /^250[ ]\d+[ ][A-Za-z]{3}[ ][A-Za-z]{3}[ ]{1,2}[0-9]{1,2}[ ][0-9]{2}:[0-9]{2}:[0-9]{2}[ ][0-9]{4}\s$/){
# next timer format: 250 1 Tue Mar 15 09:50:00 2022
$reading = "NextTimer";
- (my $code, $msg) = split (/ /, $msg, 2);
- $rv = readingsSingleUpdate($hash, $reading, $msg, 1);
- #Log3 $name, 5, "[$name] Parse: updated $reading with $msg";
+ $msg = SVDRP_parseNextTimer($hash, $reading, $msg);
+ # seems that only with newline the sprintf formatting is kept - but I don't like it here ;-)
+ #$msg = $timers."\n".$msg;
+ readingsSingleUpdate($hash, $reading, $msg, 1);
}
elsif ($msg =~ /^250[ ]\d+[ ][A-Za-z0-9\h\.\-_?!#]+\s$/){
# Channel format: 250 4 RTL Television
@@ -575,7 +596,7 @@ sub SVDRP_parseMessage {
}
elsif ($msg =~ /^250[ ]Key[ ][A-Za-z0-9"]+[ ]accepted\s$/){
# HitKey format: 250 Key "up" accepted
- $reading = "HitKey";
+ $reading = "HitKeyInfo";
(my $code, $msg) = split (/ /, $msg, 2);
$rv = readingsSingleUpdate($hash, $reading, $msg, 1);
#Log3 $name, 5, "[$name] Parse: updated $reading with $msg"
@@ -639,6 +660,81 @@ sub SVDRP_parseMessage {
#$rv = readingsSingleUpdate($hash, $reading, $msg, 1);
#Log3 $name, 5, "[$name] Parse: updated $reading with $msg"
}
+
+ elsif ($msg =~ /^214/){
+ # Helpinfo format: 214-xxxx
+ $reading = "HelpInfo";
+ # empty HelpInfo reading, if we got a new one
+ my $sendingcmd = ReadingsVal($name,".sendingcmd","0");
+ if ($sendingcmd eq "1") {
+ readingsBeginUpdate($hash);
+ readingsBulkUpdate($hash, ".sendingcmd", "0", 1);
+ readingsBulkUpdate($hash, $reading, "", 1);
+ readingsEndUpdate($hash, 1);
+ }
+ # check if we got "214-n"
+ if (substr($msg, 3, 1) eq "-"){
+ ($code, $msg) = split (/-/, $msg, 2);
+ #Log3 $name, 5, "[$name] Parse: HelpInfo: substring contains '-'";
+ }
+ else{
+ ($code, $msg) = split (/ /, $msg, 2);
+ }
+ $text = ReadingsVal($name, $reading, "");
+ $msg = SVDRP_parseHelpinfo($name, $msg);
+ if ($msg ne "none"){
+ $msg = $text."\n".$msg;
+ $rv = readingsSingleUpdate($hash, $reading, $msg, 1);
+ Log3 $name, 5, "[$name] Parse: HelpInfo: updated $reading with '$msg'";
+ }
+ #$rv = readingsSingleUpdate($hash, $reading, $msg, 1);
+ #Log3 $name, 5, "[$name] Parse: HelpInfo: updated $reading with $msg"
+ }
+
+ elsif ($msg =~ /^9[0-9][0-9]/){
+ # PLUG resonse is like
+ # 900-SAT>IP device: 0
+ # 900-CardIndex: 0
+ # 900-Stream: rtsp://10.1.1.9/?src=1&freq=11185&pol=v&ro=0.35&msys=dvbs2&mtype=8psk&sr=22000&fec=23 (Unicast) [stream=1]
+ # 900-Signal: lock=1 strength=67 quality=100 frontend=1
+ # 900-Stream bitrate: 75 kB/s
+ # 900-Buffer bitrate: 0 kB/s
+ # 900-Buffer usage: 0/2048 kB (0,0%)
+ # 900-Channel: Das Erste HD;ARD:11493:HC23M5O35P0S1:S19.2E:22000:5101=27:5102=deu@3,5103=mis@3,5107=qks@3;5106=deu@106:5104;5105=deu:0:10301:1:1019:0
+ # 900-Active pids:
+ # 900-Active section filters:
+ # 900-Filter 0: 7 ( 9 kB/s) Pid=0x12 (EIT)
+ # 900-Filter 1: 0 ( 0 kB/s) Pid=0x14 (TDT)
+ # 900-Filter 2: 2 ( 0 kB/s) Pid=0x00 (PAT)
+ # 900-Filter 3: 0 ( 0 kB/s) Pid=0x11 (SDT)
+ # 900-Filter 4: 0 ( 0 kB/s) Pid=0x10 (NIT)
+ # 900 Filter 5: 0 ( 0 kB/s) Pid=0x60 (---)
+ $reading = "PluginInfo";
+
+ # check if we got "900-n"
+ if (substr($msg, 3, 1) eq "-"){
+ ($code, $msg) = split (/-/, $msg, 2);
+ #Log3 $name, 5, "[$name] Parse: substring contains '-'";
+ }
+ else{
+ ($code, $msg) = split (/ /, $msg, 2);
+ }
+
+ $plugin = ReadingsVal($name, $reading, "");
+ $msg = SVDRP_parsePlugin($name, $msg);
+
+ if ($msg ne "none"){
+ $msg = $plugin."\n".$msg;
+ $rv = readingsSingleUpdate($hash, $reading, $msg, 1);
+ Log3 $name, 5, "[$name] Parse: updated $reading with '$msg'";
+ }
+
+ #Log3 $name, 5, "[$name] Parse: parsePlugin returned $msg";
+ #$msg = $plugin."\n".$msg;
+ #$rv = readingsSingleUpdate($hash, $reading, $msg, 1);
+ #Log3 $name, 5, "[$name] Parse: updated $reading with $parsedmsg"
+ }
+
#Log3 $name, 5, "[$name] Parse: updated $reading with '$msg'";
}
@@ -679,6 +775,7 @@ sub SVDRP_parseDiskStatus{
sub SVDRP_parseTimer{
my ($name, $msg) = @_;
+ my $hash = $defs{$name};
#$count = 0;
#$output = "";
my $parsedmsg = "none";
@@ -704,13 +801,49 @@ sub SVDRP_parseTimer{
($i1, $i2, $day, $start, $end, $i3, $i4, $timername) = split (":", $timerstr, 8);
substr ($start, 2, 0) = ":";
substr ($end, 2, 0) = ":";
- #$output .= "\n" if ($count > 0); # add LF only if first line is contained
+
+ # store timer ID and Name in hidden setting, to re-use with NextTimer command
+ $timername =~ s/[:\r\n]//g;
+ $SVDRP_timers{$timerid} = $timername;
+ readingsSingleUpdate( $hash, ".Timers", encode_json( \%SVDRP_timers ), 1 );
+
$parsedmsg = "ID: ".sprintf("%2s",$timerid)." | Day: ".sprintf("%-10s",$day)." | Start: ".$start." | Stop: ".$end." | Name: ".$timername;
+
}
#Log3 $name, 5, "[$name] parseTimer: parsed output is $parsedmsg";
return $parsedmsg;
}
+sub SVDRP_parseNextTimer {
+ my ($hash, $reading, $msg) = @_;
+ #my $hash = $defs{$name};
+ my $name = $hash->{NAME};
+ my $timername = "";
+ (my $code, $msg) = split (/ /, $msg, 2);
+ # replace double blank by single blank
+ $msg =~ s/ / /g;
+ Log3 $name, 5, "[$name] Parse: NextTimer: $msg";
+ (my $tid, my $tday, my $tmonth, my $tdate, my $tstart, my $tyear) = split (/ /,$msg);
+ Log3 $name, 5, "[$name] Parse: NextTimer: $tid - $tday - $tmonth - $tdate - $tstart - $tyear";
+ # get timer name from hidden reading (requires ListTimer to be run)
+ my %myVDRtimers = SVDRP_restoreJson($hash, ".Timers");
+ if (exists($myVDRtimers{$tid})){
+ $timername = $myVDRtimers{$tid};
+ Log3 $name, 5, "[$name] Parse: NextTimer: ID: $tid, name: $timername";
+
+ }
+ my $parsedmsg = "ID: ".sprintf("%2s",$tid)." | Day: ".sprintf("%3s",$tday).sprintf("%3s",$tdate).".".sprintf("%3s",$tmonth)." ".sprintf("%4i",$tyear)." | Start: ".$tstart." | Name: ".$timername;
+ Log3 $name, 5, "[$name] Parse: NextTimer: $parsedmsg";
+
+ #readingsSingleUpdate($hash, $reading, $parsedmsg, 1);
+ #Log3 $name, 5, "[$name] Parse: updated $reading with $msg";
+ return $parsedmsg;
+}
+
+sub SVDRP_getTimerNames {
+ my ($name, $msg) = @_;
+
+}
sub SVDRP_parseRecording {
my ($name, $msg) = @_;
my $type = "none";
@@ -753,6 +886,19 @@ sub SVDRP_parseRecording {
return $msg;
}
+sub SVDRP_parseHelpinfo {
+ my ($name, $msg) = @_;
+ Log3 $name, 5, "[$name] parseHelpinfo: parsed output is $msg";
+ return $msg;
+}
+
+
+sub SVDRP_parsePlugin {
+ my ($name, $msg) = @_;
+ Log3 $name, 5, "[$name] parsePlugin: parsed output is $msg";
+ return $msg;
+}
+
sub SVDRP_Set {
my ($hash, @param) = @_;
@@ -760,7 +906,7 @@ sub SVDRP_Set {
my $name = shift @param;
my $opt = shift @param;
- my $value = join("", @param);
+ my $value = join(" ", @param);
#my $value = shift @param;
my $msg;
my $msg2;
@@ -770,6 +916,7 @@ sub SVDRP_Set {
my $writecmd;
$hash = $defs{$name};
+ $hash->{version} = $version;
# construct set list
my @cList = (keys %SVDRP_sets);
@@ -788,6 +935,9 @@ sub SVDRP_Set {
# empty reading error
readingsSingleUpdate($hash, "globalError", "", 1);
readingsSingleUpdate($hash, "infoError", "", 1);
+ # set .sendingcmd to indicate that cmd sending cycle is started
+ # needed e.g. to empty HelpInfo as soon as new info is received
+ readingsSingleUpdate($hash, ".sendingcmd", "1", 1);
if ($opt eq "cleanUp"){
main::Log3 $name, 5, "[$name]: Set: $name cleanUp";
@@ -823,6 +973,8 @@ sub SVDRP_Set {
if ($opt eq "LSTT"){
# delete ListTimers, will be re-filled completely
readingsSingleUpdate($hash, "ListTimers", "", 1);
+ #$SVDRP_timers{$timerid} = $timername;
+ %SVDRP_timers = ();
main::Log3 $name, 5, "[$name]: Set: deleted ListTimers, value is now ".ReadingsVal($name,"ListTimers","none");
}
@@ -841,6 +993,11 @@ sub SVDRP_Set {
main::Log3 $name, 5, "[$name]: Set: deleted Recordings, value is now ".ReadingsVal($name,"Recordings","none");
}
+ if ($opt =~ /^PLUG/){
+ readingsSingleUpdate($hash, "PluginInfo", "", 1);
+ main::Log3 $name, 5, "[$name]: Set: $name PluginInfo";
+ }
+
# get or no value will sent send $msg to the given command $opt
if ($value eq "get" || !$value){
$msg = "$opt\r\n";
@@ -868,6 +1025,11 @@ sub SVDRP_Set {
$writecmd = $name."|".$cmds."|".$optorg;
InternalTimer( $next, "SVDRP_multiWrite", $writecmd);
}
+ elsif($msg =~ /NEXT/) {
+ my $cmds = "LSTT NEXT";
+ $writecmd = $name."|".$cmds."|".$optorg;
+ InternalTimer( $next, "SVDRP_multiWrite", $writecmd);
+ }
else{
$writecmd = $name."|".$msg."|".$optorg;
InternalTimer( $next, "SVDRP_singleWrite", $writecmd);
@@ -905,6 +1067,7 @@ sub SVDRP_multiWrite {
if ($_ eq "LSTT"){
# delete ListTimers, will be re-filled completely
readingsSingleUpdate($hash, "ListTimers", "", 1);
+ %SVDRP_timers = ();
}
if ($_ eq "STAT"){
$send = $_." disk\r\n"
@@ -1003,6 +1166,16 @@ sub SVDRP_checkStatus ($){
}
}
+sub SVDRP_restoreJson {
+ my ($hash, $reading) = @_;
+ my $name = $hash->{NAME};
+ my $jsets = ReadingsVal($name, $reading, "{none:none}");
+ my $decode = decode_json($jsets);
+ # just for logging
+ #my %decode = %$decode;
+ #main::Log3 $name, 5, "[$name]: restore: ". keys(%decode);
+ return %$decode;
+}
###################################################
# end #
###################################################
@@ -1069,6 +1242,9 @@ sub SVDRP_checkStatus ($){
(i.e. ListTimers, NextTimer, Channel, Volume, DiskStatus)
+