diff --git a/contrib/DS_Starter/49_SSCam.pm b/contrib/DS_Starter/49_SSCam.pm
index b749b67f7..b40662667 100644
--- a/contrib/DS_Starter/49_SSCam.pm
+++ b/contrib/DS_Starter/49_SSCam.pm
@@ -159,6 +159,7 @@ BEGIN {
# Versions History intern
my %vNotesIntern = (
+ "9.5.0" => "15.07.2020 streamDev master type added, comref revised ",
"9.4.5" => "15.07.2020 fix crash while autocreate CommandDelete, CommandSave is missing ",
"9.4.4" => "14.07.2020 fix crash while autocreate makeDeviceName is missing ",
"9.4.3" => "13.07.2020 streamDev refactored, comref revised ",
@@ -762,8 +763,8 @@ sub Define {
$hash->{HELPER}{APIREC} = "SYNO.SurveillanceStation.Recording"; # This API provides method to query recording information.
# Startwerte setzen
- if(IsModelCam($hash)) {
- $attr{$name}{webCmd} = "on:off:snap:enable:disable:runView:stopView"; # initiale Webkommandos setzen
+ if(IsModelCam($hash)) { # initiale Webkommandos setzen
+ $attr{$name}{webCmd} = "on:off:snap:enable:disable:runView:stopView";
} else {
$attr{$name}{webCmd} = "homeMode";
$attr{$name}{webCmdLabel} = "HomeMode";
@@ -1148,7 +1149,7 @@ sub Set {
"off:noArg ".
"motdetsc:disable,camera,SVS ".
"snap ".
- (AttrVal($name, "snapGalleryBoost",0) ? (AttrVal($name,"snapGalleryNumber",undef) || AttrVal($name,"snapGalleryBoost",0))?"snapGallery:noArg ":"snapGallery:$defSnum ":" ").
+ (AttrVal($name, "snapGalleryBoost",0) ? (AttrVal($name,"snapGalleryNumber",undef) || AttrVal($name,"snapGalleryBoost",0)) ? "snapGallery:noArg " : "snapGallery:$defSnum " : " ").
"createReadingsGroup ".
"createSnapGallery:noArg ".
"createStreamDev:generic,hls,lastsnap,mjpeg,switched ".
@@ -1175,10 +1176,11 @@ sub Set {
$setlist = "Unknown argument $opt, choose one of ".
"autocreateCams:noArg ".
"credentials ".
+ "createStreamDev:master ".
"smtpcredentials ".
"createReadingsGroup ".
"extevent:1,2,3,4,5,6,7,8,9,10 ".
- ($hash->{HELPER}{APIHMMAXVER}?"homeMode:on,off ": "").
+ ($hash->{HELPER}{APIHMMAXVER} ? "homeMode:on,off " : "").
"snapCams ";
}
@@ -1472,7 +1474,7 @@ sub Set {
$attr{$ptzcdev}{group} = $name."_PTZcontrol";
return qq{PTZ control device "$ptzcdev" created and assigned to room "$room".};
- } elsif ($opt eq "createStreamDev" && IsModelCam($hash)) {
+ } elsif ($opt eq "createStreamDev") {
if (!$hash->{CREDENTIALS}) {return qq{Credentials of $name are not set - make sure you've set it with "set $name credentials username password"};}
my ($livedev,$ret);
@@ -1507,9 +1509,14 @@ sub Set {
$ret = CommandDefine($hash->{CL},"$livedev SSCamSTRM {FHEM::SSCam::streamDev('$name','$livedev','switched')}");
return $ret if($ret);
}
+ if($prop =~ /master/x) {
+ $livedev = "SSCamSTRM.$name.master";
+ $ret = CommandDefine($hash->{CL},"$livedev SSCamSTRM {FHEM::SSCam::streamDev('$name','$livedev','master')}");
+ return $ret if($ret);
+ }
my $room = AttrVal($name,"room","SSCam");
- $attr{$livedev}{room} = $room;
+ $attr{$livedev}{room} = $room;
return "Livestream device \"$livedev\" created and assigned to room \"$room\".";
} elsif ($opt eq "createReadingsGroup") {
@@ -7867,10 +7874,9 @@ sub ptzPanel {
### add Preset / Patrols
###############################
if(!$ftui) {
- my ($Presets,$Patrols,$zoom);
+ my ($Presets,$Patrols);
my $cmdPreset = "goPreset";
my $cmdPatrol = "runPatrol";
- my $cmdZoom = "setZoom";
## Presets
for my $fn (sort keys %{$data{webCmdFn}}) {
@@ -8067,7 +8073,8 @@ sub streamDev { ## no critic 'comp
# Javascript Bibliothek für Tooltips (http://www.walterzorn.de/tooltip/tooltip.htm#download) und Texte
my $calias = $hash->{CAMNAME}; # Alias der Kamera
my $ttjs = "/fhem/pgm2/sscam_tooltip.js";
- my ($ttrefresh, $ttrecstart, $ttrecstop, $ttsnap, $ttcmdstop, $tthlsreact, $ttmjpegrun, $tthlsrun, $ttlrrun, $tth264run, $ttlmjpegrun, $ttlsnaprun);
+ my ($ttrefresh, $ttrecstart, $ttrecstop, $ttsnap, $ttcmdstop, $tthlsreact);
+ my ($ttmjpegrun, $tthlsrun, $ttlrrun, $tth264run, $ttlmjpegrun, $ttlsnaprun);
# Hinweis Popups
if(AttrVal("global","language","EN") =~ /EN/x) {
@@ -8187,11 +8194,13 @@ sub streamDev { ## no critic 'comp
}
$ret .= '
';
$ret .= '';
-
- if(!$StmKey || ReadingsVal($camname, "Availability", "") ne "enabled" || IsDisabled($camname)) {
+
+ my $ismm = FHEM::SSCamSTRM::IsModelMaster($streamHash); # prüfen ob Streaming Dev ist MODEL = master
+
+ if(!$ismm && (!$StmKey || ReadingsVal($camname, "Availability", "") ne "enabled" || IsDisabled($camname))) {
# Ausgabe bei Fehler
my $cam = AttrVal($camname, "alias", $camname); # Linktext als Aliasname oder Devicename setzen
- $cause = !$StmKey?"Camera $cam has no Reading \"StmKey\" set !":"Cam \"$cam\" is disabled";
+ $cause = !$StmKey ? "Camera $cam has no Reading \"StmKey\" set !" : "Cam \"$cam\" is disabled";
$cause = "Camera \"$cam\" is disabled" if(IsDisabled($camname));
$ret .= " $cause
| ";
$ret .= '
';
@@ -8207,6 +8216,7 @@ sub streamDev { ## no critic 'comp
$ret .= &{$sdfn{$fmt}{fn}} (\%params);
} else {
$cause = qq{Streaming of format "$fmt" is not supported};
+ $cause = qq{Select a Streaming client with the "adoptFrom" command.} if($ismm);
$ret .= " $cause
| ";
}
use strict "refs";
@@ -9040,7 +9050,7 @@ sub composeGallery {
if($strmdev) {
my $streamHash = $defs{$strmdev}; # Hash des SSCamSTRM-Devices
- $uuid = $streamHash->{FUUID}; # eindeutige UUID des Streamingdevices
+ $uuid = $streamHash->{FUUID}; # eindeutige UUID des Streamingdevices
delete $streamHash->{HELPER}{STREAM};
$alias = AttrVal($strmdev, "alias", $strmdev); # Linktext als Aliasname oder Devicename setzen
if(AttrVal($strmdev, "noLink", 0)) {
@@ -9050,8 +9060,8 @@ sub composeGallery {
}
}
- my $cmddosnap = "FW_cmd('$FW_ME$FW_subdir?XHR=1&cmd=set $name snap 1 2 STRM:$uuid')"; # Snapshot auslösen mit Kennzeichnung "by STRM-Device"
- my $imgdosnap = "
";
+ my $cmddosnap = "FW_cmd('$FW_ME$FW_subdir?XHR=1&cmd=set $name snap 1 2 STRM:$uuid')"; # Snapshot auslösen mit Kennzeichnung "by STRM-Device"
+ my $imgdosnap = "
";
# bei Aufruf durch FTUI Kommandosyntax anpassen
if($ftui) {
@@ -9111,8 +9121,8 @@ sub composeGallery {
my $gattr = (AttrVal($name,"snapGallerySize","Icon") eq "Full")?$ha:"";
# Ausgabetabelle erstellen
- my ($htmlCode);
- $htmlCode = "";
+ my $htmlCode;
+ # $htmlCode = "";
$htmlCode .= "";
$htmlCode .= " $header
";
$htmlCode .= '
';
@@ -9132,16 +9142,17 @@ sub composeGallery {
$cell++;
if ( $cell == $sgc+1 ) {
- $htmlCode .= sprintf("$data{SSCam}{$name}{SNAPHASH}{$key}{createdTm} | " );
- $htmlCode .= "";
- $htmlCode .= "";
- $cell = 1;
+ $htmlCode .= sprintf("$data{SSCam}{$name}{SNAPHASH}{$key}{createdTm} | " );
+ $htmlCode .= "
";
+ $htmlCode .= "";
+ $cell = 1;
} else {
- $htmlCode .= sprintf("$data{SSCam}{$name}{SNAPHASH}{$key}{createdTm} | " );
+ $htmlCode .= sprintf("$data{SSCam}{$name}{SNAPHASH}{$key}{createdTm} | " );
}
$idata = "";
}
+
} else {
my @as;
for(cache($name, "c_getkeys")) { # relevant keys aus allen vorkommenden selektieren
@@ -9151,6 +9162,7 @@ sub composeGallery {
}
my %seen;
my @unique = sort{$a<=>$b} grep { !$seen{$_}++ } @as; # distinct / unique the keys
+
for my $key (@unique) {
$imgdat = cache($name, "c_read", "{SNAPHASH}{$key}{imageData}");
$imgTm = cache($name, "c_read", "{SNAPHASH}{$key}{createdTm}");
@@ -9160,12 +9172,12 @@ sub composeGallery {
$cell++;
if ( $cell == $sgc+1 ) {
- $htmlCode .= sprintf("$imgTm | " );
- $htmlCode .= "
";
- $htmlCode .= "";
- $cell = 1;
+ $htmlCode .= sprintf("$imgTm | " );
+ $htmlCode .= "
";
+ $htmlCode .= "";
+ $cell = 1;
} else {
- $htmlCode .= sprintf("$imgTm | " );
+ $htmlCode .= sprintf("$imgTm | " );
}
$idata = "";
@@ -9177,13 +9189,19 @@ sub composeGallery {
}
$htmlCode .= "
";
+
+ if(!$hb) {
+ $htmlCode .= "";
+ $htmlCode .= "";
+ $htmlCode .= "$imgdosnap " if($strmdev);
+ $htmlCode .= " | ";
+ $htmlCode .= "
";
+ }
+
$htmlCode .= "";
$htmlCode .= "
";
$htmlCode .= "
";
- if(!$hb) {
- $htmlCode .= "$imgdosnap " if($strmdev);
- }
- $htmlCode .= "";
+ # $htmlCode .= "";
undef $imgdat;
undef $imgTm;
@@ -9346,7 +9364,7 @@ sub prepareSendData {
}
}
$asref = $svshash->{HELPER}{ALLSNAPREF}; # Hashreferenz zum summarischen Snaphash
- for my $key (keys%{$asref}) { # prüfen ob Bildhash komplett ?
+ for my $key (keys%{$asref}) { # prüfen ob Bildhash komplett ?
if(!$asref->{$key}) {
return; # Bildhash noch nicht komplett
}
@@ -9357,10 +9375,10 @@ sub prepareSendData {
$name = $svshash->{NAME}; # Name des auslösenden SVS-Devices wird eingesetzt
Log3($name, 4, "$name - Central Snaphash fillup completed by all selected cams. Send it now ...");
- my $cache = cache($name, "c_init"); # Cache initialisieren (im SVS Device)
+ my $cache = cache($name, "c_init"); # Cache initialisieren (im SVS Device)
if(!$cache || $cache eq "internal" ) {
delete $data{SSCam}{RS};
- for my $key (keys%{$asref}) { # Referenz zum summarischen Hash einsetzen
+ for my $key (keys%{$asref}) { # Referenz zum summarischen Hash einsetzen
$data{SSCam}{RS}{$key} = delete $asref->{$key};
}
$dat = $data{SSCam}{RS}; # Referenz zum summarischen Hash einsetzen
@@ -9425,16 +9443,16 @@ sub prepareSendData {
$smtpmsg{$bodyk} = "$bodyt";
$ret = sendEmail($hash, {'subject' => $smtpmsg{subject},
- 'part1txt' => $smtpmsg{body},
- 'part2type' => 'image/jpeg',
- 'smtpport' => $sp,
- 'sdat' => $dat,
- 'opmode' => $OpMode,
- 'smtpnousessl' => $nousessl,
- 'sslfrominit' => $sslfrominit,
- 'smtpsslport' => $smtpsslport,
- 'tac' => $tac,
- }
+ 'part1txt' => $smtpmsg{body},
+ 'part2type' => 'image/jpeg',
+ 'smtpport' => $sp,
+ 'sdat' => $dat,
+ 'opmode' => $OpMode,
+ 'smtpnousessl' => $nousessl,
+ 'sslfrominit' => $sslfrominit,
+ 'smtpsslport' => $smtpsslport,
+ 'tac' => $tac,
+ }
);
readingsSingleUpdate($hash, "sendEmailState", $ret, 1) if ($ret);
}
@@ -9465,16 +9483,16 @@ sub prepareSendData {
$smtpmsg{$bodyk} = "$bodyt";
$ret = sendEmail($hash, {'subject' => $smtpmsg{subject},
- 'part1txt' => $smtpmsg{body},
- 'part2type' => 'video/mpeg',
- 'smtpport' => $sp,
- 'vdat' => $dat,
- 'opmode' => $OpMode,
- 'smtpnousessl' => $nousessl,
- 'sslfrominit' => $sslfrominit,
- 'smtpsslport' => $smtpsslport,
- 'tac' => $tac,
- }
+ 'part1txt' => $smtpmsg{body},
+ 'part2type' => 'video/mpeg',
+ 'smtpport' => $sp,
+ 'vdat' => $dat,
+ 'opmode' => $OpMode,
+ 'smtpnousessl' => $nousessl,
+ 'sslfrominit' => $sslfrominit,
+ 'smtpsslport' => $smtpsslport,
+ 'tac' => $tac,
+ }
);
readingsSingleUpdate($hash, "sendEmailState", $ret, 1) if ($ret);
}
@@ -9490,7 +9508,7 @@ sub prepareSendData {
$mt =~ s/['"]//gx;
my ($tbotk,$tbott,$peerk,$peert,$subjk,$subjt);
- my ($telebot,$peers,$subj) = split(",", $mt, 3 );
+ my ($telebot,$peers,$subj) = split(",", $mt, 3 );
($tbotk,$tbott) = split("=>", $telebot) if($telebot);
($peerk,$peert) = split("=>", $peers ) if($peers);
($subjk,$subjt) = split("=>", $subj ) if($subj);
@@ -9513,14 +9531,14 @@ sub prepareSendData {
$telemsg{$subjk} = "$subjt" if($subjt);
$ret = sendTelegram($hash, {'subject' => $telemsg{subject},
- 'part2type' => 'image/jpeg',
- 'sdat' => $dat,
- 'opmode' => $OpMode,
- 'tac' => $tac,
- 'telebot' => $telemsg{$tbotk},
- 'peers' => $telemsg{$peerk},
- 'MediaStream' => '-1', # Code für MediaStream im TelegramBot (png/jpg = -1)
- }
+ 'part2type' => 'image/jpeg',
+ 'sdat' => $dat,
+ 'opmode' => $OpMode,
+ 'tac' => $tac,
+ 'telebot' => $telemsg{$tbotk},
+ 'peers' => $telemsg{$peerk},
+ 'MediaStream' => '-1', # Code für MediaStream im TelegramBot (png/jpg = -1)
+ }
);
readingsSingleUpdate($hash, "sendTeleState", $ret, 1) if ($ret);
}
@@ -9559,14 +9577,14 @@ sub prepareSendData {
$telemsg{$subjk} = "$subjt" if($subjt);
$vdat = $dat;
- $ret = sendTelegram($hash, {'subject' => $telemsg{subject},
- 'vdat' => $vdat,
- 'opmode' => $OpMode,
- 'telebot' => $telemsg{$tbotk},
- 'peers' => $telemsg{$peerk},
- 'tac' => $tac,
- 'MediaStream' => '-30', # Code für MediaStream im TelegramBot (png/jpg = -1)
- }
+ $ret = sendTelegram($hash, {'subject' => $telemsg{subject},
+ 'vdat' => $vdat,
+ 'opmode' => $OpMode,
+ 'telebot' => $telemsg{$tbotk},
+ 'peers' => $telemsg{$peerk},
+ 'tac' => $tac,
+ 'MediaStream' => '-30', # Code für MediaStream im TelegramBot (png/jpg = -1)
+ }
);
readingsSingleUpdate($hash, "sendTeleState", $ret, 1) if ($ret);
}
@@ -9605,12 +9623,12 @@ sub prepareSendData {
$chatmsg{$subjk} = "$subjt" if($subjt);
$ret = sendChat($hash, {'subject' => $chatmsg{subject},
- 'opmode' => $OpMode,
- 'tac' => $tac,
- 'sdat' => $dat,
- 'chatbot' => $chatmsg{$cbotk},
- 'peers' => $chatmsg{$peerk},
- }
+ 'opmode' => $OpMode,
+ 'tac' => $tac,
+ 'sdat' => $dat,
+ 'chatbot' => $chatmsg{$cbotk},
+ 'peers' => $chatmsg{$peerk},
+ }
);
readingsSingleUpdate($hash, "sendChatState", $ret, 1) if ($ret);
}
@@ -9648,13 +9666,13 @@ sub prepareSendData {
$chatmsg{$peerk} = "$peert" if($peert);
$chatmsg{$subjk} = "$subjt" if($subjt);
- $ret = sendChat($hash, {'subject' => $chatmsg{subject},
- 'opmode' => $OpMode,
- 'tac' => $tac,
- 'vdat' => $dat,
- 'chatbot' => $chatmsg{$cbotk},
- 'peers' => $chatmsg{$peerk},
- }
+ $ret = sendChat($hash, {'subject' => $chatmsg{subject},
+ 'opmode' => $OpMode,
+ 'tac' => $tac,
+ 'vdat' => $dat,
+ 'chatbot' => $chatmsg{$cbotk},
+ 'peers' => $chatmsg{$peerk},
+ }
);
readingsSingleUpdate($hash, "sendChatState", $ret, 1) if ($ret);
}
@@ -9679,14 +9697,14 @@ sub sendChat {
Log3($name, 4, "$name - ####################################################");
my %chatparams = (
- 'subject' => { 'default'=>'', 'required'=>1, 'set'=>1},
- 'opmode' => { 'default'=>'', 'required'=>1, 'set'=>1}, # OpMode muss gesetzt sein
- 'tac' => { 'default'=>'', 'required'=>0, 'set'=>1}, # übermittelter Transaktionscode der ausgewerteten Transaktion
- 'sdat' => { 'default'=>'', 'required'=>0, 'set'=>1}, # Hashref der Bilddaten (Bilddaten base64 codiert)
- 'vdat' => { 'default'=>'', 'required'=>0, 'set'=>1}, # Hashref der Videodaten
- 'chatbot' => { 'default'=>'', 'required'=>1, 'set'=>1}, # SSChatBot-Device welches zum Senden verwendet werden soll
- 'peers' => { 'default'=>'', 'required'=>0, 'set'=>1}, # SSChatBot Peers
- 'videofolderMap' => {'attr'=>'videofolderMap', 'default'=>'', 'required'=>1, 'set'=>1}, # Wert des Attributs videofolderMap (muss gesetzt sein !)
+ 'subject' => { 'default'=>'', 'required'=>1, 'set'=>1},
+ 'opmode' => { 'default'=>'', 'required'=>1, 'set'=>1}, # OpMode muss gesetzt sein
+ 'tac' => { 'default'=>'', 'required'=>0, 'set'=>1}, # übermittelter Transaktionscode der ausgewerteten Transaktion
+ 'sdat' => { 'default'=>'', 'required'=>0, 'set'=>1}, # Hashref der Bilddaten (Bilddaten base64 codiert)
+ 'vdat' => { 'default'=>'', 'required'=>0, 'set'=>1}, # Hashref der Videodaten
+ 'chatbot' => { 'default'=>'', 'required'=>1, 'set'=>1}, # SSChatBot-Device welches zum Senden verwendet werden soll
+ 'peers' => { 'default'=>'', 'required'=>0, 'set'=>1}, # SSChatBot Peers
+ 'videofolderMap' => {'attr'=>'videofolderMap', 'default'=>'', 'required'=>1, 'set'=>1}, # Wert des Attributs videofolderMap (muss gesetzt sein !)
);
my $tac = $extparamref->{tac};
@@ -9944,7 +9962,7 @@ sub sendTelegram {
'telebot' => { 'default'=>'', 'required'=>1, 'set'=>1}, # TelegramBot-Device welches zum Senden verwendet werden soll
'peers' => { 'default'=>'', 'required'=>0, 'set'=>1}, # TelegramBot Peers
'MediaStream' => { 'default'=>'', 'required'=>0, 'set'=>1}, # Code für MediaStream im TelegramBot (png/jpg = -1)
- );
+ );
my $tac = $extparamref->{tac};
@@ -10516,7 +10534,7 @@ sub sendEmail {
'sslfrominit' => { 'default'=>'', 'required'=>0, 'set'=>1}, # SSL soll sofort ! aufgebaut werden
'tac' => { 'default'=>'', 'required'=>0, 'set'=>1}, # übermittelter Transaktionscode der ausgewerteten Transaktion
'vdat' => { 'default'=>'', 'required'=>0, 'set'=>1}, # Videodaten, wenn gesetzt muss 'part2type' auf 'video/mpeg' gesetzt sein
- );
+ );
my $tac = $extparamref->{tac};
@@ -11670,7 +11688,10 @@ return;
- - createStreamDev [generic | hls | lastsnap | mjpeg | switched] (valid for CAM)
+ - createStreamDev [generic | hls | lastsnap | mjpeg | switched] (valid for CAM)
+ respectively
+ createStreamDev [master] (valid for SVS)
+
A separate Streaming-Device (type SSCamSTRM) will be created. This device can be used as a discrete device in a dashboard
for example.
@@ -11680,7 +11701,7 @@ return;
- generic | - the streaming device playback a content determined by attribute "genericStrmHtmlTag" |
+ generic | - the streaming device playback a content determined by attribute genericStrmHtmlTag |
hls | - the streaming device playback a permanent HLS video stream |
lastsnap | - the streaming device playback the newest snapshot |
mjpeg | - the streaming device playback a permanent MJPEG video stream (Streamkey method) |
@@ -11689,8 +11710,9 @@ return;
- You can control the design with HTML tags in attribute "htmlattr" of the camera device or by
+ You can control the design with HTML tags in attribute htmlattr of the camera device or by
specific attributes of the SSCamSTRM-device itself.
+
Streaming device "hls"
@@ -13591,7 +13613,10 @@ attr <name> genericStrmHtmlTag <img $HTMLATTR
- - createStreamDev [generic | hls | lastsnap | mjpeg | switched] (gilt für CAM)
+ - createStreamDev [generic | hls | lastsnap | mjpeg | switched] (gilt für CAM)
+ bzw.
+ createStreamDev [master] (gilt für SVS)
+
Es wird ein separates Streaming-Device (Typ SSCamSTRM) erstellt. Dieses Device kann z.B. als separates Device
in einem Dashboard genutzt werden.
@@ -13601,17 +13626,18 @@ attr <name> genericStrmHtmlTag <img $HTMLATTR
- generic | - das Streaming-Device gibt einen durch das Attribut "genericStrmHtmlTag" bestimmten Content wieder |
+ generic | - das Streaming-Device gibt einen durch das Attribut genericStrmHtmlTag bestimmten Content wieder |
hls | - das Streaming-Device gibt einen permanenten HLS Datenstrom wieder |
lastsnap | - das Streaming-Device zeigt den neuesten Schnappschuß an |
mjpeg | - das Streaming-Device gibt einen permanenten MJPEG Kamerastream wieder (Streamkey Methode) |
switched | - Wiedergabe unterschiedlicher Streamtypen. Drucktasten zur Steuerung werden angeboten. |
-
+
- Die Gestaltung kann durch HTML-Tags im Attribut "htmlattr" im Kameradevice oder mit den
+ Die Gestaltung kann durch HTML-Tags im Attribut htmlattr im Kameradevice oder mit den
spezifischen Attributen im Streaming-Device beeinflusst werden.
+
Streaming Device "hls"
diff --git a/contrib/DS_Starter/49_SSCamSTRM.pm b/contrib/DS_Starter/49_SSCamSTRM.pm
index b3f9eb12f..b9b4cd569 100644
--- a/contrib/DS_Starter/49_SSCamSTRM.pm
+++ b/contrib/DS_Starter/49_SSCamSTRM.pm
@@ -1,5 +1,5 @@
########################################################################################################################
-# $Id: 49_SSCamSTRM.pm 22267 2020-06-25 21:07:13Z DS_Starter $
+# $Id: 49_SSCamSTRM.pm 22329 2020-07-02 17:16:52Z DS_Starter $
#########################################################################################################################
# 49_SSCamSTRM.pm
#
@@ -42,6 +42,7 @@ BEGIN {
qw(
AnalyzePerlCommand
AttrVal
+ data
defs
devspec2array
FmtDateTime
@@ -61,7 +62,9 @@ BEGIN {
sortTopicNum
FW_cmd
FW_directNotify
- FW_wname
+ FW_wname
+ FW_pH
+ FW_widgetFallbackFn
FHEM::SSCam::ptzPanel
FHEM::SSCam::streamDev
FHEM::SSCam::composeGallery
@@ -84,9 +87,9 @@ BEGIN {
}
-
# Versions History intern
my %vNotesIntern = (
+ "2.13.0" => "14.07.2020 integrate streamDev master ",
"2.12.0" => "28.06.2020 upgrade SSCam functions due to SSCam switch to packages ",
"2.11.0" => "24.06.2020 switch to packages, changes according to PBP ",
"2.10.2" => "08.11.2019 undef \$link in FwFn / streamAsHtml to save memory ",
@@ -132,6 +135,8 @@ my %SSCAM_imc = ( # di
1 => { 0 => "off", 1 => "inactive" },
);
+my %sdevs = (); # Hash der vorhandenen Streaming Devices
+
my $todef = 5; # Default Popup Zeit für set <> popupStream
################################################################
@@ -253,9 +258,19 @@ sub Set {
return if(IsDisabled($name) || $hash->{MODEL} =~ /ptzcontrol|snapgallery/x);
- my $setlist = "Unknown argument $opt, choose one of ".
+ my $setlist;
+
+ if(!IsModelMaster($hash)) {
+ $setlist = "Unknown argument $opt, choose one of ".
"popupStream "
;
+ } else {
+ my $sd = streamDevs();
+ $setlist = "Unknown argument $opt, choose one of ".
+ "adoptFrom:$sd ".
+ "reset:noArg "
+ ;
+ }
if ($opt eq "popupStream") {
my $txt = FHEM::SSCam::getClHash($hash);
@@ -269,10 +284,8 @@ sub Set {
unless ($to =~ /^\d+$/x || lc($to) eq "ok") { $to = $todef; }
$to = ($to =~ /\d+/x) ? (1000 * $to) : $to;
- my $pd = AttrVal($name, "popupStreamFW", "TYPE=FHEMWEB");
- my $parent = $hash->{PARENT};
- my $parentHash = $defs{$parent};
- my $htmlCode = $hash->{HELPER}{STREAM};
+ my $pd = AttrVal($name, "popupStreamFW", "TYPE=FHEMWEB");
+ my $htmlCode = $hash->{HELPER}{STREAM};
if ($hash->{HELPER}{STREAMACTIVE}) {
my $out = "";
@@ -289,6 +302,42 @@ sub Set {
}
}
+ } elsif ($opt eq "adoptFrom") {
+ shift @a; shift @a;
+ $prop = join "#", @a;
+ my $strmd = $sdevs{"$prop"};
+ my $valid = ($strmd && $defs{$strmd} && $defs{$strmd}{TYPE} eq "SSCamSTRM");
+
+ return qq{The command "$opt" needs a valid SSCamSTRM device as argument} if(!$valid);
+
+ # Übernahme der Readings
+ my @r;
+ delReadings($hash);
+ for my $key (keys %{$defs{$strmd}{READINGS}}) {
+ my $val = ReadingsVal($strmd, $key, "");
+ next if(!$val);
+ push @r, "$key:$val";
+ }
+
+ # Übernahme LINK
+ $hash->{LINK} = $defs{$strmd}{LINK};
+ readingsSingleUpdate($hash,"clientLink", $hash->{LINK}, 0);
+
+ if(@r) {
+ readingsBeginUpdate($hash);
+
+ for my $elem (@r) {
+ my ($rn,$rval) = split ":", $elem, 2;
+ readingsBulkUpdate($hash, $rn, $rval);
+ }
+
+ readingsEndUpdate($hash, 1);
+ }
+
+ } elsif ($opt eq "reset") {
+ delReadings($hash);
+ $hash->{LINK} = $hash->{DEF};
+
} else {
return "$setlist";
}
@@ -354,26 +403,40 @@ return;
#############################################################################################
sub FwFn {
my ($FW_wname, $name, $room, $pageHash) = @_; # pageHash is set for summaryFn.
- my $hash = $defs{$name};
- my $link = $hash->{LINK};
+ my $hash = $defs{$name};
RemoveInternalTimer($hash);
+
$hash->{HELPER}{FW} = $FW_wname;
+ my $clink = ReadingsVal($name, "clientLink", "");
+ $hash->{LINK} = $clink if($clink);
+
+ my $link = $hash->{LINK};
$link = AnalyzePerlCommand(undef, $link) if($link =~ m/^{(.*)}$/xs);
my $ret = "";
+
+ if(IsModelMaster($hash) && $clink) {
+ my $alias = AttrVal($name, "alias", $name); # Linktext als Aliasname oder Devicename setzen
+ my $dlink = "$alias is Streaming master of device ";
+ $dlink = "$alias is Streaming master of device " if(AttrVal($name, "noLink", 0)); # keine Links im Stream-Dev generieren
+ $ret .= "$dlink " if(!AttrVal($name,"hideDisplayName",0));
+ }
+
if(IsDisabled($name)) {
if(AttrVal($name,"hideDisplayName",0)) {
$ret .= "Stream-device $name is disabled";
} else {
$ret .= "Stream-device is disabled";
- }
+ }
+
} else {
- $ret .= $link;
+ $ret .= $link;
+ $ret .= sDevsWidget($name) if(IsModelMaster($hash));
}
-
- my $al = AttrVal($name, "autoRefresh", 0); # Autorefresh nur des aufrufenden FHEMWEB-Devices
+
+ my $al = AttrVal($name, "autoRefresh", 0); # Autorefresh nur des aufrufenden FHEMWEB-Devices
if($al) {
InternalTimer(gettimeofday()+$al, "FHEM::SSCamSTRM::webRefresh", $hash, 0);
Log3($name, 5, "$name - next start of autoRefresh: ".FmtDateTime(gettimeofday()+$al));
@@ -392,12 +455,23 @@ sub explodeDEF {
my $link = shift;
my $arg = (split("[()]",$link))[1];
- $arg =~ s/'//xg;
+ $arg =~ s/'//xg;
($hash->{PARENT},undef,$hash->{MODEL}) = split(",",$arg);
return;
}
+#############################################################################################
+# Ist das MODEL "master" ?
+#############################################################################################
+sub IsModelMaster {
+ my $hash = shift;
+
+ my $mm = $hash->{MODEL} eq "master" ? 1 : 0;
+
+return $mm;
+}
+
#############################################################################################
# Seitenrefresh
# festgelegt durch SSCamSTRM-Attribut "autoRefresh" und "autoRefreshFW"
@@ -436,12 +510,12 @@ sub setVersionInfo {
if($modules{$type}{META}{x_prereqs_src} && !$hash->{HELPER}{MODMETAABSENT}) {
# META-Daten sind vorhanden
$modules{$type}{META}{version} = "v".$v; # Version aus META.json überschreiben, Anzeige mit {Dumper $modules{SSCamSTRM}{META}}
- if($modules{$type}{META}{x_version}) { # {x_version} ( nur gesetzt wenn $Id: 49_SSCamSTRM.pm 22267 2020-06-25 21:07:13Z DS_Starter $ im Kopf komplett! vorhanden )
+ if($modules{$type}{META}{x_version}) { # {x_version} ( nur gesetzt wenn $Id: 49_SSCamSTRM.pm 22329 2020-07-02 17:16:52Z DS_Starter $ im Kopf komplett! vorhanden )
$modules{$type}{META}{x_version} =~ s/1\.1\.1/$v/gx;
} else {
$modules{$type}{META}{x_version} = $v;
}
- return $@ unless (FHEM::Meta::SetInternals($hash)); # FVERSION wird gesetzt ( nur gesetzt wenn $Id: 49_SSCamSTRM.pm 22267 2020-06-25 21:07:13Z DS_Starter $ im Kopf komplett! vorhanden )
+ return $@ unless (FHEM::Meta::SetInternals($hash)); # FVERSION wird gesetzt ( nur gesetzt wenn $Id: 49_SSCamSTRM.pm 22329 2020-07-02 17:16:52Z DS_Starter $ im Kopf komplett! vorhanden )
if(__PACKAGE__ eq "FHEM::$type" || __PACKAGE__ eq $type) {
# es wird mit Packages gearbeitet -> Perl übliche Modulversion setzen
# mit {->VERSION()} im FHEMWEB kann Modulversion abgefragt werden
@@ -479,7 +553,7 @@ sub streamAsHtml {
}
} else {
- $ret .= $link;
+ $ret .= $link;
}
$ret .= "";
@@ -488,6 +562,98 @@ sub streamAsHtml {
return $ret;
}
+################################################################
+# delete Readings
+# $rd = angegebenes Reading löschen
+################################################################
+sub delReadings {
+ my $hash = shift;
+ my $rd = shift;
+ my $name = $hash->{NAME};
+
+ my $bl = "state|parentState"; # Blacklist
+
+ if($rd) { # angegebenes Reading löschen wenn nicht im providerLevel enthalten
+ delete($hash->{READINGS}{$rd}) if($rd !~ /$bl/x);
+ return;
+ }
+
+ for my $key (keys %{$hash->{READINGS}}) {
+ delete($hash->{READINGS}{$key}) if($key !~ /$bl/x);
+ }
+
+return;
+}
+
+################################################################
+# liefert String aller Streamingdevices außer MODEL = master
+# und füllt Hash %sdevs{Alias} = Devicename zu Auflösung
+#
+# (es wird Alias (wenn gesetzt) oder Devicename verwendet,
+# Leerzeichen werden durch "#" ersetzt)
+################################################################
+sub streamDevs {
+
+ my $sd = "";
+ undef %sdevs;
+
+ my @strmdevs = devspec2array("TYPE=SSCamSTRM:FILTER=MODEL!=master"); # Liste Streaming devices außer MODEL = master
+ for my $d (@strmdevs) {
+ next if(!$defs{$d});
+ my $alias = AttrVal($d, "alias", $d);
+ $alias =~ s/\s+/#/gx;
+ $sdevs{$alias} = "$d";
+ }
+
+ for my $a (sort keys %sdevs) {
+ $sd .= "," if($sd);
+ $sd .= $a;
+ }
+
+return $sd;
+}
+
+################################################################
+# Streaming Devices Drop-Down Widget zur Auswahl
+# in einem Master Streaming Device
+################################################################
+sub sDevsWidget {
+ my $name = shift;
+
+ my $Adopts;
+ my $ret = "";
+ my $cmdAdopt = "adoptFrom";
+ my $valAdopts = streamDevs();
+
+ for my $fn (sort keys %{$data{webCmdFn}}) {
+ next if($data{webCmdFn}{$fn} ne "FW_widgetFallbackFn");
+ no strict "refs"; ## no critic 'NoStrict'
+ $Adopts = &{$data{webCmdFn}{$fn}}($FW_wname,$name,"",$cmdAdopt,$valAdopts);
+ use strict "refs";
+ last if(defined($Adopts));
+ }
+
+ if($Adopts) {
+ $Adopts =~ s,^]*>(.*) | $,$1,;
+ } else {
+ $Adopts = FW_pH "cmd.$name=set $name $cmdAdopt", $cmdAdopt, 0, "", 1, 1;
+ }
+
+ ## Tabellenerstellung
+ $ret .= "";
+ $ret .= '';
+
+ if($valAdopts) {
+ $ret .= "";
+ $ret .= "Adopt: | $Adopts | ";
+ $ret .= "
";
+ }
+
+ $ret .= "
";
+
+return $ret;
+}
+
1;
=pod