diff --git a/fhem/contrib/DS_Starter/49_SSCam.pm b/fhem/contrib/DS_Starter/49_SSCam.pm index 891bfa237..453c60d45 100644 --- a/fhem/contrib/DS_Starter/49_SSCam.pm +++ b/fhem/contrib/DS_Starter/49_SSCam.pm @@ -1,5 +1,5 @@ ######################################################################################################################## -# $Id: 49_SSCam.pm 17735 2018-11-12 18:12:01Z DS_Starter $ +# $Id: 49_SSCam.pm 17891 2018-12-03 21:52:16Z DS_Starter $ ######################################################################################################################### # 49_SSCam.pm # @@ -45,6 +45,10 @@ use HttpUtils; # Versions History intern our %SSCam_vNotesIntern = ( + "7.7.0" => "06.12.2018 SVS-Device: autocreateCams command added, some other fixes and improvements ", + "7.6.0" => "02.12.2018 sub SSCam_ptzpanel completed by Preset and Patrol, minor fixes ", + "7.5.0" => "02.12.2018 sub SSCam_StreamDev and SSCam_composegallery changed to use popup window ", + "7.4.1" => "26.11.2018 sub composegallery deleted, SSCam_composegallery changed to get information for SSCam_refresh ", "7.4.0" => "24.11.2018 new set command \"createReadingsGroup\", versionNotes can process lists like \"2,6\", changed compatibility check, use SnapId when get information after took snapshot and sscam state-event ", "7.3.3" => "18.11.2018 change rights decsption in commandRef ", "7.3.2" => "12.11.2018 fix Warning in line 4954, set COMPATIBILITY to 8.2.2 ", @@ -94,6 +98,10 @@ our %SSCam_vNotesIntern = ( # Versions History extern our %SSCam_vNotesExtern = ( + "7.7.0" => "06.12.2018 autocreateCams command added in SVS device. BY this command all cameras installed in SVS can be defined automatically. ", + "7.6.0" => "02.12.2018 The PTZ panel is completed by \"Preset\" and \"Patrol\" (only for PTZ cameras) ", + "7.5.0" => "02.12.2018 A click on suitable content in a stream- or snapgallery device opens a popup window. ". + "The popup size can be adjusted by attribute \"popupWindowSize\". ", "7.4.0" => "20.11.2018 new command \"createReadingsGroup\". By this command a ReadingsGroup with a name of your choice (or use the default name) can be created. ". "Procedure changes of taking snapshots avoid inaccuracies if camera names in SVS very similar. ", "7.3.2" => "12.11.2018 fix Warning if 'livestreamprefix' is set to DEF, COMPATIBILITY set to 8.2.2 ", @@ -266,6 +274,8 @@ 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 use vars qw($FW_room); # currently selected room 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) = @_; @@ -639,6 +649,7 @@ sub SSCam_Set($@) { } else { # setlist für SVS Devices $setlist = "Unknown argument $opt, choose one of ". + "autocreateCams:noArg ". "credentials ". "createReadingsGroup ". "extevent:1,2,3,4,5,6,7,8,9,10 ". @@ -775,7 +786,7 @@ sub SSCam_Set($@) { my $rgdev = $prop?$prop:"RG.SSCam"; my $rgdef = '<%it_camera>,On/Offline>,< >,,< >,erkennung>,< >,,< >,(MB)>,< >,,< >,Modul>,< >,'."\n". - 'TYPE=SSCam:FILTER=MODEL!=SVS:Availability,< >,state,< >,CamMotDetSc,< >,CamLastRecTime,< >,UsedSpaceMB,< >,LastUpdateTime,< >,?!disable,< >,?!LSnap,?!LRec,?!Start,?!Stop'."\n". + 'TYPE=SSCam:FILTER=MODEL!=SVS:Availability,< >,state,< >,!CamMotDetSc,< >,!CamLastRecTime,< >,!UsedSpaceMB,< >,!LastUpdateTime,< >,?!disable,< >,?!LSnap,?!LRec,?!Start,?!Stop'."\n". '< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >'."\n". '< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >'."\n". '< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >'."\n". @@ -898,6 +909,11 @@ sub SSCam_Set($@) { $hash->{HELPER}{HOMEMODE} = $prop; SSCam_sethomemode($hash); + } elsif ($opt eq "autocreateCams" && !SSCam_IsModelCam($hash)) { + if (!$hash->{CREDENTIALS}) {return "Credentials of $name are not set - make sure you've set it with \"set $name credentials username password\"";} + + SSCam_setAutocreate($hash); + } elsif ($opt eq "goPreset" && SSCam_IsModelCam($hash)) { if (!$hash->{CREDENTIALS}) {return "Credentials of $name are not set - make sure you've set it with \"set $name credentials username password\"";} if (!$prop) {return "Function \"goPreset\" needs a \"Presetname\" as an argument";} @@ -1625,7 +1641,7 @@ sub SSCam_getcredentials ($$) { my ($retcode, $credstr); my (@key,$len,$i); - if ($boot eq 1) { + if ($boot) { # mit $boot=1 Credentials von Platte lesen und als scrambled-String in RAM legen $index = $hash->{TYPE}."_".$hash->{NAME}."_credentials"; ($retcode, $credstr) = getKeyValue($index); @@ -1664,6 +1680,7 @@ sub SSCam_getcredentials ($$) { $success = (defined($passwd)) ? 1 : 0; } + return ($success, $username, $passwd); } @@ -2428,6 +2445,54 @@ sub SSCam_hlsactivate($) { } } +############################################################################### +# Kameras mit Autocreate erstellen +############################################################################### +sub SSCam_setAutocreate($) { + my ($hash) = @_; + my $camname = $hash->{CAMNAME}; + my $name = $hash->{NAME}; + my $errorcode; + my $error; + + RemoveInternalTimer($hash, "SSCam_setAutocreate"); + return if(IsDisabled($name)); + + if (ReadingsVal("$name", "state", "") =~ /^dis.*/) { + if (ReadingsVal("$name", "state", "") eq "disabled") { + $errorcode = "402"; + } elsif (ReadingsVal("$name", "state", "") eq "disconnected") { + $errorcode = "502"; + } + + # Fehlertext zum Errorcode ermitteln + $error = &SSCam_experror($hash,$errorcode); + + readingsBeginUpdate($hash); + readingsBulkUpdate($hash,"Errorcode",$errorcode); + readingsBulkUpdate($hash,"Error",$error); + readingsEndUpdate($hash, 1); + + Log3($name, 2, "$name - ERROR - autocreate cameras - $error"); + return; + } + + if ($hash->{HELPER}{ACTIVE} eq "off") { + # Aktivierung starten + $hash->{OPMODE} = "Autocreate"; + $hash->{HELPER}{ACTIVE} = "on"; + $hash->{HELPER}{LOGINRETRIES} = 0; + + if (AttrVal($name,"debugactivetoken",0)) { + Log3($name, 3, "$name - Active-Token was set by OPMODE: $hash->{OPMODE}"); + } + SSCam_getapisites($hash); + + } else { + InternalTimer(gettimeofday()+2.1, "SSCam_setAutocreate", $hash, 0); + } +} + ############################################################################### # HLS-Stream reaktivieren (stoppen & starten) ############################################################################### @@ -3726,8 +3791,8 @@ sub SSCam_checksid ($) { return; } - if(SSCam_IsModelCam($hash)) { - # Normalverarbeitung für Cams + if(SSCam_IsModelCam($hash) || $hash->{OPMODE} eq "Autocreate") { + # Normalverarbeitung für Cams oder Autocreate Cams return SSCam_getcamid($hash); } else { # Sprung zu SSCam_camop wenn SVS Device @@ -3791,9 +3856,11 @@ sub SSCam_getcamid_parse ($) { my $hash = $param->{hash}; my $name = $hash->{NAME}; my $camname = $hash->{CAMNAME}; - my $apicammaxver = $hash->{HELPER}{APICAMMAXVER}; + my $apicammaxver = $hash->{HELPER}{APICAMMAXVER}; + my $OpMode = $hash->{OPMODE}; my ($data,$success,$error,$errorcode,$camid); - my ($i,$n,$id); + my ($i,$n,$id,$errstate,$camdef,$nrcreated); + my $cdall = ""; my %allcams; if ($err ne "") { @@ -3827,7 +3894,7 @@ sub SSCam_getcamid_parse ($) { if ($success) { # die Liste aller Kameras konnte ausgelesen werden - $i = 0; + ($i,$nrcreated) = (0,0); # Namen aller installierten Kameras mit Id's in Assoziatives Array einlesen %allcams = (); @@ -3840,6 +3907,40 @@ sub SSCam_getcamid_parse ($) { $id = $data->{'data'}->{'cameras'}->[$i]->{'id'}; $allcams{"$n"} = "$id"; $i += 1; + + if ($OpMode eq "Autocreate") { + # Cam autocreate + ($err,$camdef) = SSCam_Autocreate($hash,$n); + if($camdef) { + $cdall = $cdall.($cdall?", ":"").$camdef; + $nrcreated++; + } + $errstate = $err if($err); + } + + } + + if ($OpMode eq "Autocreate") { + # Cam autocreate + Log3($name, 3, "$name - Cameras defined by autocreate: $cdall") if($cdall); + + $errstate = $errstate?$errstate:"none"; + readingsBeginUpdate($hash); + readingsBulkUpdate($hash,"NumberAutocreatedCams",$nrcreated); + readingsBulkUpdate($hash,"Errorcode","none"); + readingsBulkUpdate($hash,"Error",$errstate); + readingsBulkUpdate($hash,"state","autocreate finished"); + readingsEndUpdate($hash, 1); + + CommandSave(undef, undef) if($errstate eq "none" && $nrcreated && AttrVal("global","autosave", 1)); + + # Freigabe Funktionstoken + $hash->{HELPER}{ACTIVE} = "off"; + if (AttrVal($name,"debugactivetoken",0)) { + Log3($name, 3, "$name - Active-Token deleted by OPMODE: $hash->{OPMODE}"); + } + + return; } # Ist der gesuchte Kameraname im Hash enhalten (in SVS eingerichtet ?) @@ -3992,7 +4093,7 @@ sub SSCam_camop ($) { my $snapid = ReadingsVal("$name", "LastSnapId", " "); if($OpMode eq "getsnapinfo") { Log3($name,4, "$name - Call getsnapinfo with params: Image numbers => $limit, Image size => $imgsize, Id => $snapid"); - $url = "$proto://$serveraddr:$serverport/webapi/$apitakesnappath?api=\"$apitakesnap\"&method=\"List\"&version=\"$apitakesnapmaxver\"&idList =\"$snapid\"&keyword=\"$keyword\"&imgSize=\"$imgsize\"&limit=\"$limit\"&_sid=\"$sid\""; + $url = "$proto://$serveraddr:$serverport/webapi/$apitakesnappath?api=\"$apitakesnap\"&method=\"List\"&version=\"$apitakesnapmaxver\"&idList =\"$snapid\"&imgSize=\"$imgsize\"&limit=\"$limit\"&_sid=\"$sid\""; } else { Log3($name,4, "$name - Call getsnapinfo with params: Image numbers => $limit, Image size => $imgsize, Keyword => $keyword"); $url = "$proto://$serveraddr:$serverport/webapi/$apitakesnappath?api=\"$apitakesnap\"&method=\"List\"&version=\"$apitakesnapmaxver\"&keyword=\"$keyword\"&imgSize=\"$imgsize\"&limit=\"$limit\"&_sid=\"$sid\""; @@ -5066,13 +5167,8 @@ sub SSCam_camop_parse ($) { my $stmkey = $sk[1]; $stmkey =~ tr/"//d; # Quotes in StmKey entfernen falls noQuotesForSID gesezt - $mjpegHttp =~ tr/"//d if(AttrVal($name, "noQuotesForSID",0)); - - # Readings löschen falls sie nicht angezeigt werden sollen (showStmInfoFull) - #if (!AttrVal($name,"showStmInfoFull",0)) { - # delete($defs{$name}{READINGS}{StmKeymjpegHttp}); - #delete($defs{$name}{READINGS}{StmKeyUnicstOverHttp}); - #} + # $mjpegHttp =~ tr/"//d if(AttrVal($name, "noQuotesForSID",0)); + $mjpegHttp =~ tr/"//d; # Streaminginfos in Helper speichern $hash->{HELPER}{STMKEYMJPEGHTTP} = $mjpegHttp if($mjpegHttp); @@ -5799,9 +5895,58 @@ sub SSCam_logout_return ($) { if (AttrVal($name,"debugactivetoken",0)) { Log3($name, 3, "$name - Active-Token deleted by OPMODE: $hash->{OPMODE}"); } + return; } +############################################################################################# +# Autocreate für Kameras +# $sn = Name der Kamera in SVS +############################################################################################# +sub SSCam_Autocreate ($$) { + my ($hash,$sn) = @_; + my $name = $hash->{NAME}; + my $type = $hash->{TYPE}; + + my ($cmd, $err); + my $camname = makeDeviceName($sn); # erlaubten Kameranamen für FHEM erzeugen + my $camhash = $defs{$camname}; # Test ob SSCam-Device schon definiert ist + + if(!$camhash) { + my $arg = $hash->{SERVERADDR}." ".$hash->{SERVERPORT}; + $cmd = "$camname $type $sn $arg"; + Log3($name, 2, "$name - Autocreate camera: define $cmd"); + $err = CommandDefine(undef, $cmd); + + if($err) { + Log3($name, 1, "ERROR: $err"); + } else { + my $room = AttrVal($name, "room", "SSCam"); + my $session = AttrVal($name, "session", "DSM"); + CommandAttr(undef,"$camname room $room"); + CommandAttr(undef,"$camname session $session"); + CommandAttr(undef,"$camname icon it_camera"); + CommandAttr(undef,"$camname pollcaminfoall 210"); + CommandAttr(undef,"$camname pollnologging 1"); + CommandAttr(undef,"$camname httptimeout 20"); + + # Credentials abrufen und setzen + my ($success, $username, $password) = SSCam_getcredentials($hash,0); + if($success) { + CommandSet(undef, "$camname credentials $username $password"); + } + + InternalTimer(gettimeofday()+1.8, "SSCam_addptzattr", "$name", 0); + + } + } else { + Log3($name, 4, "$name - Autocreate - camera \"$camname\" already exists"); + $camname = ""; + } + +return ($err,$camname); +} + ############################################################################### # Test ob JSON-String empfangen wurde ############################################################################### @@ -6049,6 +6194,8 @@ sub SSCam_ptzpanel($;$$) { my $hash = $defs{$name}; my $iconpath = AttrVal("$name","ptzPanel_iconPath","www/images/sscam"); my $iconprefix = AttrVal("$name","ptzPanel_iconPrefix","black_btn_"); + my $valPresets = ReadingsVal("$name","Presets",""); + my $valPatrols = ReadingsVal("$name","Patrols",""); my $rowisset = 0; my $ptz_ret; my $row; @@ -6104,6 +6251,61 @@ sub SSCam_ptzpanel($;$$) { $ptz_ret .= ""; $ptz_ret .= ""; + ######################## + # add Preset & Patrols + + my ($Presets,$Patrols,$fn); + my $cmdPreset = "goPreset"; + my $cmdPatrol = "runPatrol"; + + foreach $fn (sort keys %{$data{webCmdFn}}) { + no strict "refs"; + $Presets = &{$data{webCmdFn}{$fn}}($FW_wname,$name,"",$cmdPreset,$valPresets); + use strict "refs"; + last if(defined($Presets)); + } + if($Presets) { + $Presets =~ s,^]*>(.*)$,$1,; + # Log3($name, 1, "$name - commandArgs: $Presets"); + } else { + $Presets = FW_pH "cmd.$name=set $name $cmdPreset", $cmdPreset, 0, "", 1, 1; + } + + foreach $fn (sort keys %{$data{webCmdFn}}) { + no strict "refs"; + $Patrols = &{$data{webCmdFn}{$fn}}($FW_wname,$name,"",$cmdPatrol,$valPatrols); + use strict "refs"; + last if(defined($Patrols)); + } + + + # Rahmenklasse + $ptz_ret .= "
"; + $ptz_ret .= ""; + $ptz_ret .= ""; + $ptz_ret .= '"; + $ptz_ret .= ""; + $ptz_ret .= "
'; + + # Dropdown Klasse + $ptz_ret .= ""; + $ptz_ret .= ""; + $ptz_ret .= ""; + $ptz_ret .= ""; + $ptz_ret .= "
Preset:
$Presets
"; + + $ptz_ret .= ""; + $ptz_ret .= ""; + $ptz_ret .= ""; + $ptz_ret .= ""; + $ptz_ret .= "
Patrol:
$Patrols
"; + + # Rahmenklasse end + $ptz_ret .= "
"; + $ptz_ret .= "
"; + + ##################### + if ($rowisset) { return $ptz_ret; } else { @@ -6176,9 +6378,9 @@ return; } ###################################################################################### -# Stream einer Kamera - Kamera Liveview weblink device -# API: SYNO.SurveillanceStation.VideoStreaming -# Methode: GetLiveViewPath +# Funktion für SSCamSTRM-Devices - Kamera Liveview weblink device +# API: SYNO.SurveillanceStation.VideoStreaming +# Methode: GetLiveViewPath ###################################################################################### sub SSCam_StreamDev($$$) { my ($camname,$strmdev,$fmt) = @_; @@ -6234,6 +6436,8 @@ sub SSCam_StreamDev($$$) { my $ha = AttrVal($camname, "htmlattr", 'width="500" height="325"'); # HTML Attribute der Cam $ha = AttrVal($strmdev, "htmlattr", $ha); # htmlattr mit htmattr Streaming-Device übersteuern + my $pws = AttrVal($strmdev, "popupWindowSize", ""); # Größe eines Popups + $pws =~ s/"//g if($pws); my $StmKey = ReadingsVal($camname,"StmKey",undef); $ret = ""; @@ -6263,7 +6467,7 @@ sub SSCam_StreamDev($$$) { if($apiaudiostmmaxver) { # keine API "SYNO.SurveillanceStation.AudioStream" mehr ab API v2.8 $audiolink = "$proto://$serveraddr:$serverport/webapi/$apiaudiostmpath?api=$apiaudiostm&version=$apiaudiostmmaxver&method=Stream&cameraId=$camid&_sid=$sid"; } - $ret .= "
"; + $ret .= "')\">
"; if(ReadingsVal($camname, "Record", "Stop") eq "Stop") { # Aufnahmebutton endlos Start $ret .= "$imgrecendless "; @@ -6286,6 +6490,7 @@ sub SSCam_StreamDev($$$) { Your browser does not support the audio element. "; $ret .= ""; + $ret .= "" if(AttrVal($camname,"ptzPanel_use",1)); } } elsif($fmt =~ /generic/) { @@ -6333,7 +6538,7 @@ sub SSCam_StreamDev($$$) { if($link && $wltype =~ /image|iframe|video|base64img|embed|hls/) { if($wltype =~ /image/) { - $ret .= "
"; + $ret .= "')\">
"; $ret .= "$imgstop "; $ret .= $imgblank; if($hash->{HELPER}{RUNVIEW} =~ /live_fw/) { @@ -6359,10 +6564,12 @@ sub SSCam_StreamDev($$$) { $ret .= ""; + $ret .= ""; + $ret .= "" if(AttrVal($camname,"ptzPanel_use",1)); } } elsif ($wltype =~ /iframe/) { - $ret .= "
"; $ret .= "$imgstop "; @@ -6375,10 +6582,11 @@ sub SSCam_StreamDev($$$) { Your browser does not support the audio element. "; $ret .= ""; + $ret .= "" if(AttrVal($camname,"ptzPanel_use",1)); } } elsif ($wltype =~ /video/) { - $ret .= "