diff --git a/fhem/CHANGED b/fhem/CHANGED index 7e056401b8..e2341c37da 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,8 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - feature: 49_SSCam: V8.0.0, new type "hls" of streaming devices, hls + playback now available for all common browsers, + tooltip hints in streaming devices, minor fixes - feature: 30_HUEBridge, 31_HUEDevice: added get startup command - change: 55_DWD_OpenData: maintenance release (forum #83097 msg #869647) - change: mqtt2.template: change name convention + cleanup diff --git a/fhem/FHEM/49_SSCam.pm b/fhem/FHEM/49_SSCam.pm index 0e566e1f87..6982b97d2b 100644 --- a/fhem/FHEM/49_SSCam.pm +++ b/fhem/FHEM/49_SSCam.pm @@ -45,6 +45,7 @@ use HttpUtils; # Versions History intern our %SSCam_vNotesIntern = ( + "8.0.0" => "13.12.2018 HLS with sscam_hls.js integrated for SSCamSTRM type hls, realize tooltipps in streaming devices, minor fixes", "7.7.1" => "12.12.2018 change autocreateCams: define new device only if ne device with Internal CAMNAME is defined, ". "fix getsnapinfo function get wrong snapid or none if cam is new defined ", "7.7.0" => "10.12.2018 SVS-Device: autocreateCams command added, some other fixes and improvements, minor code rewrite, ". @@ -101,6 +102,8 @@ our %SSCam_vNotesIntern = ( # Versions History extern our %SSCam_vNotesExtern = ( + "8.0.0" => "18.12.2018 HLS is integrated using sscam_hls.js in Streaming device types \"hls\". HLS streaming is now available ". + "for all common used browser types. Tooltipps are added to streaming devices and snapgallery.", "7.7.0" => "10.12.2018 autocreateCams command added to SVS device. By this command all cameras installed in SVS can be ". "defined automatically.
". "In SSCamSTRM devices the \"set <name> popupStream\" command is implemented which may open a popup window with the ". @@ -277,9 +280,40 @@ my %SSCam_errlist = ( 600 => "Presetname and PresetID not found in Hash", ); +# Tooltipps Textbausteine (http://www.walterzorn.de/tooltip/tooltip.htm#download), §NAME§ wird durch Kameranamen ersetzt +our %SSCam_ttips_en = ( + ttrefresh => "The playback of streaming content of camera of "§NAME§" will be restartet.", + ttrecstart => "Start an endless recording of camera "§NAME§".
You have to stop the recording manually.", + ttrecstop => "Stopp the recording of camera "§NAME§".", + ttsnap => "Take a snapshot of camera "§NAME§".", + ttcmdstop => "Stopp playback of camera "§NAME§"", + tthlsreact => "Reactivate HTTP Livestreaming Interface of camera "§NAME§".
The camera is enforced to restart HLS transmission.", + ttmjpegrun => "Playback the MJPEG Livestream of camera "§NAME§".", + tthlsrun => "Playback the native HTTP Livestream of camera "§NAME§".", + ttlrrun => "Playback of last recording of camera "§NAME§" in an iFrame.
Both MJPEG and H.264 recordings are rendered.", + tth264run => "Playback of last H.264 recording of camera "§NAME§".
It only starts if the recording is type H.264", + ttlmjpegrun => "Playback of last MJPEG recording of camera "§NAME§".
It only starts if the recording is type MJPEG", + ttlsnaprun => "Playback of last snapshot of camera "§NAME§".", +); + +our %SSCam_ttips_de = ( + ttrefresh => "Die Wiedergabe des Streams von Kamera "§NAME§" wird neu gestartet.", + ttrecstart => "Startet eine Endlosaufnahme von Kamera "§NAME§".
Die Aufnahme muß manuell gestoppt werden.", + ttrecstop => "Stoppt die laufende Aufnahme von Kamera "§NAME§".", + ttsnap => "Ein Schnappschuß von Kamera "§NAME§" wird aufgenommen.", + ttcmdstop => "Stopp Wiedergabe von Kamera "§NAME§"", + tthlsreact => "Reactiviert das HTTP Livestreaming Interface von camera "§NAME§".
Die Kamera wird aufgefordert die HLS Übertragung zu restarten.", + ttmjpegrun => "Wiedergabe des MJPEG Livestreams von Kamera "§NAME§"", + tthlsrun => "Wiedergabe des HTTP Livestreams von Kamera "§NAME§".
Es wird die HLS Funktion der Synology Surveillance Station verwendet.", + ttlrrun => "Wiedergabe der letzten Aufnahme von Kamera "§NAME§" in einem iFrame.
Es werden sowohl MJPEG als auch H.264 Aufnahmen wiedergegeben.", + tth264run => "Wiedergabe der letzten H.264 Aufnahme von Kamera "§NAME§".
Die Wiedergabe startet nur wenn die Aufnahme vom Typ H.264 ist.", + ttlmjpegrun => "Wiedergabe der letzten MJPEG Aufnahme von Kamera "§NAME§".
Die Wiedergabe startet nur wenn die Aufnahme vom Typ MJPEG ist.", + ttlsnaprun => "Wiedergabe des letzten Schnappschusses von Kamera "§NAME§".", +); + # Standardvariablen my $SSCam_slim = 3; # default Anzahl der abzurufenden Schnappschüsse mit snapGallery -my $SSCAM_snum = "1,2,3,4,5,6,7,8,9,10"; # mögliche Anzahl der abzurufenden Schnappschüsse mit snapGallery +my $SSCAM_snum = "1,2,3,4,5,6,7,8,9,10"; # mögliche Anzahl der abzurufenden Schnappschüsse mit snapGallery use vars qw($FW_ME); # webname (default is fhem), used by 97_GROUP/weblink use vars qw($FW_subdir); # Sub-path in URL, used by FLOORPLAN/weblink @@ -288,6 +322,7 @@ use vars qw($FW_detail); # currently selected device for detail view use vars qw($FW_wname); # Web instance sub FW_pH(@); # add href +################################################################ sub SSCam_Initialize($) { my ($hash) = @_; $hash->{DefFn} = "SSCam_Define"; @@ -304,6 +339,8 @@ sub SSCam_Initialize($) { $hash->{AttrList} = "disable:1,0 ". "genericStrmHtmlTag ". + "hlsNetScript:1,0 ". + "hlsStrmObject ". "httptimeout ". "htmlattr ". "livestreamprefix ". @@ -454,6 +491,10 @@ sub SSCam_Attr($$$$) { # $name is device name # aName and aVal are Attribute name and value + if ($aName =~ /hlsNetScript/ && SSCam_IsModelCam($hash)) { + return " The attribute \"$aName\" is only valid for devices of type \"SVS\"! Please set this attribute in a device of this type."; + } + # dynamisch PTZ-Attribute setzen (wichtig beim Start wenn Reading "DeviceType" nicht gesetzt ist) if ($cmd eq "set" && ($aName =~ m/ptzPanel_.*/)) { foreach my $n (0..9) { @@ -639,7 +680,7 @@ sub SSCam_Set($@) { "snap:noArg ". (AttrVal($name, "snapGalleryBoost",0)?(AttrVal($name,"snapGalleryNumber",undef) || AttrVal($name,"snapGalleryBoost",0))?"snapGallery:noArg ":"snapGallery:$SSCAM_snum ":" "). "createSnapGallery:noArg ". - "createStreamDev:generic,mjpeg,switched ". + "createStreamDev:generic,hls,mjpeg,switched ". ((ReadingsVal("$name", "CapPTZPan", "false") ne "false") ? "createPTZcontrol:noArg ": ""). "enable:noArg ". "disable:noArg ". @@ -754,7 +795,7 @@ sub SSCam_Set($@) { $sgdev = "SSCamSTRM.$name.snapgallery"; $ret = CommandDefine($hash->{CL},"$sgdev SSCamSTRM {SSCam_composegallery('$name','$sgdev','snapgallery')}"); return $ret if($ret); - my $room = "SnapGallery"; + my $room = "SSCam"; $attr{$sgdev}{room} = $room; return "Snapgallery device \"$sgdev\" created and assigned to room \"$room\"."; @@ -763,7 +804,7 @@ sub SSCam_Set($@) { my $ptzcdev = "SSCamSTRM.$name.PTZcontrol"; my $ret = CommandDefine($hash->{CL},"$ptzcdev SSCamSTRM {SSCam_ptzpanel('$name','$ptzcdev','ptzcontrol')}"); return $ret if($ret); - my $room = AttrVal($name,"room","PTZcontrol"); + my $room = AttrVal($name,"room","SSCam"); $attr{$ptzcdev}{room} = $room; $attr{$ptzcdev}{group} = $name."_PTZcontrol"; return "PTZ control device \"$ptzcdev\" created and assigned to room \"$room\"."; @@ -781,6 +822,13 @@ sub SSCam_Set($@) { $livedev = "SSCamSTRM.$name.generic"; $ret = CommandDefine($hash->{CL},"$livedev SSCamSTRM {SSCam_StreamDev('$name','$livedev','generic')}"); return $ret if($ret); + } + if($prop =~ /hls/) { + $livedev = "SSCamSTRM.$name.hls"; + $ret = CommandDefine($hash->{CL},"$livedev SSCamSTRM {SSCam_StreamDev('$name','$livedev','hls')}"); + return $ret if($ret); + my $c = "The device needs to set attribute \"hlsStrmObject\" in camera device \"$name\" to a valid HLS videostream"; + CommandAttr($hash->{CL},"$livedev comment $c"); } if($prop =~ /switched/) { $livedev = "SSCamSTRM.$name.switched"; @@ -788,7 +836,7 @@ sub SSCam_Set($@) { return $ret if($ret); } - my $room = AttrVal($name,"room","Livestream"); + my $room = AttrVal($name,"room","SSCam"); $attr{$livedev}{room} = $room; return "Livestream device \"$livedev\" created and assigned to room \"$room\"."; @@ -802,7 +850,7 @@ sub SSCam_Set($@) { '< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >'."\n". '< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >'."\n". '<%it_server>,On/Off>,< >,,< >, >,< >,< >,< >,< >, >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >'."\n". - 'TYPE=SSCam:FILTER=MODEL=SVS:HomeModeState,< >,state,< >,< >,< >,< >,< >,< >, >,< >,< >,< >,?!disable,< >,< >,< >,< >,< >'."\n". + 'TYPE=SSCam:FILTER=MODEL=SVS:!HomeModeState,< >,state,< >,< >,< >,< >,< >,< >, >,< >,< >,< >,?!disable,< >,< >,< >,< >,< >'."\n". ''; my $ret = CommandDefine($hash->{CL},"$rgdev readingsGroup $rgdef"); @@ -1423,7 +1471,7 @@ sub SSCam_FWsummaryFn ($$$$) { if($hash->{HELPER}{RUNVIEW} =~ /live_fw/) { if(ReadingsVal($d, "Record", "Stop") eq "Stop") { # Aufnahmebutton endlos Start - $ret .= "$imgrecendless "; + $ret .= "$imgrecendless "; } else { # Aufnahmebutton Stop $ret .= "$imgrecstop "; @@ -5775,7 +5823,7 @@ sub SSCam_Autocreate ($$) { } return ($err,$camname); -} +} ############################################################################### # Test ob JSON-String empfangen wurde @@ -6211,6 +6259,11 @@ return; # Funktion für SSCamSTRM-Devices - Kamera Liveview weblink device # API: SYNO.SurveillanceStation.VideoStreaming # Methode: GetLiveViewPath +# +# $camname = Name der Kamaera (Parent-Device) +# $strmdev = Name des Streaming-Devices +# $fmt = Streaming Format +# ###################################################################################### sub SSCam_StreamDev($$$) { my ($camname,$strmdev,$fmt) = @_; @@ -6273,7 +6326,40 @@ sub SSCam_StreamDev($$$) { $pws =~ s/"//g if($pws); my $StmKey = ReadingsVal($camname,"StmKey",undef); + # 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); + if(AttrVal("global","language","EN") =~ /EN/) { + $ttrefresh = $SSCam_ttips_en{"ttrefresh"}; $ttrefresh =~ s/§NAME§/$calias/g; + $ttrecstart = $SSCam_ttips_en{"ttrecstart"}; $ttrecstart =~ s/§NAME§/$calias/g; + $ttrecstop = $SSCam_ttips_en{"ttrecstop"}; $ttrecstop =~ s/§NAME§/$calias/g; + $ttsnap = $SSCam_ttips_en{"ttsnap"}; $ttsnap =~ s/§NAME§/$calias/g; + $ttcmdstop = $SSCam_ttips_en{"ttcmdstop"}; $ttcmdstop =~ s/§NAME§/$calias/g; + $tthlsreact = $SSCam_ttips_en{"tthlsreact"}; $tthlsreact =~ s/§NAME§/$calias/g; + $ttmjpegrun = $SSCam_ttips_en{"ttmjpegrun"}; $ttmjpegrun =~ s/§NAME§/$calias/g; + $tthlsrun = $SSCam_ttips_en{"tthlsrun"}; $tthlsrun =~ s/§NAME§/$calias/g; + $ttlrrun = $SSCam_ttips_en{"ttlrrun"}; $ttlrrun =~ s/§NAME§/$calias/g; + $tth264run = $SSCam_ttips_en{"tth264run"}; $tth264run =~ s/§NAME§/$calias/g; + $ttlmjpegrun= $SSCam_ttips_en{"ttlmjpegrun"}; $ttlmjpegrun =~ s/§NAME§/$calias/g; + $ttlsnaprun = $SSCam_ttips_en{"ttlsnaprun"}; $ttlsnaprun =~ s/§NAME§/$calias/g; + } else { + $ttrefresh = $SSCam_ttips_de{"ttrefresh"}; $ttrefresh =~ s/§NAME§/$calias/g; + $ttrecstart = $SSCam_ttips_de{"ttrecstart"}; $ttrecstart =~ s/§NAME§/$calias/g; + $ttrecstop = $SSCam_ttips_de{"ttrecstop"}; $ttrecstop =~ s/§NAME§/$calias/g; + $ttsnap = $SSCam_ttips_de{"ttsnap"}; $ttsnap =~ s/§NAME§/$calias/g; + $ttcmdstop = $SSCam_ttips_de{"ttcmdstop"}; $ttcmdstop =~ s/§NAME§/$calias/g; + $tthlsreact = $SSCam_ttips_de{"tthlsreact"}; $tthlsreact =~ s/§NAME§/$calias/g; + $ttmjpegrun = $SSCam_ttips_de{"ttmjpegrun"}; $ttmjpegrun =~ s/§NAME§/$calias/g; + $tthlsrun = $SSCam_ttips_de{"tthlsrun"}; $tthlsrun =~ s/§NAME§/$calias/g; + $ttlrrun = $SSCam_ttips_de{"ttlrrun"}; $ttlrrun =~ s/§NAME§/$calias/g; + $tth264run = $SSCam_ttips_de{"tth264run"}; $tth264run =~ s/§NAME§/$calias/g; + $ttlmjpegrun= $SSCam_ttips_de{"ttlmjpegrun"}; $ttlmjpegrun =~ s/§NAME§/$calias/g; + $ttlsnaprun = $SSCam_ttips_de{"ttlsnaprun"}; $ttlsnaprun =~ s/§NAME§/$calias/g; + } + $ret = ""; + $ret .= ""; $ret .= ''; $ret .= ''; $ret .= ''; @@ -6281,8 +6367,8 @@ sub SSCam_StreamDev($$$) { if(!$StmKey || ReadingsVal($camname, "Availability", "") ne "enabled" || IsDisabled($camname)) { # Ausgabe bei Fehler my $cam = AttrVal($camname, "alias", $camname); - $cause = !$StmKey?"Cam $cam has no Reading \"StmKey\" set !":"Cam \"$cam\" is disabled"; - $cause = "Cam \"$cam\" is disabled" if(IsDisabled($camname)); + $cause = !$StmKey?"Camera $cam has no Reading \"StmKey\" set !":"Cam \"$cam\" is disabled"; + $cause = "Camera \"$cam\" is disabled" if(IsDisabled($camname)); $ret .= ""; $ret .= ''; $ret .= ''; @@ -6291,7 +6377,7 @@ sub SSCam_StreamDev($$$) { return $ret; } - if($fmt =~ /mjpeg/) { + if ($fmt =~ /mjpeg/) { if($apivideostmsmaxver) { # keine API "SYNO.SurveillanceStation.VideoStream" mehr ab API v2.8 $link = "$proto://$serveraddr:$serverport/webapi/$apivideostmspath?api=$apivideostms&version=$apivideostmsmaxver&method=Stream&cameraId=$camid&format=mjpeg&_sid=$sid"; } elsif ($hash->{HELPER}{STMKEYMJPEGHTTP}) { @@ -6306,12 +6392,12 @@ sub SSCam_StreamDev($$$) { if(ReadingsVal($camname, "Record", "Stop") eq "Stop") { # Aufnahmebutton endlos Start - $ret .= "$imgrecendless "; + $ret .= "$imgrecendless "; } else { # Aufnahmebutton Stop - $ret .= "$imgrecstop "; + $ret .= "$imgrecstop "; } - $ret .= "$imgdosnap "; + $ret .= "$imgdosnap "; $ret .= ""; if(AttrVal($camname,"ptzPanel_use",1)) { my $ptz_ret = SSCam_ptzpanel($camname); @@ -6329,7 +6415,7 @@ sub SSCam_StreamDev($$$) { $ret .= "" if(AttrVal($camname,"ptzPanel_use",0)); } - } elsif($fmt =~ /generic/) { + } elsif ($fmt =~ /generic/) { my $htag = AttrVal($camname,"genericStrmHtmlTag",""); if( $htag =~ m/^\s*(.*)\s*$/s ) { $htag = $1; @@ -6349,23 +6435,23 @@ sub SSCam_StreamDev($$$) { $ret .= ""; if(AttrVal($camname,"ptzPanel_use",1)) { my $ptz_ret = SSCam_ptzpanel($camname); @@ -6374,26 +6460,72 @@ sub SSCam_StreamDev($$$) { } } - } elsif($fmt =~ /switched/) { + } elsif ($fmt =~ /hls/) { + # es ist ein .m3u8-File bzw. ein Link dorthin zu übergeben + my $cam = AttrVal($camname, "alias", $camname); + my $m3u8 = AttrVal($camname, "hlsStrmObject", ""); + + if( $m3u8 =~ m/^\s*(.*)\s*$/s ) { + $m3u8 = $1; + $m3u8 =~ s/\$NAME/$camname/g; + } + my $d = $camname; + $d =~ s/\./_/; # Namensableitung zur javascript Codeanpassung + + if(!$m3u8) { + $cause = "You have to specify attribute \"hlsStrmObject\" in Camera $cam !"; + $ret .= ""; + $ret .= ''; + $ret .= ''; + $ret .= '

$cause

"; $ret .= "$htag"; if($htag) { - $streamHash->{HELPER}{STREAM} = "$htag"; # Stream für "get popupStream" speichern + $streamHash->{HELPER}{STREAM} = "$htag"; # Stream für "set popupStream" speichern $streamHash->{HELPER}{STREAM} =~ s/["']//g; $streamHash->{HELPER}{STREAM} =~ s/\s+/ /g; $streamHash->{HELPER}{STREAMACTIVE} = 1; # Statusbit wenn ein Stream aktiviert ist } $ret .= "
"; Log3($strmdev, 4, "$strmdev - generic Stream params:\n$htag"); - $ret .= "$imgrefresh "; + $ret .= "$imgrefresh "; $ret .= $imgblank; if(ReadingsVal($camname, "Record", "Stop") eq "Stop") { # Aufnahmebutton endlos Start - $ret .= "$imgrecendless "; + $ret .= "$imgrecendless "; } else { # Aufnahmebutton Stop - $ret .= "$imgrecstop "; + $ret .= "$imgrecstop "; } - $ret .= "$imgdosnap "; + $ret .= "$imgdosnap "; $ret .= "

$cause

'; + $ret .= ''; + return $ret; + } + + $ret .= "
"; + $ret .= SSCam_bindhlsjs ($camname, $strmdev, $m3u8, $d); + + $streamHash->{HELPER}{STREAM} = ""; # Stream für "set popupStream" speichern + $streamHash->{HELPER}{STREAMACTIVE} = 1; # Statusbit wenn ein Stream aktiviert ist + + $ret .= "$imgrefresh "; + $ret .= $imgblank; + if(ReadingsVal($camname, "Record", "Stop") eq "Stop") { + # Aufnahmebutton endlos Start + $ret .= "$imgrecendless "; + } else { + # Aufnahmebutton Stop + $ret .= "$imgrecstop "; + } + $ret .= "$imgdosnap "; + $ret .= ""; + if(AttrVal($camname,"ptzPanel_use",1)) { + my $ptz_ret = SSCam_ptzpanel($camname); + if($ptz_ret) { + $ret .= "$ptz_ret"; + } + } + + } elsif ($fmt =~ /switched/) { my $wltype = $hash->{HELPER}{WLTYPE}; $link = $hash->{HELPER}{LINK}; if($link && $wltype =~ /image|iframe|video|base64img|embed|hls/) { if($wltype =~ /image/) { $ret .= "')\">
" if($link); - $streamHash->{HELPER}{STREAM} = ""; # Stream für "get popupStream" speichern + $streamHash->{HELPER}{STREAM} = ""; # Stream für "set popupStream" speichern $streamHash->{HELPER}{STREAMACTIVE} = 1 if($link); # Statusbit wenn ein Stream aktiviert ist - $ret .= "$imgstop "; + $ret .= "$imgstop "; $ret .= $imgblank; if($hash->{HELPER}{RUNVIEW} =~ /live_fw/) { if(ReadingsVal($camname, "Record", "Stop") eq "Stop") { # Aufnahmebutton endlos Start - $ret .= "$imgrecendless "; + $ret .= "$imgrecendless "; } else { # Aufnahmebutton Stop - $ret .= "$imgrecstop "; + $ret .= "$imgrecstop "; } - $ret .= "$imgdosnap "; + $ret .= "$imgdosnap "; } $ret .= ""; if(AttrVal($camname,"ptzPanel_use",1) && $hash->{HELPER}{RUNVIEW} =~ /live_fw/) { @@ -6418,10 +6550,10 @@ sub SSCam_StreamDev($$$) {
" if($link); $streamHash->{HELPER}{STREAM} = ""; # Stream für "get popupStream" speichern - $streamHash->{HELPER}{STREAMACTIVE} = 1 if($link); # Statusbit wenn ein Stream aktiviert ist - $ret .= "$imgstop "; - $ret .= "$imgrefresh "; + ""; # Stream für "set popupStream" speichern + $streamHash->{HELPER}{STREAMACTIVE} = 1 if($link); # Statusbit wenn ein Stream aktiviert ist + $ret .= "$imgstop "; + $ret .= "$imgrefresh "; $ret .= ""; if($hash->{HELPER}{AUDIOLINK} && ReadingsVal($camname, "CamAudioType", "Unknown") !~ /Unknown/) { $ret .= ''; @@ -6445,9 +6577,9 @@ sub SSCam_StreamDev($$$) { "". "". "Your browser does not support the video tag". - ""; # Stream für "get popupStream" speichern + ""; # Stream für "set popupStream" speichern $streamHash->{HELPER}{STREAMACTIVE} = 1 if($link); # Statusbit wenn ein Stream aktiviert ist - $ret .= "$imgstop "; + $ret .= "$imgstop "; $ret .= ""; if($hash->{HELPER}{AUDIOLINK} && ReadingsVal($camname, "CamAudioType", "Unknown") !~ /Unknown/) { $ret .= ''; @@ -6460,14 +6592,14 @@ sub SSCam_StreamDev($$$) { } } elsif($wltype =~ /base64img/) { $ret .= "')\">
" if($link); - $streamHash->{HELPER}{STREAM} = ""; # Stream für "get popupStream" speichern + $streamHash->{HELPER}{STREAM} = ""; # Stream für "get popupStream" speichern $streamHash->{HELPER}{STREAMACTIVE} = 1 if($link); # Statusbit wenn ein Stream aktiviert ist - $ret .= "$imgstop "; + $ret .= "$imgstop "; $ret .= ""; } elsif($wltype =~ /embed/) { $ret .= "')\">" if($link); - $streamHash->{HELPER}{STREAM} = ""; # Stream für "get popupStream" speichern + $streamHash->{HELPER}{STREAM} = ""; # Stream für "set popupStream" speichern $streamHash->{HELPER}{STREAMACTIVE} = 1 if($link); # Statusbit wenn ein Stream aktiviert ist } elsif($wltype =~ /hls/) { @@ -6480,20 +6612,20 @@ sub SSCam_StreamDev($$$) { "". "". "Your browser does not support the video tag". - ""; # Stream für "get popupStream" speichern + ""; # Stream für "set popupStream" speichern $streamHash->{HELPER}{STREAMACTIVE} = 1 if($link); # Statusbit wenn ein Stream aktiviert ist - $ret .= "$imgstop "; - $ret .= "$imgrefresh "; - $ret .= "$imghlsreact "; + $ret .= "$imgstop "; + $ret .= "$imgrefresh "; + $ret .= "$imghlsreact "; $ret .= $imgblank; if(ReadingsVal($camname, "Record", "Stop") eq "Stop") { # Aufnahmebutton endlos Start - $ret .= "$imgrecendless "; + $ret .= "$imgrecendless "; } else { # Aufnahmebutton Stop - $ret .= "$imgrecstop "; + $ret .= "$imgrecstop "; } - $ret .= "$imgdosnap "; + $ret .= "$imgdosnap "; $ret .= ""; if(AttrVal($camname,"ptzPanel_use",1)) { my $ptz_ret = SSCam_ptzpanel($camname); @@ -6501,17 +6633,19 @@ sub SSCam_StreamDev($$$) { $ret .= "$ptz_ret"; } } + } + } else { my $cam = AttrVal($camname, "alias", $camname); $cause = "Playback cam \"$cam\" switched off"; $ret .= "
$cause

"; - $ret .= "$imgmjpegrun "; - $ret .= "$imghlsrun " if(SSCam_IsHLSCap($hash)); - $ret .= "$imglrirun "; - $ret .= "$imglh264run "; - $ret .= "$imglmjpegrun "; - $ret .= "$imglsnaprun "; + $ret .= "$imgmjpegrun "; + $ret .= "$imghlsrun " if(SSCam_IsHLSCap($hash)); + $ret .= "$imglrirun "; + $ret .= "$imglh264run "; + $ret .= "$imglmjpegrun "; + $ret .= "$imglsnaprun "; $ret .= ""; } } else { @@ -6527,6 +6661,52 @@ sub SSCam_StreamDev($$$) { return $ret; } +############################################################################################# +# hls.js laden für Streamimgdevice Typen HLS, RTSP +# $m3u8 - ein .m3u8-File oder ein entsprechender Link +# $d - ein Unique-Name zur Codeableitung (darf keinen . enthalten) +############################################################################################# +sub SSCam_bindhlsjs ($$$$) { + my ($camname, $strmdev, $m3u8, $d) = @_; + my $hlsjs = "sscam_hls.js"; # hls.js Release von Projekteite https://github.com/video-dev/hls.js/releases + my $ret; + + $ret .= " + + "; + + my $dcs = (devspec2array("TYPE=SSCam:FILTER=MODEL=SVS"))[0]; # ist ein SVS-Device angelegt ? + my $uns = AttrVal($dcs,"hlsNetScript",0) if($dcs); # ist in einem SVS Device die Nutzung hls.js auf Projektseite ausgewählt ? + + if($uns) { + my $lib = "https://cdn.jsdelivr.net/npm/hls.js\@latest"; + $ret .= ""; + Log3($strmdev, 4, "$strmdev - HLS Streaming use net library \"$lib\" "); + } else { + $ret .= ""; + Log3($strmdev, 4, "$strmdev - HLS Streaming use local file \"/fhem/pgm2/$hlsjs\" "); + } + + $ret .= ""; + +return $ret; +} + ############################################################################### # Schnappschußgalerie zusammenstellen # Verwendung durch SSCamSTRM-Devices @@ -6535,7 +6715,7 @@ sub SSCam_composegallery ($;$$) { my ($name,$strmdev,$model) = @_; my $hash = $defs{$name}; my $camname = $hash->{CAMNAME}; - my $allsnaps = $hash->{HELPER}{".SNAPHASH"}; # = \%allsnaps + my $allsnaps = $hash->{HELPER}{".SNAPHASH"}; # = \%allsnaps my $sgc = AttrVal($name,"snapGalleryColumns",3); # Anzahl der Images in einer Tabellenzeile my $lss = ReadingsVal($name, "LastSnapTime", " "); # Zeitpunkt neueste Aufnahme my $lang = AttrVal("global","language","EN"); # Systemsprache @@ -6559,7 +6739,7 @@ sub SSCam_composegallery ($;$$) { my $ha = AttrVal($name, "snapGalleryHtmlAttr", AttrVal($name, "htmlattr", 'width="500" height="325"')); my $pws = AttrVal($strmdev, "popupWindowSize", ""); # Größe eines Popups - $pws =~ s/"//g if($pws); + $pws =~ s/"//g if($pws); # falls "SSCam_composegallery" durch ein SSCamSTRM-Device aufgerufen wird my $devWlink = ""; @@ -6575,6 +6755,15 @@ sub SSCam_composegallery ($;$$) { $sgbnote = "ACHTUNG - Es können keine Schnappschüsse abgerufen werden. Bitte setzen sie das Attribut \"snapGalleryBoost=1\" im Device $name" if ($lang eq "DE"); } + # Javascript Bibliothek für Tooltips (http://www.walterzorn.de/tooltip/tooltip.htm#download) und Texte + my $ttjs = "/fhem/pgm2/sscam_tooltip.js"; + my ($ttsnap); + if(AttrVal("global","language","EN") =~ /EN/) { + $ttsnap = $SSCam_ttips_en{"ttsnap"}; $ttsnap =~ s/§NAME§/$camname/g; + } else { + $ttsnap = $SSCam_ttips_de{"ttsnap"}; $ttsnap =~ s/§NAME§/$camname/g; + } + my $header; if ($lang eq "EN") { $header = "Snapshots ($limit/$totalcnt) of camera $camname - newest Snapshot: $lss
"; @@ -6586,11 +6775,12 @@ sub SSCam_composegallery ($;$$) { $header .= $sgbnote; my $gattr = (AttrVal($name,"snapGallerySize","Icon") eq "Full")?$ha:" "; - my @as = sort{$a <=>$b}keys%{$allsnaps}; + my @as = sort{$a<=>$b}keys%{$allsnaps}; # Ausgabetabelle erstellen my ($htmlCode,$ct); $htmlCode = ""; + $htmlCode .= ""; $htmlCode .= sprintf("$devWlink
$header
"); $htmlCode .= ""; $htmlCode .= ""; @@ -6599,8 +6789,9 @@ sub SSCam_composegallery ($;$$) { foreach my $key (@as) { $ct = $allsnaps->{$key}{createdTm}; - my $html = sprintf("" ); - + my $idata = ""; + $idata = "onClick=\"FW_okDialog('{$key}{imageData} $pws>')\"" if(AttrVal($name,"snapGalleryBoost",0)); + my $html = sprintf("" ); $cell++; if ( $cell == $sgc+1 ) { @@ -6616,14 +6807,14 @@ sub SSCam_composegallery ($;$$) { if ( $cell == 2 ) { $htmlCode .= ""; } - + $htmlCode .= ""; $htmlCode .= ""; $htmlCode .= "
$ct
{$key}{imageData}\" $gattr onClick=\"FW_okDialog('{$key}{imageData} $pws>')\">
$ct
{$key}{imageData}\" $gattr $idata>
"; $htmlCode .= "
"; - $htmlCode .= "$imgdosnap " if($strmdev); + $htmlCode .= "$imgdosnap " if($strmdev); $htmlCode .= ""; - + return $htmlCode; } @@ -7001,8 +7192,8 @@ attr <name> genericStrmHtmlTag <video $HTMLATTR controls autoplay>
  • set <name> createPTZcontrol     (valid for PTZ-CAM)

  • - A separate PTZ-control panel will be created (type SSCamSTRM). The current room of the parent camera device is - assigned if it is set there. + A separate PTZ control panel will be created (type SSCamSTRM). The current room of the parent camera device is + assigned if it is set there (default "SSCam"). With the "ptzPanel_.*"-attributes or respectively the specific attributes of the SSCamSTRM-device the properties of the control panel can be affected.


    @@ -7022,7 +7213,7 @@ attr <name> genericStrmHtmlTag <video $HTMLATTR controls autoplay>
  • set <name> createSnapGallery     (valid for CAM)

  • A snapshot gallery will be created as a separate device (type SSCamSTRM). The device will be provided in - room "SnapGallery". + room "SSCam". With the "snapGallery..."-attributes respectively the specific attributes of the SSCamSTRM-device you are able to manipulate the properties of the new snapshot gallery device.

    @@ -8331,7 +8522,7 @@ attr <name> genericStrmHtmlTag <video $HTMLATTR controls autoplay>
      -
    • set <name> createStreamDev [generic | mjpeg | switched]     (gilt für CAM)

    • +
    • set <name> createStreamDev [generic | hls | mjpeg | switched]     (gilt für CAM)

    • Es wird ein separates Streaming-Device (Typ SSCamSTRM) erstellt. Dieses Device kann z.B. als separates Device in einem Dashboard genutzt werden. @@ -8342,6 +8533,7 @@ attr <name> genericStrmHtmlTag <video $HTMLATTR controls autoplay> +
      generic - das Streaming-Device gibt einen durch das Attribut "genericStrmHtmlTag" bestimmten Content wieder
      hls - das Streaming-Device gibt einen permanenten HLS Datenstrom wieder
      mjpeg - das Streaming-Device gibt einen permanenten MJPEG Kamerastream wieder (Streamkey Methode)
      switched - Wiedergabe unterschiedlicher Streamtypen. Drucktasten zur Steuerung werden angeboten.
      @@ -8349,12 +8541,29 @@ attr <name> genericStrmHtmlTag <video $HTMLATTR controls autoplay>

      Die Gestaltung kann durch HTML-Tags im Attribut "htmlattr" im Kameradevice oder mit den - spezifischen Attributen im Streaming-Device beeinflusst werden.
      - Soll ein HLS-Stream im Streaming-Device vom Typ "switched" gestartet werden, muss die Kamera in der Synology Surveillance Station - auf das Videoformat H.264 eingestellt und HLS von der eingesetzten SVS-Version unterstützt sein. - Diese Auswahltaste wird deshalb im nur im Streaming-Device angeboten wenn das Reading "CamStreamFormat = HLS" beinhaltet.
      - HLS (HTTP Live Streaming) kann momentan nur auf Mac Safari oder mobilen iOS/Android-Geräten wiedergegeben werden.
      - Im "switched"-Device werden Drucktasten zur Steuerung des zu startenden Medientyps angeboten.
      + spezifischen Attributen im Streaming-Device beeinflusst werden.

      + + Streaming Device "hls"

      + + Das Streaming-Device vom Typ "hls" verwendet die Bibliothek hls.js zur Bildverarbeitung und ist auf allen Browsern mit + MediaSource extensions (MSE) lauffähig. Mit dem Attribut "hlsNetScript" kann bestimmt werden, ob + die lokal installierte hls.js (./www/pgm2/hls.js) oder immer die aktuellste Bibliotheksversion von der hls.js Projektseite + verwendet werden soll. Dieses Attribut ist zentral in einem Device vom Typ "SVS" zu setzen !
      + Bei Verwendung dieses Streamingdevices ist zwingend das Attribut "hlsStrmObject" im SSCam Device + mit dem darzustellenden Stream anzugeben. +

      + + Streaming Device "switched hls"

      + + Dieser Typ nutzt den von der Synology Surveillance Station gelieferten HLS Videostream. + Soll ein HLS-Stream im Streaming-Device vom Typ "switched" gestartet werden, muss die Kamera in der Synology Surveillance + Station auf das Videoformat H.264 eingestellt und HLS von der eingesetzten SVS-Version unterstützt sein. + Diese Auswahltaste wird deshalb im nur dann im Streaming-Device angeboten, wenn das Reading "CamStreamFormat = HLS" beinhaltet.
      + HLS (HTTP Live Streaming) kann momentan nur auf Mac Safari oder mobilen iOS/Android-Geräten wiedergegeben werden. +

      + + Streaming Device "generic"

      + Ein Streaming-Device vom Typ "generic" benötigt die Angabe von HTML-Tags im Attribut "genericStrmHtmlTag". Diese Tags spezifizieren den wiederzugebenden Content.

      @@ -8374,7 +8583,7 @@ attr <name> genericStrmHtmlTag <video $HTMLATTR controls autoplay>
    • set <name> createPTZcontrol     (gilt für PTZ-CAM)

    • Es wird ein separates PTZ-Steuerungspaneel (Type SSCamSTRM) erstellt. Es wird der aktuelle Raum des Kameradevice - zugewiesen sofern dort gesetzt. + zugewiesen sofern dort gesetzt (default "SSCam"). Mit den "ptzPanel_.*"-Attributen bzw. den spezifischen Attributen des erzeugten SSCamSTRM-Devices können die Eigenschaften des PTZ-Paneels beeinflusst werden.


      @@ -8393,7 +8602,7 @@ attr <name> genericStrmHtmlTag <video $HTMLATTR controls autoplay>
    • set <name> createSnapGallery     (gilt für CAM)

    • Es wird eine Schnappschußgallerie als separates Device (Type SSCamSTRM) erzeugt. Das Device wird im Raum - "SnapGallery" erstellt. + "SSCam" erstellt. Mit den "snapGallery..."-Attributen bzw. den spezifischen Attributen des erzeugten SSCamSTRM-Devices können die Eigenschaften der Schnappschußgallerie beeinflusst werden.

      @@ -9177,6 +9386,36 @@ attr <name> genericStrmHtmlTag <video $HTMLATTR controls autoplay>
    • httptimeout
      Timeout-Wert für HTTP-Aufrufe zur Synology Surveillance Station, Default: 4 Sekunden (wenn httptimeout = "0" oder nicht gesetzt)

    • + + +
    • hlsNetScript     (setzbar in Device Typ "SVS")
      + Wenn gesetzt, wird die aktuellste hls.js Version von der Projektseite verwendet (Internetverbindung nötig). +
      + Im Standard wird die lokal installierte Version (./www/pgm2/sscam_hls.js) zur Wiedergabe von Daten in allen + Streaming Devices vom Typ "hls" genutzt (siehe set <name> createStreamDev hls"). + Dieses Attribut wird in einem Device vom Typ "SVS" gesetzt und gilt zentral für alle Streaming Devices ! +

    • + + +
    • hlsStrmObject
      + Wurde ein Streaming Device mit "set <name> createStreamDev hls" definiert, muss mit diesem Attribut der Link zum + Wiedergabeobjekt bekannt gemacht werden.
      + Die Angabe muss ein HTTP Live Streaming Objekt mit der Endung ".m3u8" enthalten.
      + Die Variable $NAME kann als Platzhalter genutzt werden und übernimmt den SSCam-Devicenamen. +

      + +
        + Beispiele:
        + attr <name> hlsStrmObject https://video-dev.github.io/streams/x36xhzz/x36xhzz.m3u8
        + # ein Beispielstream der zum Test des Streaming Devices verwendet werden kann (Internetverbindung nötig)

        + attr <name> hlsStrmObject http://192.168.2.10:32000/CamHE1.m3u8
        + # Wiedergabe eines Kamera HLS-Streams der z.B. durch ffmpeg bereitgestellt wird

        + attr <name> hlsStrmObject http://192.168.2.10:32000/$NAME.m3u8
        + # Wie obiges Beispiel mit der Variablennutzung für "CamHE1" +
      +
      +
    • +
    • htmlattr
      diff --git a/fhem/FHEM/49_SSCamSTRM.pm b/fhem/FHEM/49_SSCamSTRM.pm index 822d57eebe..da4112da54 100644 --- a/fhem/FHEM/49_SSCamSTRM.pm +++ b/fhem/FHEM/49_SSCamSTRM.pm @@ -34,6 +34,7 @@ use warnings; # Versions History intern our %SSCamSTRM_vNotesIntern = ( + "2.2.0" => "13.12.2018 load sscam_hls.js, sscam_tooltip.js from pgm2 for HLS Streaming support and tooltips ", "2.1.0" => "11.12.2018 switch \"popupStream\" from get to set ", "2.0.0" => "09.12.2018 get command \"popupStream\" and attribute \"popupStreamFW\" ", "1.5.0" => "02.12.2018 new attribute \"popupWindowSize\" ", @@ -59,6 +60,8 @@ sub SSCam_ptzpanel($;$$); sub SSCam_StreamDev($$$); sub SSCam_getclhash($;$$); +# my $hlsjs = "hls.js"; # hls.js Release von Seite https://github.com/video-dev/hls.js/releases + ################################################################ sub SSCamSTRM_Initialize($) { my ($hash) = @_; @@ -83,8 +86,11 @@ sub SSCamSTRM_Initialize($) { $hash->{FW_hideDisplayName} = 1; # Forum 88667 # $hash->{FW_addDetailToSummary} = 1; # $hash->{FW_atPageEnd} = 1; # wenn 1 -> kein Longpoll ohne informid in HTML-Tag -} + #$data{FWEXT}{SSCAMSTRM}{SCRIPT} = "/pgm2/".$hlsjs if (!$data{FWEXT}{SSCAMSTRM}{SCRIPT}); + +return undef; +} ################################################################ sub SSCamSTRM_Define($$) { @@ -200,7 +206,7 @@ sub SSCamSTRM_FwFn($;$$$) { RemoveInternalTimer($hash); $hash->{HELPER}{FW} = $FW_wname; - + $link = AnalyzePerlCommand(undef, $link) if($link =~ m/^{(.*)}$/s); my $show = $defs{$hash->{PARENT}}->{HELPER}{ACTSTRM} if($hash->{MODEL} =~ /switched/); $show = $show?"($show)":""; @@ -480,7 +486,7 @@ Abhängig vom Zustand des Streaming-Devices werden zum Start von Aktionen unters
    • autoRefresh
      Wenn gesetzt, werden aktive Browserseiten des FHEMWEB-Devices welches das SSCamSTRM-Device aufgerufen hat, nach der - eingestellten Zeit (Sekunden) neu geladen. Sollen statt dessen Broserseiten eines bestimmten FHEMWEB-Devices neu + eingestellten Zeit (Sekunden) neu geladen. Sollen statt dessen Browserseiten eines bestimmten FHEMWEB-Devices neu geladen werden, kann dieses Device mit dem Attribut "autoRefreshFW" festgelegt werden. Dies kann in manchen Fällen die Wiedergabe innerhalb einer Anwendung stabilisieren.