From 3481b6bff79130cd758d96804d642b1888ddbfc8 Mon Sep 17 00:00:00 2001 From: nasseeder1 Date: Mon, 24 Jan 2022 21:23:40 +0000 Subject: [PATCH] 49_SSCAM: module ready for SVS 9.0.0 forum:#125646 git-svn-id: https://svn.fhem.de/fhem/trunk@25554 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 1 + fhem/FHEM/49_SSCam.pm | 138 +++++++++++++++------------ fhem/lib/FHEM/SynoModules/API.pm | 104 ++++++++++---------- fhem/lib/FHEM/SynoModules/SMUtils.pm | 74 +++++++++++--- 4 files changed, 194 insertions(+), 123 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index 259084c06..48f9fa5d3 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,6 @@ # 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. + - change: 49_SSCAM: module ready for SVS 9.0.0 forum:#125646 - bugfix: 59_LuftdatenInfo: fix API endpoint - bugfix: 10_KNX: fix dpt14 set 0 - bugfix: 89_FULLY: Fixed speak and overlayMessage commands. diff --git a/fhem/FHEM/49_SSCam.pm b/fhem/FHEM/49_SSCam.pm index 870cda219..7533fe34e 100644 --- a/fhem/FHEM/49_SSCam.pm +++ b/fhem/FHEM/49_SSCam.pm @@ -49,6 +49,7 @@ use FHEM::SynoModules::SMUtils qw( showModuleInfo jboolmap completeAPI + ApiVal showAPIinfo setCredentials getCredentials @@ -184,6 +185,7 @@ BEGIN { # Versions History intern my %vNotesIntern = ( + "9.10.3" => "23.11.2022 made SYNO.SurveillanceStation.AudioStream, SYNO.SurveillanceStation.VideoStream optional for SVS compatibility to 9.0.0 ", "9.10.2" => "03.11.2021 set SVS compatibility to 8.2.10 ", "9.10.1" => "18.07.2021 set SVS compatibility to 8.2.9 ", "9.10.0" => "03.07.2021 change getApiSites_Parse for better simu_SVSversion, new value 8.2.8-xxxx for attr simu_SVSversion ", @@ -636,38 +638,42 @@ my %hvada = ( # Fun ); my %hsimu = ( # Funktionshash Version Simulation - "71xxxx-simu" => {AUTH => "4", EXTREC => "2", CAM => "8", SNAPSHOT => "1", PTZ => "4", - PRESET => "1", SVSINFO => "5", CAMEVENT => "1", EVENT => "5", VIDEOSTM => "1", - EXTEVT => "1", STM => "1", LOG => "1", REC => "4" }, - "72xxxx-simu" => {AUTH => "6", EXTREC => "3", CAM => "8", SNAPSHOT => "1", PTZ => "5", - PRESET => "1", SVSINFO => "6", CAMEVENT => "1", EVENT => "5", VIDEOSTM => "1", - EXTEVT => "1", STM => "1", LOG => "1", REC => "4" }, - "800xxxx-simu" => {AUTH => "6", EXTREC => "3", CAM => "9", SNAPSHOT => "1", PTZ => "5", - PRESET => "1", SVSINFO => "6", CAMEVENT => "1", EVENT => "5", VIDEOSTM => "1", - EXTEVT => "1", STM => "1", LOG => "1", REC => "6" }, - "815xxxx-simu" => {AUTH => "6", EXTREC => "3", CAM => "9", SNAPSHOT => "1", PTZ => "5", - PRESET => "1", SVSINFO => "6", CAMEVENT => "1", EVENT => "5", VIDEOSTM => "1", - EXTEVT => "1", STM => "1", HMODE => "1", LOG => "3", AUDIOSTM => "2", - VIDEOSTMS => "1", REC => "6" }, - "820xxxx-simu" => {AUTH => "6", EXTREC => "3", CAM => "9", SNAPSHOT => "1", PTZ => "5", - PRESET => "1", SVSINFO => "6", CAMEVENT => "1", EVENT => "5", VIDEOSTM => "1", - EXTEVT => "1", STM => "1", HMODE => "1", LOG => "3", AUDIOSTM => "2", - VIDEOSTMS => "1", REC => "6" }, - "828xxxx-simu" => {AUTH => "6", EXTREC => "3", CAM => "9", SNAPSHOT => "1", PTZ => "6", - PRESET => "1", SVSINFO => "8", CAMEVENT => "1", EVENT => "5", VIDEOSTM => "1", - EXTEVT => "1", STM => "1", HMODE => "1", LOG => "3", AUDIOSTM => "2", - VIDEOSTMS => "1", REC => "6" }, + "71xxxx-simu" => {INFO => "1", AUTH => "4", EXTREC => "2", CAM => "8", SNAPSHOT => "1", + PTZ => "4", PRESET => "1", SVSINFO => "5", CAMEVENT => "1", EVENT => "5", + VIDEOSTM => "1", EXTEVT => "1", STM => "1", LOG => "1", REC => "4" }, + "72xxxx-simu" => {INFO => "1", AUTH => "6", EXTREC => "3", CAM => "8", SNAPSHOT => "1", + PTZ => "5", PRESET => "1", SVSINFO => "6", CAMEVENT => "1", EVENT => "5", + VIDEOSTM => "1", EXTEVT => "1", STM => "1", LOG => "1", REC => "4" }, + "800xxxx-simu" => {INFO => "1", AUTH => "6", EXTREC => "3", CAM => "9", SNAPSHOT => "1", + PTZ => "5", PRESET => "1", SVSINFO => "6", CAMEVENT => "1", EVENT => "5", + VIDEOSTM => "1", EXTEVT => "1", STM => "1", LOG => "1", REC => "6" }, + "815xxxx-simu" => {INFO => "1", AUTH => "6", EXTREC => "3", CAM => "9", SNAPSHOT => "1", + PTZ => "5", PRESET => "1", SVSINFO => "6", CAMEVENT => "1", EVENT => "5", + VIDEOSTM => "1", EXTEVT => "1", STM => "1", LOG => "3", REC => "6", + AUDIOSTM => "2", VIDEOSTMS => "1", HMODE => "1" }, + "820xxxx-simu" => {INFO => "1", AUTH => "6", EXTREC => "3", CAM => "9", SNAPSHOT => "1", + PTZ => "5", PRESET => "1", SVSINFO => "6", CAMEVENT => "1", EVENT => "5", + VIDEOSTM => "1", EXTEVT => "1", STM => "1", HMODE => "1", LOG => "3", + AUDIOSTM => "2", VIDEOSTMS => "1", REC => "6" }, + "828xxxx-simu" => {INFO => "1", AUTH => "6", EXTREC => "3", CAM => "9", SNAPSHOT => "1", + PTZ => "6", PRESET => "1", SVSINFO => "8", CAMEVENT => "1", EVENT => "5", + VIDEOSTM => "1", EXTEVT => "1", STM => "1", HMODE => "1", LOG => "3", + AUDIOSTM => "2", VIDEOSTMS => "1", REC => "6" }, ); # Standardvariablen und Forward-Deklaration my $defSlim = 3; # default Anzahl der abzurufenden Schnappschüsse mit snapGallery my $defColumns = 3; # default Anzahl der Spalten einer snapGallery my $defSnum = "1,2,3,4,5,6,7,8,9,10"; # mögliche Anzahl der abzurufenden Schnappschüsse mit snapGallery -my $compstat = "8.2.10"; # getestete SVS-Version +my $compstat = "9.0.00"; # getestete SVS-Version my $valZoom = ".++,+,stop,-,--."; # Inhalt des Setters "setZoom" my $shutdownInProcess = 0; # Statusbit shutdown my $todef = 20; # httptimeout default Wert + my @simus = qw(7.1-xxxx 7.2-xxxx 8.0.0-xxxx + 8.1.5-xxxx 8.2.0-xxxx 8.2.8-xxxx + ); # mögliche Simulationsversionen + #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 @@ -819,6 +825,8 @@ sub Initialize { $hash->{FW_detailFn} = \&FWdetailFn; $hash->{FW_deviceOverview} = 1; + my $simver = join ",", @simus; + $hash->{AttrList} = "disable:1,0 ". "debugactivetoken:1,0 ". "debugCachetime:1,0 ". @@ -860,7 +868,7 @@ sub Initialize { "session:SurveillanceStation,DSM ". "showPassInLog:1,0 ". "showStmInfoFull:1,0 ". - "simu_SVSversion:7.1-xxxx,7.2-xxxx,8.0.0-xxxx,8.1.5-xxxx,8.2.0-xxxx,8.2.8-xxxx ". + "simu_SVSversion:$simver ". "videofolderMap ". "webCmd ". $readingFnAttributes; @@ -3638,7 +3646,7 @@ sub __runLiveview { if ($hash->{HELPER}{RUNVIEW} !~ m/snap|^live_.*hls$/x) { if ($hash->{HELPER}{RUNVIEW} =~ m/live/x) { - if($hash->{HELPER}{API}{AUDIOSTM}{VER}) { # Audio aktivieren + if(ApiVal ($hash, $hash->{HELPER}{API}{AUDIOSTM}, 'VER', '')) { # Audio aktivieren $hash->{HELPER}{ACALL}{AKEY} = "AUDIOSTM"; $hash->{HELPER}{ACALL}{APART} = qq{api=_ANAME_&version=_AVER_&method=Stream&cameraId=_CID_&_sid=_SID_}; } @@ -3646,7 +3654,7 @@ sub __runLiveview { delete $hash->{HELPER}{AUDIOLINK}; } - if($hash->{HELPER}{API}{VIDEOSTMS}{VER}) { # API "SYNO.SurveillanceStation.VideoStream" vorhanden ? (removed ab API v2.8) + if(ApiVal ($hash, $hash->{HELPER}{API}{VIDEOSTMS}, 'VER', '')) { # API "SYNO.SurveillanceStation.VideoStream" vorhanden ? (removed ab API v2.8) $hash->{HELPER}{CALL}{VKEY} = "VIDEOSTMS"; $hash->{HELPER}{CALL}{PART} = qq{api=_NAME_&version=_VER_&method=Stream&cameraId=_CID_&format=mjpeg&_sid=_SID_}; } @@ -4603,11 +4611,9 @@ sub __getCaminfoAll { __getSvsInfo ($hash); - # wenn gesetzt = manuelle Abfrage - # return if ($mode); # 24.03.2018 geänd. + my $pcia = AttrVal($name,"pollcaminfoall", 0); + my $pnl = AttrVal($name,"pollnologging", 0); - my $pcia = AttrVal($name,"pollcaminfoall",0); - my $pnl = AttrVal($name,"pollnologging",0); if ($pcia) { my $new = gettimeofday()+$pcia; InternalTimer($new, $caller, $hash, 0); @@ -5008,7 +5014,7 @@ sub __getStreamFormat { my $caller = (caller(0))[3]; RemoveInternalTimer($hash, $caller); - return if(IsDisabled($name)); + return if(IsDisabled($name) || !ApiVal ($hash, $hash->{HELPER}{API}{VIDEOSTMS}, 'VER', '')); if ($hash->{HELPER}{ACTIVE} eq "off") { $hash->{OPMODE} = "getstreamformat"; @@ -5275,8 +5281,8 @@ sub getApiSites_Parse { delActiveToken($hash); # ausgeführte Funktion ist abgebrochen, Freigabe Funktionstoken return; - - } elsif ($myjson ne "") { # Evaluiere ob Daten im JSON-Format empfangen wurden + } + elsif ($myjson ne "") { # Evaluiere ob Daten im JSON-Format empfangen wurden ($success) = evaljson($hash,$myjson); if(!$success) { @@ -5346,8 +5352,17 @@ sub getApiSites_Parse { if (AttrVal($name, "simu_SVSversion", undef)) { Log3($name, 4, "$name - SVS version $actvs will be simulated"); + + for my $ak (sort keys %{$hash->{HELPER}{API}} ) { + next if($ak =~ /^PARSET$/x); + if(!exists $hsimu{$actvs}{$ak}) { + Log3($name, 4, "$name - delete $hash->{HELPER}{API}{$ak}{NAME} due to version setting"); + delete $hash->{HELPER}{API}{$ak}; + } + } - for my $k (sort keys %{$hsimu{$actvs}}) { + for my $k (sort keys %{$hsimu{$actvs}} ) { + next if(!ApiVal ($hash, $hash->{HELPER}{API}{$k}, 'NAME', '')); $hash->{HELPER}{API}{$k}{VER} = $hsimu{$actvs}{$k}; $hash->{HELPER}{API}{$k}{MOD} = "yes"; Log3($name, 4, "$name - Version of $hash->{HELPER}{API}{$k}{NAME} adapted to: $hash->{HELPER}{API}{$k}{VER}"); @@ -5912,8 +5927,8 @@ sub camOp_Parse { readingsSingleUpdate($hash, "CamStreamFormat", $sformat, 1); setReadingErrorNone ($hash, 1); } - elsif ($OpMode eq "runpatrol") { # eine Tour wurde gestartet - my $st = (ReadingsVal("$name", "Record", "Stop") eq "Start") ? "on" : "off"; # falls Aufnahme noch läuft -> state = on setzen + elsif ($OpMode eq "runpatrol") { # eine Tour wurde gestartet + my $st = (ReadingsVal("$name", "Record", "Stop") eq "Start") ? "on" : "off"; # falls Aufnahme noch läuft -> state = on setzen DoTrigger($name,"patrol started"); Log3 ($name, 3, qq{$name - Patrol "$hash->{HELPER}{GOPATROLNAME}" of camera $camname has been started successfully} ); @@ -6435,7 +6450,7 @@ sub _parsegetsvsinfo { ## no critic "not used" } my $avsc = $major.$minor.(($small=~/\d/x) ? $small : 0); # Kompatibilitätscheck - my $avcomp = $hash->{COMPATIBILITY}; + my $avcomp = $compstat; $avcomp =~ s/\.//gx; my $compstate = ($avsc <= $avcomp) ? "true" : "false"; @@ -6503,9 +6518,9 @@ sub __parserunliveviewHLS { ## no critic "not used" my $serveraddr = $hash->{SERVERADDR}; my $serverport = $hash->{SERVERPORT}; my $camid = $hash->{CAMID}; - my $apivideostms = $hash->{HELPER}{API}{VIDEOSTMS}{NAME}; - my $apivideostmspath = $hash->{HELPER}{API}{VIDEOSTMS}{PATH}; - my $apivideostmsver = $hash->{HELPER}{API}{VIDEOSTMS}{VER}; + my $apivideostms = ApiVal ($hash, $hash->{HELPER}{API}{VIDEOSTMS}, 'NAME', ''); + my $apivideostmspath = ApiVal ($hash, $hash->{HELPER}{API}{VIDEOSTMS}, 'PATH', ''); + my $apivideostmsver = ApiVal ($hash, $hash->{HELPER}{API}{VIDEOSTMS}, 'VER', ''); my $sid = $hash->{HELPER}{SID}; $hash->{HELPER}{HLSSTREAM} = "active"; @@ -7493,7 +7508,7 @@ return; ############################################################################### # Eigenschaften des Device liefern ############################################################################### -sub IsModelCam { # Modelleigenschaft liefern Cam-> 1 , sonst 0 +sub IsModelCam { # Modelleigenschaft liefern Cam-> 1 , sonst 0 my $hash = shift; my $m = ($hash->{MODEL} ne "SVS") ? 1 : 0; @@ -7502,13 +7517,13 @@ return $m; } sub IsCapHLS { # HLS Lieferfähigkeit (existiert "SYNO.SurveillanceStation.VideoStream" & Reading) - my ($hash) = @_; + my $hash = shift; my $name = $hash->{NAME}; my $cap = 0; - my $api = $hash->{HELPER}{API}{VIDEOSTMS}{VER}; - my $csf = (ReadingsVal($name,"CamStreamFormat","MJPEG") eq "HLS")?1:0; + my $apiver = ApiVal ($hash, $hash->{HELPER}{API}{VIDEOSTMS}, 'VER', ''); + my $csf = (ReadingsVal($name,"CamStreamFormat","MJPEG") eq "HLS") ? 1 : 0; - $cap = 1 if($api && $csf); + $cap = 1 if($apiver && $csf); return $cap; } @@ -7727,15 +7742,15 @@ sub streamDev { ## no critic 'comp pws => $pws, serveraddr => $hash->{SERVERADDR}, serverport => $hash->{SERVERPORT}, - apivideostm => $hash->{HELPER}{API}{VIDEOSTM}{NAME}, - apivideostmpath => $hash->{HELPER}{API}{VIDEOSTM}{PATH}, - apivideostmver => $hash->{HELPER}{API}{VIDEOSTM}{VER}, - apiaudiostm => $hash->{HELPER}{API}{AUDIOSTM}{NAME}, - apiaudiostmpath => $hash->{HELPER}{API}{AUDIOSTM}{PATH}, - apiaudiostmver => $hash->{HELPER}{API}{AUDIOSTM}{VER}, - apivideostms => $hash->{HELPER}{API}{VIDEOSTMS}{NAME}, - apivideostmspath => $hash->{HELPER}{API}{VIDEOSTMS}{PATH}, - apivideostmsver => $hash->{HELPER}{API}{VIDEOSTMS}{VER}, + apivideostm => ApiVal ($hash, $hash->{HELPER}{API}{VIDEOSTM}, 'NAME', ''), + apivideostmpath => ApiVal ($hash, $hash->{HELPER}{API}{VIDEOSTM}, 'PATH', ''), + apivideostmver => ApiVal ($hash, $hash->{HELPER}{API}{VIDEOSTM}, 'VER', ''), + apiaudiostm => ApiVal ($hash, $hash->{HELPER}{API}{AUDIOSTM}, 'NAME', ''), + apiaudiostmpath => ApiVal ($hash, $hash->{HELPER}{API}{AUDIOSTM}, 'PATH', ''), + apiaudiostmver => ApiVal ($hash, $hash->{HELPER}{API}{AUDIOSTM}, 'VER', ''), + apivideostms => ApiVal ($hash, $hash->{HELPER}{API}{VIDEOSTMS}, 'NAME', ''), + apivideostmspath => ApiVal ($hash, $hash->{HELPER}{API}{VIDEOSTMS}, 'PATH', ''), + apivideostmsver => ApiVal ($hash, $hash->{HELPER}{API}{VIDEOSTMS}, 'VER', ''), camid => $hash->{CAMID}, sid => $hash->{HELPER}{SID}, proto => $hash->{PROTOCOL}, @@ -7845,10 +7860,10 @@ sub _streamDevMJPEG { ## no critic 'complexity not my $serverport = $params->{serverport}; my $apivideostms = $params->{apivideostms}; my $apivideostmspath = $params->{apivideostmspath}; - my $apivideostmsver = $params->{apivideostmsver}; + my $apivideostmsver = $params->{apivideostmsver}; my $apiaudiostm = $params->{apiaudiostm}; my $apiaudiostmpath = $params->{apiaudiostmpath}; - my $apiaudiostmver = $params->{apiaudiostmver}; + my $apiaudiostmver = $params->{apiaudiostmver}; my $cmdrecendless = $params->{cmdrecendless}; my $ttrecstart = $params->{ttrecstart}; @@ -7871,9 +7886,10 @@ sub _streamDevMJPEG { ## no critic 'complexity not else { if($apivideostmsver) { $link = "$proto://$serveraddr:$serverport/webapi/$apivideostmspath?api=$apivideostms&version=$apivideostmsver&method=Stream&cameraId=$camid&format=mjpeg&_sid=$sid"; - - } elsif ($hash->{HELPER}{STMKEYMJPEGHTTP}) { + } + elsif ($hash->{HELPER}{STMKEYMJPEGHTTP}) { $link = $hash->{HELPER}{STMKEYMJPEGHTTP}; + $link =~ s/"//gx; # vermeidet Javascript Fehler "SyntaxError: " unterminated string literal" } return $ret if(!$link); @@ -7883,10 +7899,10 @@ sub _streamDevMJPEG { ## no critic 'complexity not } if(!$ftui) { - $ret .= "')\">
"; + $ret .= qq{
}; } else { - $ret .= "
"; + $ret .= qq{
}; } $streamHash->{HELPER}{STREAM} = ""; # Stream für "get popupStream" speichern @@ -7900,6 +7916,7 @@ sub _streamDevMJPEG { ## no critic 'complexity not else { # Aufnahmebutton Stop $ret .= "$imgrecstop "; } + $ret .= "$imgdosnap "; } @@ -11657,7 +11674,8 @@ sub exitOnDis { if ($avail eq "disabled") { $errorcode = "402"; $exit = 1; - } elsif ($avail eq "disconnected") { + } + elsif ($avail eq "disconnected") { $errorcode = "502"; $exit = 1; } diff --git a/fhem/lib/FHEM/SynoModules/API.pm b/fhem/lib/FHEM/SynoModules/API.pm index a139f03bf..820004715 100644 --- a/fhem/lib/FHEM/SynoModules/API.pm +++ b/fhem/lib/FHEM/SynoModules/API.pm @@ -3,7 +3,7 @@ ######################################################################################################################### # API.pm # -# (c) 2020 by Heiko Maaz +# (c) 2020 - 2022 by Heiko Maaz # e-mail: Heiko dot Maaz at t-online dot de # # This Module provides Synology API information. @@ -32,7 +32,9 @@ use warnings; use utf8; use Carp qw(croak carp); -use version; our $VERSION = version->declare('1.2.0'); +use version; our $VERSION = version->declare('1.3.0'); + +# use lib qw(/opt/fhem/FHEM /opt/fhem/lib); # für Syntaxcheck mit: perl -c /opt/fhem/lib/FHEM/SynoModules/API.pm use Exporter ('import'); our @EXPORT_OK = qw(apistatic); @@ -70,28 +72,30 @@ return; ######################################################################## # Liefert die statischen Informationen der Surveillance API +# mk : 1 - API Key muss vorhanden sein +# 0 - API Key kann vorhanden sein ######################################################################## sub _staticSurveillance { my %hapi = ( - INFO => { NAME => "SYNO.API.Info" }, # Info-Seite für alle API's, einzige statische Seite ! - AUTH => { NAME => "SYNO.API.Auth" }, # API used to perform session login and logout - SVSINFO => { NAME => "SYNO.SurveillanceStation.Info" }, - EVENT => { NAME => "SYNO.SurveillanceStation.Event" }, - EXTREC => { NAME => "SYNO.SurveillanceStation.ExternalRecording" }, - EXTEVT => { NAME => "SYNO.SurveillanceStation.ExternalEvent" }, - CAM => { NAME => "SYNO.SurveillanceStation.Camera" }, # stark geändert ab API v2.8 - SNAPSHOT => { NAME => "SYNO.SurveillanceStation.SnapShot" }, # This API provides functions on snapshot, including taking, editing and deleting snapshots. - PTZ => { NAME => "SYNO.SurveillanceStation.PTZ" }, - PRESET => { NAME => "SYNO.SurveillanceStation.PTZ.Preset" }, - CAMEVENT => { NAME => "SYNO.SurveillanceStation.Camera.Event" }, - VIDEOSTM => { NAME => "SYNO.SurveillanceStation.VideoStreaming" }, # verwendet in Response von "SYNO.SurveillanceStation.Camera: GetLiveViewPath" -> StreamKey-Methode - STM => { NAME => "SYNO.SurveillanceStation.Stream" }, # Beschreibung ist falsch und entspricht "SYNO.SurveillanceStation.Streaming" auch noch ab v2.8 - HMODE => { NAME => "SYNO.SurveillanceStation.HomeMode" }, - LOG => { NAME => "SYNO.SurveillanceStation.Log" }, - AUDIOSTM => { NAME => "SYNO.SurveillanceStation.AudioStream" }, # Audiostream mit SID, removed in API v2.8 (noch undokumentiert verfügbar) - VIDEOSTMS => { NAME => "SYNO.SurveillanceStation.VideoStream" }, # Videostream mit SID, removed in API v2.8 (noch undokumentiert verfügbar) - REC => { NAME => "SYNO.SurveillanceStation.Recording" }, # This API provides method to query recording information. - ); + INFO => { NAME => "SYNO.API.Info", mk => 1 }, # Info-Seite für alle API's, einzige statische Seite ! + AUTH => { NAME => "SYNO.API.Auth", mk => 1 }, # API used to perform session login and logout + SVSINFO => { NAME => "SYNO.SurveillanceStation.Info", mk => 1 }, + EVENT => { NAME => "SYNO.SurveillanceStation.Event", mk => 1 }, + EXTREC => { NAME => "SYNO.SurveillanceStation.ExternalRecording", mk => 1 }, + EXTEVT => { NAME => "SYNO.SurveillanceStation.ExternalEvent", mk => 1 }, + CAM => { NAME => "SYNO.SurveillanceStation.Camera", mk => 1 }, # stark geändert ab API v2.8 + SNAPSHOT => { NAME => "SYNO.SurveillanceStation.SnapShot", mk => 1 }, # This API provides functions on snapshot, including taking, editing and deleting snapshots. + PTZ => { NAME => "SYNO.SurveillanceStation.PTZ", mk => 1 }, + PRESET => { NAME => "SYNO.SurveillanceStation.PTZ.Preset", mk => 1 }, + CAMEVENT => { NAME => "SYNO.SurveillanceStation.Camera.Event", mk => 1 }, + VIDEOSTM => { NAME => "SYNO.SurveillanceStation.VideoStreaming", mk => 1 }, # verwendet in Response von "SYNO.SurveillanceStation.Camera: GetLiveViewPath" -> StreamKey-Methode + STM => { NAME => "SYNO.SurveillanceStation.Stream", mk => 1 }, # Beschreibung ist falsch und entspricht "SYNO.SurveillanceStation.Streaming" auch noch ab v2.8 + HMODE => { NAME => "SYNO.SurveillanceStation.HomeMode", mk => 0 }, + LOG => { NAME => "SYNO.SurveillanceStation.Log", mk => 1 }, + AUDIOSTM => { NAME => "SYNO.SurveillanceStation.AudioStream", mk => 0 }, # Audiostream mit SID, removed in API v2.8 (noch undokumentiert verfügbar vor SVS 9.0.0 / API V 3.11) + VIDEOSTMS => { NAME => "SYNO.SurveillanceStation.VideoStream", mk => 0 }, # Videostream mit SID, removed in API v2.8 (noch undokumentiert verfügbar vor SVS 9.0.0 / API V 3.11) + REC => { NAME => "SYNO.SurveillanceStation.Recording", mk => 1 }, # This API provides method to query recording information. +); return \%hapi; } @@ -101,8 +105,8 @@ return \%hapi; ######################################################################## sub _staticChat { my %hapi = ( - INFO => { NAME => "SYNO.API.Info" }, - EXTERNAL => { NAME => "SYNO.Chat.External" }, + INFO => { NAME => "SYNO.API.Info", mk => 1 }, + EXTERNAL => { NAME => "SYNO.Chat.External", mk => 1 }, ); return \%hapi; @@ -113,12 +117,12 @@ return \%hapi; ######################################################################## sub _staticCalendar { my %hapi = ( - INFO => { NAME => "SYNO.API.Info" }, - AUTH => { NAME => "SYNO.API.Auth" }, # API used to perform session login and logout - CAL => { NAME => "SYNO.Cal.Cal" }, # API to manipulate calendar - EVENT => { NAME => "SYNO.Cal.Event" }, # Provide methods to manipulate events in the specific calendar - SHARE => { NAME => "SYNO.Cal.Sharing" }, # Get/set sharing setting of calendar - TODO => { NAME => "SYNO.Cal.Todo" }, # Provide methods to manipulate events in the specific calendar + INFO => { NAME => "SYNO.API.Info", mk => 1 }, + AUTH => { NAME => "SYNO.API.Auth", mk => 1 }, # API used to perform session login and logout + CAL => { NAME => "SYNO.Cal.Cal", mk => 1 }, # API to manipulate calendar + EVENT => { NAME => "SYNO.Cal.Event", mk => 1 }, # Provide methods to manipulate events in the specific calendar + SHARE => { NAME => "SYNO.Cal.Sharing", mk => 1 }, # Get/set sharing setting of calendar + TODO => { NAME => "SYNO.Cal.Todo", mk => 1 }, # Provide methods to manipulate events in the specific calendar ); return \%hapi; @@ -129,27 +133,27 @@ return \%hapi; ######################################################################## sub _staticFile { my %hapi = ( - INFO => { NAME => "SYNO.API.Info" }, - AUTH => { NAME => "SYNO.API.Auth" }, # Perform login and logout - FSINFO => { NAME => "SYNO.FileStation.Info" }, # Provide File Station info - LIST => { NAME => "SYNO.FileStation.List" }, # List all shared folders, enumerate files in a shared folder, and get detailed file information - SEARCH => { NAME => "SYNO.FileStation.Search" }, # Search files on given criteria - LVFOLDER => { NAME => "SYNO.FileStation.VirtualFolder" }, # List all mount point folders of virtual file system, ex: CIFS or ISO - FAVORITE => { NAME => "SYNO.FileStation.Favorite" }, # Add a folder to user’s favorites or do operations on user’s favorites - THUMB => { NAME => "SYNO.FileStation.Thumb" }, # Get a thumbnail of a file - DIRSIZE => { NAME => "SYNO.FileStation.DirSize" }, # Get the total size of files/folders within folder(s) - MD5 => { NAME => "SYNO.FileStation.MD5" }, # Get MD5 of a file - CHECKPERM => { NAME => "SYNO.FileStation.CheckPermission" }, # Check if the file/folder has a permission of a file/folder or not - UPLOAD => { NAME => "SYNO.FileStation.Upload" }, # Upload a file - DOWNLOAD => { NAME => "SYNO.FileStation.Download" }, # Download files/folders - SHARING => { NAME => "SYNO.FileStation.Sharing" }, # Generate a sharing link to share files/folders with other people and perform operations on sharing links - CFOLDER => { NAME => "SYNO.FileStation.CreateFolder" }, # Create folder(s) - RENAME => { NAME => "SYNO.FileStation.Rename" }, # Rename a file/folder - COPYMOVE => { NAME => "SYNO.FileStation.CopyMove" }, # Copy/Move files/folders - DELETE => { NAME => "SYNO.FileStation.Delete" }, # Delete files/folders - EXTRACT => { NAME => "SYNO.FileStation.Extract" }, # Extract an archive and do operations on an archive - COMPRESS => { NAME => "SYNO.FileStation.Compress" }, # Compress files/folders - BGTASK => { NAME => "SYNO.FileStation.BackgroundTask" }, # Get information regarding tasks of file operations which are run as the background process including copy, move, delete, compress and extract tasks or perform operations on these background tasks + INFO => { NAME => "SYNO.API.Info", mk => 1 }, + AUTH => { NAME => "SYNO.API.Auth", mk => 1 }, # Perform login and logout + FSINFO => { NAME => "SYNO.FileStation.Info", mk => 1 }, # Provide File Station info + LIST => { NAME => "SYNO.FileStation.List", mk => 1 }, # List all shared folders, enumerate files in a shared folder, and get detailed file information + SEARCH => { NAME => "SYNO.FileStation.Search", mk => 1 }, # Search files on given criteria + LVFOLDER => { NAME => "SYNO.FileStation.VirtualFolder", mk => 1 }, # List all mount point folders of virtual file system, ex: CIFS or ISO + FAVORITE => { NAME => "SYNO.FileStation.Favorite", mk => 1 }, # Add a folder to user’s favorites or do operations on user’s favorites + THUMB => { NAME => "SYNO.FileStation.Thumb", mk => 1 }, # Get a thumbnail of a file + DIRSIZE => { NAME => "SYNO.FileStation.DirSize", mk => 1 }, # Get the total size of files/folders within folder(s) + MD5 => { NAME => "SYNO.FileStation.MD5", mk => 1 }, # Get MD5 of a file + CHECKPERM => { NAME => "SYNO.FileStation.CheckPermission", mk => 1 }, # Check if the file/folder has a permission of a file/folder or not + UPLOAD => { NAME => "SYNO.FileStation.Upload", mk => 1 }, # Upload a file + DOWNLOAD => { NAME => "SYNO.FileStation.Download", mk => 1 }, # Download files/folders + SHARING => { NAME => "SYNO.FileStation.Sharing", mk => 1 }, # Generate a sharing link to share files/folders with other people and perform operations on sharing links + CFOLDER => { NAME => "SYNO.FileStation.CreateFolder", mk => 1 }, # Create folder(s) + RENAME => { NAME => "SYNO.FileStation.Rename", mk => 1 }, # Rename a file/folder + COPYMOVE => { NAME => "SYNO.FileStation.CopyMove", mk => 1 }, # Copy/Move files/folders + DELETE => { NAME => "SYNO.FileStation.Delete", mk => 1 }, # Delete files/folders + EXTRACT => { NAME => "SYNO.FileStation.Extract", mk => 1 }, # Extract an archive and do operations on an archive + COMPRESS => { NAME => "SYNO.FileStation.Compress", mk => 1 }, # Compress files/folders + BGTASK => { NAME => "SYNO.FileStation.BackgroundTask", mk => 1 }, # Get information regarding tasks of file operations which are run as the background process including copy, move, delete, compress and extract tasks or perform operations on these background tasks ); return \%hapi; diff --git a/fhem/lib/FHEM/SynoModules/SMUtils.pm b/fhem/lib/FHEM/SynoModules/SMUtils.pm index 1e032a794..c13faf213 100644 --- a/fhem/lib/FHEM/SynoModules/SMUtils.pm +++ b/fhem/lib/FHEM/SynoModules/SMUtils.pm @@ -3,7 +3,7 @@ ######################################################################################################################### # SMUtils.pm # -# (c) 2020-2021 by Heiko Maaz +# (c) 2020-2022 by Heiko Maaz # e-mail: Heiko dot Maaz at t-online dot de # # This Module provides routines for FHEM modules developed for Synology use cases. @@ -50,7 +50,7 @@ use FHEM::SynoModules::ErrCodes qw(:all); # Erro use GPUtils qw( GP_Import GP_Export ); use Carp qw(croak carp); -use version 0.77; our $VERSION = version->declare('1.23.1'); +use version 0.77; our $VERSION = version->declare('1.23.2'); use Exporter ('import'); our @EXPORT_OK = qw( @@ -69,6 +69,7 @@ our @EXPORT_OK = qw( smUrlEncode plotPngToFile completeAPI + ApiVal showAPIinfo setCredentials getCredentials @@ -691,19 +692,64 @@ return ($err, $file); sub completeAPI { my $jdata = shift // carp "got no data Hash reference" && return; my $apiref = shift // carp $carpnoapir && return; - + for my $key (keys %{$apiref}) { - next if($key =~ /^PARSET$/x); - $apiref->{$key}{PATH} = $jdata->{data}{$apiref->{$key}{NAME}}{path} // return; - $apiref->{$key}{VER} = $jdata->{data}{$apiref->{$key}{NAME}}{maxVersion} // return; - $apiref->{$key}{MOD} = "no"; # MOD = Version nicht modifiziert + next if($key =~ /^PARSET$/x); + $apiref->{$key}{PATH} = $jdata->{data}{$apiref->{$key}{NAME}}{path}; + $apiref->{$key}{VER} = $jdata->{data}{$apiref->{$key}{NAME}}{maxVersion}; + $apiref->{$key}{MOD} = "no"; # MOD = Version nicht modifiziert + + my $incomplete = defined $apiref->{$key}{PATH} ? 0 : 1; + return if(failInc ($apiref->{$key}{mk}, $incomplete)); } - $apiref->{PARSET} = 1; # alle API Hash values erfolgreich gesetzt + $apiref->{PARSET} = 1; # alle API Hash values erfolgreich gesetzt return 1; } +############################################################################### +# API Key must include Check +############################################################################### +sub failInc { + my $mk = shift; + my $incomplete = shift; + + if ($incomplete && $mk) { + return 1; + } + +return; +} + +############################################################################### +# liefert den Wert eines API-Keys +# +# $apihash : Hash der API-Keys +# $key : MOD - Modifizierung des API-Keys +# NAME - API-Name +# PATH - API-Pfad +# VER - API-Version +# mk - Muß-Key ? -> 0 = optional, 1 = muß +# $def : default-Wert +############################################################################### +sub ApiVal { + my $hash = shift; + my $apihash = shift; + my $key = shift; + my $def = shift; + + my $name = $hash->{NAME}; + my $type = $hash->{TYPE}; + + if(defined ($apihash) && + defined ($apihash->{$key})) { + return $apihash->{$key}; + } + +return $def; +} + ############################################################################### # zeigt den Inhalt des verwendeten API Hash als Popup # $apiref: Referenz zum instanziierten API-Hash @@ -718,20 +764,22 @@ sub showAPIinfo { my $out = ""; $out .= "Synology $type API Info

"; $out .= ""; - $out .= ""; + $out .= ""; $out .= ""; for my $key (sort keys %{$apiref}) { next if($key =~ /^PARSET$/x); - my $apiname = $apiref->{$key}{NAME}; - my $apipath = $apiref->{$key}{PATH}; - my $apiver = $apiref->{$key}{VER}; - my $apimod = $apiref->{$key}{MOD}; + my $apiname = ApiVal ($hash, $apiref->{$key}, 'NAME', ''); + my $apipath = ApiVal ($hash, $apiref->{$key}, 'PATH', ''); + my $apiver = ApiVal ($hash, $apiref->{$key}, 'VER', ''); + my $apimod = ApiVal ($hash, $apiref->{$key}, 'MOD', ''); + my $mk = ApiVal ($hash, $apiref->{$key}, 'mk', ''); $out .= ""; $out .= ""; $out .= ""; $out .= ""; + $out .= ""; $out .= ""; $out .= ""; }
API Path Version Modified
API Path Version MustKey Modified
$apiname $apipath $apiver $mk $apimod