diff --git a/fhem/CHANGED b/fhem/CHANGED index 0f6c35440..92a06174c 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: V5.3.0, new createStreamDev generic, control elements + for runView content within fhemweb, some new CamLive- + Readings, minor fixes - change: 95_Dashboard: V3.10.1, added FW_hideDisplayName, Forum #88727 - change: 98_feels_like.pm: Improved algorithms New attribute "sensorType" diff --git a/fhem/FHEM/49_SSCam.pm b/fhem/FHEM/49_SSCam.pm index ccf573d99..dd9d7355f 100644 --- a/fhem/FHEM/49_SSCam.pm +++ b/fhem/FHEM/49_SSCam.pm @@ -27,6 +27,9 @@ ######################################################################################################################### # Versions History: # +# 5.3.0 29.06.2018 changes regarding to "createStreamDev ... generic", refresh reading parentState of all +# SSCamSTRM devices with PARENT=SSCam-device, control elements for runView within fhemweb, +# new CamLive.*-Readings, minor fixes # 5.2.7 26.06.2018 fix state turns to "off" even though cam is disabled # 5.2.6 20.06.2018 running stream as human readable entry for SSCamSTRM-Device, goAbsPTZ fix set-entry für non-PTZ # 5.2.5 18.06.2018 trigger lastsnap_fw to SSCamSTRM-Device only if snap was done by it. @@ -45,7 +48,7 @@ # 4.1.0 05.05.2018 use SYNO.SurveillanceStation.VideoStream instead of SYNO.SurveillanceStation.VideoStreaming, # preparation for hls # 4.0.0 01.05.2018 AudioStream possibility added -# 3.10.0 24.04.2018 CreateStreamDev added, new features lastrec_fw_MJPEG, lastrec_fw_MPEG4/H.264 added to +# 3.10.0 24.04.2018 createStreamDev added, new features lastrec_fw_MJPEG, lastrec_fw_MPEG4/H.264 added to # playback MPEG4/H.264 videos # 3.9.2 21.04.2018 minor fixes # 3.9.1 20.04.2018 Attribute ptzPanel_use, initial webcommands in DeviceOverview changed, minor fixes ptzPanel @@ -240,7 +243,7 @@ use Time::HiRes; use HttpUtils; # no if $] >= 5.017011, warnings => 'experimental'; -my $SSCamVersion = "5.2.7"; +my $SSCamVersion = "5.3.0"; # Aufbau Errorcode-Hashes (siehe Surveillance Station Web API) my %SSCam_errauthlist = ( @@ -310,6 +313,7 @@ sub SSCam_Initialize($) { $hash->{AttrList} = "disable:1,0 ". + "genericStrmHtmlTag ". "httptimeout ". "htmlattr ". "livestreamprefix ". @@ -492,9 +496,9 @@ sub SSCam_Attr($$$$) { if ($do == 0) { delete($defs{$name}{READINGS}{StmKeymjpegHttp}); - delete($defs{$name}{READINGS}{StmKeyUnicst}); delete($defs{$name}{READINGS}{LiveStreamUrl}); - delete($defs{$name}{READINGS}{StmKeyUnicstOverHttp}); + delete($defs{$name}{READINGS}{StmKeyUnicstOverHttp}); + delete($defs{$name}{READINGS}{StmKeymxpegHttp}); } } @@ -589,7 +593,8 @@ sub SSCam_Attr($$$$) { } if($aName =~ m/pollcaminfoall/) { return "The value of \"$aName\" has to be greater than 10 seconds." if($aVal <= 10); - } + } + } if ($cmd eq "del") { @@ -618,7 +623,7 @@ sub SSCam_Set($@) { my $setlist; my @prop; - return "module is deactivated" if(IsDisabled($name)); + return if(IsDisabled($name)); if(SSCam_IsModelCam($hash)) { # selist für Cams @@ -633,7 +638,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:mjpeg,switched ". + "createStreamDev:generic,mjpeg,switched ". ((ReadingsVal("$name", "CapPTZPan", "false") ne "false") ? "createPTZcontrol:noArg ": ""). "enable:noArg ". "disable:noArg ". @@ -747,6 +752,11 @@ sub SSCam_Set($@) { $ret = CommandDefine($hash->{CL},"$livedev SSCamSTRM {SSCam_StreamDev('$name','$livedev','mjpeg')}"); return $ret if($ret); } + if($prop =~ /generic/) { + $livedev = "SSCamSTRM.$name.generic"; + $ret = CommandDefine($hash->{CL},"$livedev SSCamSTRM {SSCam_StreamDev('$name','$livedev','generic')}"); + return $ret if($ret); + } if($prop =~ /switched/) { $livedev = "SSCamSTRM.$name.switched"; $ret = CommandDefine($hash->{CL},"$livedev SSCamSTRM {SSCam_StreamDev('$name','$livedev','switched')}"); @@ -1176,11 +1186,50 @@ sub SSCam_FWsummaryFn ($$$$) { return if(!$hash->{HELPER}{LINK} || ReadingsVal($d, "state", "") =~ /^dis.*/ || IsDisabled($name)); + # Definition Tasten + my $imgblank = ""; # nicht sichtbare Leertaste + my $cmdstop = "cmd=set $d stopView"; # Stream deaktivieren + my $imgstop = ""; + my $cmdhlsreact = "cmd=set $d hlsreactivate"; # HLS Stream reaktivieren + my $imghlsreact = ""; + my $cmdmjpegrun = "cmd=set $d runView live_fw"; # MJPEG Stream aktivieren + my $imgmjpegrun = ""; + my $cmdhlsrun = "cmd=set $d runView live_fw_hls"; # HLS Stream aktivieren + my $imghlsrun = ""; + my $cmdlrirun = "cmd=set $d runView lastrec_fw"; # Last Record IFrame + my $imglrirun = ""; + my $cmdlh264run = "cmd=set $d runView lastrec_fw_MPEG4/H.264"; # Last Record H.264 + my $imglh264run = ""; + my $cmdlmjpegrun = "cmd=set $d runView lastrec_fw_MJPEG"; # Last Record MJPEG + my $imglmjpegrun = ""; + my $cmdlsnaprun = "cmd=set $d runView lastsnap_fw STRM"; # Last SNAP + my $imglsnaprun = ""; + my $cmdrecendless = "cmd=set $d on 0"; # Endlosaufnahme Start + my $imgrecendless = ""; + my $cmdrecstop = "cmd=set $d off"; # Aufnahme Stop + my $imgrecstop = ""; + my $cmddosnap = "cmd=set $d snap STRM"; # Snapshot auslösen mit Kennzeichnung "by STRM-Device" + my $imgdosnap = ""; + + my $attr = AttrVal($d, "htmlattr", " "); Log3($name, 4, "$name - SSCam_FWsummaryFn called - FW_wname: $FW_wname, device: $d, room: $room, attributes: $attr"); if($wltype eq "image") { $ret = ""; + $ret .= "$imgstop "; + $ret .= $imgblank; + if($hash->{HELPER}{RUNVIEW} =~ /live_fw/) { + if(ReadingsVal($d, "Record", "Stop") eq "Stop") { + # Aufnahmebutton endlos Start + $ret .= "$imgrecendless "; + } else { + # Aufnahmebutton Stop + $ret .= "$imgrecstop "; + } + $ret .= "$imgdosnap "; + } + $ret .= ""; if($hash->{HELPER}{AUDIOLINK} && ReadingsVal($d, "CamAudioType", "Unknown") !~ /Unknown/) { $ret .= "{HELPER}{AUDIOLINK} preload='none' volume='0.5' controls> Your browser does not support the audio element. @@ -1188,7 +1237,11 @@ sub SSCam_FWsummaryFn ($$$$) { } } elsif($wltype eq "iframe") { - $ret = "Iframes disabled"; + $ret = " + Iframes disabled + "; + $ret .= ""; + $ret .= "$imgstop "; if($hash->{HELPER}{AUDIOLINK} && ReadingsVal($d, "CamAudioType", "Unknown") !~ /Unknown/) { $ret .= "{HELPER}{AUDIOLINK} preload='none' volume='0.5' controls> Your browser does not support the audio element. @@ -1210,21 +1263,38 @@ sub SSCam_FWsummaryFn ($$$$) { } elsif($wltype eq "base64img") { $alias = $hash->{HELPER}{ALIAS}; $ret = ""; + $ret .= "$imgstop "; } elsif($wltype eq "hls") { $alias = $hash->{HELPER}{ALIAS}; - $ret = " - - - "; + $ret = " + + + Your browser does not support the video tag + "; + $ret .= ""; + $ret .= "$imgstop "; + $ret .= "$imghlsreact "; + $ret .= $imgblank; + if(ReadingsVal($d, "Record", "Stop") eq "Stop") { + # Aufnahmebutton endlos Start + $ret .= "$imgrecendless "; + } else { + # Aufnahmebutton Stop + $ret .= "$imgrecstop "; + } + $ret .= "$imgdosnap "; } elsif($wltype eq "video") { - $ret = " + $ret = " Your browser does not support the video tag. "; + $ret .= ""; + $ret .= "$imgstop "; + $ret .= ""; if($hash->{HELPER}{AUDIOLINK} && ReadingsVal($d, "CamAudioType", "Unknown") !~ /Unknown/) { $ret .= "{HELPER}{AUDIOLINK} preload='none' volume='0.5' controls> Your browser does not support the audio element. @@ -4326,19 +4396,9 @@ sub SSCam_camop_parse ($) { if(exists($hash->{HELPER}{RUNVIEW}) && $hash->{HELPER}{RUNVIEW} =~ /snap/ && !exists($data->{'data'}{'data'}[0]{imageData})); if (exists($hash->{HELPER}{RUNVIEW}) && $hash->{HELPER}{RUNVIEW} =~ /snap/ && exists($data->{'data'}{'data'}[0]{imageData})) { - delete $hash->{HELPER}{RUNVIEW}; - # Aufnahmestatus in state abbilden + delete $hash->{HELPER}{RUNVIEW}; $hash->{HELPER}{LINK} = $data->{data}{data}[0]{imageData}; - } - - if ($hash->{HELPER}{SNAPBYSTRMDEV} || $hash->{HELPER}{LSNAPBYSTRMDEV}) { - # Snap durch SSCamSTRM-Device ausgelöst - SSCam_refresh($hash,0,0,1); # kein Room-Refresh, kein SSCam-state-Event, SSCamSTRM-Event - delete $hash->{HELPER}{SNAPBYSTRMDEV}; - delete $hash->{HELPER}{LSNAPBYSTRMDEV}; - } else { - SSCam_refresh($hash,0,0,0); # kein Room-Refresh, kein SSCam-state-Event, kein SSCamSTRM-Event - } + } if($OpMode eq "getsnapgallery") { # es soll eine Schnappschußgallerie bereitgestellt (Attr snapGalleryBoost=1) bzw. gleich angezeigt werden (Attr snapGalleryBoost=0) @@ -4385,7 +4445,17 @@ sub SSCam_camop_parse ($) { } delete($hash->{HELPER}{GETSNAPGALLERY}); # Steuerbit getsnapgallery statt getsnapinfo - } + } + + if ($hash->{HELPER}{SNAPBYSTRMDEV} || $hash->{HELPER}{LSNAPBYSTRMDEV}) { + # Snap durch SSCamSTRM-Device ausgelöst + SSCam_refresh($hash,0,0,1); # kein Room-Refresh, kein SSCam-state-Event, SSCamSTRM-Event + delete $hash->{HELPER}{SNAPBYSTRMDEV}; + delete $hash->{HELPER}{LSNAPBYSTRMDEV}; + } else { + SSCam_refresh($hash,0,1,1); # kein Room-Refresh, SSCam-state-Event, SSCamSTRM-Event + } + Log3($name, $verbose, "$name - Snapinfos of camera $camname retrieved"); } elsif ($OpMode eq "runliveview" && $hash->{HELPER}{RUNVIEW} =~ m/^live_.*hls$/) { @@ -4676,17 +4746,16 @@ sub SSCam_camop_parse ($) { # Readings löschen falls sie nicht angezeigt werden sollen (showStmInfoFull) if (!AttrVal($name,"showStmInfoFull",0)) { delete($defs{$name}{READINGS}{StmKeymjpegHttp}); - delete($defs{$name}{READINGS}{StmKeyUnicst}); delete($defs{$name}{READINGS}{StmKeyUnicstOverHttp}); } readingsBeginUpdate($hash); readingsBulkUpdate($hash,"CamForceEnableMulticast",$camforcemcast) if($camforcemcast); readingsBulkUpdate($hash,"StmKey",$stmkey); - readingsBulkUpdate($hash,"StmKeymjpegHttp",$mjpegHttp) if(AttrVal($name,"showStmInfoFull",0)); - # readingsBulkUpdate($hash,"StmKeymxpegHttp",$mxpegHttp); + readingsBulkUpdate($hash,"StmKeymjpegHttp",$mjpegHttp) if(AttrVal($name,"showStmInfoFull",0)); + readingsBulkUpdate($hash,"StmKeymxpegHttp",$mxpegHttp) if(AttrVal($name,"showStmInfoFull",0)); readingsBulkUpdate($hash,"StmKeyUnicstOverHttp",$unicastOverHttp) if(AttrVal($name,"showStmInfoFull",0) && $unicastOverHttp); - readingsBulkUpdate($hash,"StmKeyUnicst",$unicastPath) if(AttrVal($name,"showStmInfoFull",0) && $unicastPath); + readingsBulkUpdate($hash,"StmKeyUnicst",$unicastPath) if($unicastPath); readingsBulkUpdate($hash,"Errorcode","none"); readingsBulkUpdate($hash,"Error","none"); readingsEndUpdate($hash, 1); @@ -4794,9 +4863,16 @@ sub SSCam_camop_parse ($) { $data->{'data'}->{'cameras'}->[0]->{'video_mirror'} = SSCam_jboolmap($data->{'data'}->{'cameras'}->[0]->{'video_mirror'}); $data->{'data'}->{'cameras'}->[0]->{'blPresetSpeed'} = SSCam_jboolmap($data->{'data'}->{'cameras'}->[0]->{'blPresetSpeed'}); + my $clstrmno = $data->{'data'}->{'cameras'}->[0]->{'detailInfo'}{'camLiveStreamNo'}; + $clstrmno++ if($clstrmno == 0); + readingsBeginUpdate($hash); readingsBulkUpdate($hash,"CamAudioType",$camaudiotype); readingsBulkUpdate($hash,"CamLiveMode",$camLiveMode); + readingsBulkUpdate($hash,"CamLiveFps",$data->{'data'}->{'cameras'}->[0]->{'detailInfo'}{'camLiveFps'}); + readingsBulkUpdate($hash,"CamLiveResolution",$data->{'data'}->{'cameras'}->[0]->{'detailInfo'}{'camLiveResolution'}); + readingsBulkUpdate($hash,"CamLiveQuality",$data->{'data'}->{'cameras'}->[0]->{'detailInfo'}{'camLiveQuality'}); + readingsBulkUpdate($hash,"CamLiveStreamNo",$clstrmno); readingsBulkUpdate($hash,"CamExposureMode",$exposuremode); readingsBulkUpdate($hash,"CamExposureControl",$exposurecontrol); readingsBulkUpdate($hash,"CamModel",$data->{'data'}->{'cameras'}->[0]->{'detailInfo'}{'camModel'}); @@ -5467,14 +5543,17 @@ sub SSCam_refresh($$$$) { readingsSingleUpdate($hash,"state", $st, 0); } - # state des SSCamSTRM-Device mit Opmode updaten (mit/ohne Event) - if($hash->{HELPER}{STRMDEV}) { - my $strmhash = $defs{$hash->{HELPER}{STRMDEV}}; - if($lpoll_strm) { - readingsSingleUpdate($strmhash,"state", $hash->{OPMODE}, 1); - } else { - readingsSingleUpdate($strmhash,"state", $hash->{OPMODE}, 0); - } + # parentState des SSCamSTRM-Device mit Opmode updaten (mit/ohne Event) + my @strmdvs = devspec2array("TYPE=SSCamSTRM:FILTER=PARENT=".$name); + if(@strmdvs) { + foreach (@strmdvs) { + my $strmhash = $defs{$_}; + if($lpoll_strm) { + readingsSingleUpdate($strmhash,"parentState", $hash->{OPMODE}, 1); + } else { + readingsSingleUpdate($strmhash,"parentState", $hash->{OPMODE}, 0); + } + } } return; @@ -5799,7 +5878,6 @@ sub SSCam_StreamDev($$$) { my $StmKey = ReadingsVal($camname,"StmKey",undef); $ret = ""; - #$ret .= ""; $ret .= ''; $ret .= ''; $ret .= ''; @@ -5845,6 +5923,44 @@ sub SSCam_StreamDev($$$) { $ret .= ""; } + } elsif($fmt =~ /generic/) { + my $htag = AttrVal($camname,"genericStrmHtmlTag",""); + if( $htag =~ m/^\s*(.*)\s*$/s ) { + $htag = $1; + $htag =~ s/\$NAME/$camname/g; + $htag =~ s/\$HTMLATTR/$ha/g; + } + + if(!$htag) { + $ret .= " Set attribute \"genericStrmHtmlTag\" in device $camname "; + $ret .= ''; + $ret .= ''; + $ret .= ''; + $ret .= ''; + return $ret; + } + + $ret .= ""; + $ret .= "$htag"; + $ret .= ""; + Log3($strmdev, 4, "$strmdev - generic Stream params:\n$htag"); + + 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}; @@ -5853,17 +5969,19 @@ sub SSCam_StreamDev($$$) { if($wltype =~ /image/) { $ret .= ""; $ret .= "$imgstop "; - $ret .= $imgblank; - if(ReadingsVal($camname, "Record", "Stop") eq "Stop") { - # Aufnahmebutton endlos Start - $ret .= "$imgrecendless "; - } else { - # Aufnahmebutton Stop - $ret .= "$imgrecstop "; - } - $ret .= "$imgdosnap "; + $ret .= $imgblank; + if($hash->{HELPER}{RUNVIEW} =~ /live_fw/) { + 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)) { + if(AttrVal($camname,"ptzPanel_use",1) && $hash->{HELPER}{RUNVIEW} =~ /live_fw/) { my $ptz_ret = SSCam_ptzpanel($camname); if($ptz_ret) { $ret .= "$ptz_ret"; @@ -5962,7 +6080,7 @@ sub SSCam_StreamDev($$$) { $ret .= ''; $ret .= ''; $ret .= ''; - #$ret .= ''; + Log3($strmdev, 4, "$strmdev - Link called: $link") if($link); return $ret; } @@ -5998,6 +6116,9 @@ sub SSCam_composegallery ($;$$) { : ReadingsTimestamp($name,"LastUpdateTime"," ")); # letzte Aktualisierung $lupt =~ s/ / \/ /; + my $cmddosnap = "cmd=set $name snap STRM"; # Snapshot auslösen mit Kennzeichnung "by STRM-Device" + my $imgdosnap = ""; + my $ha = AttrVal($name, "snapGalleryHtmlAttr", AttrVal($name, "htmlattr", 'width="500" height="325"')); # falls "SSCam_composegallery" durch ein SSCamSTRM-Device aufgerufen wird @@ -6025,8 +6146,7 @@ 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); @@ -6061,6 +6181,7 @@ sub SSCam_composegallery ($;$$) { $htmlCode .= ""; $htmlCode .= ""; $htmlCode .= ""; + $htmlCode .= "$imgdosnap " if($strmdev); $htmlCode .= "