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 .= " API | Path | Version | Modified | ";
+ $out .= " API | Path | Version | MustKey | Modified | ";
$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 .= " $apiname | ";
$out .= " $apipath | ";
$out .= " $apiver | ";
+ $out .= " $mk | ";
$out .= " $apimod | ";
$out .= " ";
}
|