########################################################################################################################
# $Id$
#########################################################################################################################
# 49_SSCam.pm
#
# (c) 2015-2018 by Heiko Maaz
# e-mail: Heiko dot Maaz at t-online dot de
#
# This Module can be used to operate Cameras defined in Synology Surveillance Station 7.0 or higher.
# It's based on and uses Synology Surveillance Station API.
#
# This script is part of fhem.
#
# Fhem is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# Fhem is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with fhem. If not, see .
#
#########################################################################################################################
# Versions History:
#
# 7.1.0 02.09.2018 PIR Sensor enable/disable, SSCam_Set/SSCam_Get optimized
# 7.0.1 27.08.2018 enable/disable issue (https://forum.fhem.de/index.php/topic,45671.msg830869.html#msg830869)
# 7.0.0 27.07.2018 compatibility to API v2.8
# 6.0.1 04.07.2018 Reading CamFirmware
# 6.0.0 03.07.2018 HTTPS Support, buttons for refresh SSCamSTRM-devices
# 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.
# 5.2.4 17.06.2018 SSCam_composegallery added and write warning if old composegallery-weblink device is used
# 5.2.3 16.06.2018 no SSCamSTRM refresh when snapgetinfo was running without taken a snap by SSCamSTRM-Device
# 5.2.2 16.06.2018 compatibility to SSCamSTRM V 1.1.0
# 5.2.1 14.06.2018 design change of SSCam_StreamDev, change in event generation for SSCam_StreamDev, fix global vars
# 5.2.0 14.06.2018 support longpoll refresh of SSCamSTRM-Devices
# 5.1.0 13.06.2018 more control elements (Start/Stop Recording, Take Snapshot) in func SSCam_StreamDev
# control of detaillink is moved to SSCamSTRM-device
# 5.0.1 12.06.2018 control of page refresh improved (for e.g. Floorplan,Dashboard)
# 5.0.0 11.06.2018 HLS Streaming, Buttons for Streaming-Devices, use of module SSCamSTRM for Streaming-Devices,
# deletion of Streaming-devices if SSCam-device is deleted, some more improvements, minor bugfixes
# 4.3.0 27.05.2018 HLS preparation changed
# 4.2.0 22.05.2018 PTZ-Panel integrated to created StreamDevice
# 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
# 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
# 3.9.0 17.04.2018 control panel & PTZcontrol weblink device for PTZ cams
# 3.8.4 06.04.2018 Internal MODEL changed to SVS or "CamVendor - CamModel" for Cams
# 3.8.3 05.04.2018 bugfix V3.8.2, $OpMode "Start" changed, composegallery changed
# 3.8.2 04.04.2018 $attr replaced by AttrVal, SSCam_wdpollcaminfo redesigned
# 3.8.1 04.04.2018 some codereview like new sub SSCam_jboolmap
# 3.8.0 03.04.2018 new reading PresetHome, setHome command, minor fixes
# 3.7.0 26.03.2018 minor details of setPreset changed, new command delPreset
# 3.6.0 25.03.2018 setPreset command, changed SSCam_wdpollcaminfo, SSCam_getcaminfoall
# 3.5.0 22.03.2018 new get command listPresets
# 3.4.0 21.03.2018 new commands startTracking, stopTracking
# 3.3.1 20.03.2018 new readings CapPTZObjTracking, CapPTZPresetNumber
# 3.3.0 25.02.2018 code review, API bug fix of runview lastrec, commandref revised (forum:#84953)
# 3.2.4 18.11.2017 fix bug don't retrieve SSCam_getptzlistpreset if cam is disabled
# 3.2.3 08.10.2017 set optimizeParams, get caminfo (simple), minor bugfix, commandref revised
# 3.2.2 03.10.2017 make functions ready to use "SYNO.SurveillanceStation.PTZ" version 5, minor fixes, commandref
# revised
# 3.2.1 02.10.2017 change some "SYNO.SurveillanceStation.Camera" methods to version 9
# 3.2.0 27.09.2017 new command get listLog, change to $hash->{HELPER}{".SNAPHASH"} for avoid huge "list"-report
# 3.1.0 26.09.2017 move extevent from CAM to SVS model, Reading PollState enhanced for CAM-Model, minor fixes
# 3.0.0 23.09.2017 Internal MODEL SVS or CAM -> distinguish/support Cams and SVS in different devices
# new comand get storedCredentials, commandref revised
# 2.9.0 20.09.2017 new function get homeModeState, minor fixes at simu_SVSversion, commandref revised
# 2.8.2 19.09.2017 some preparations for version 9 of API "SYNO.SurveillanceStation.Camera", SSCam_logout added to function
# get scanVirginirgin
# 2.8.1 17.09.2017 attr simu_SVSversion changed, $mjpegHttp quotes dependend if noQuotesForSID set, commandref revised
# 2.8.0 07.09.2017 Home Mode, commandref revised
# 2.7.1 28.08.2017 minor fixes
# 2.7.0 20.08.2017 bugfix if credentials not set, set maximum password lenth to 20
# 2.6.3 12.08.2017 get snapGallery can also be triggered by at or notify (better use than "set"), commandref revised
# 2.6.2 11.08.2017 set snapGallery can be triggered by at or notify
# 2.6.1 07.08.2017 some changes in composegallery if createSnapGallery used, room Snapshots changed to SnapGalllery
# commandref revised
# 2.6.0 06.08.2017 new command createSnapGallery
# 2.5.4 05.08.2017 analyze $hash->{CL} in SetFn bzw. GetFn, set snapGallery only if snapGalleryBoost=1 is set,
# some snapGallery improvements and fixes
# 2.5.3 02.08.2017 implement snapGallery as set-command
# 2.5.2 01.08.2017 get snapGallery with or without snapGalleryBoost (some more attributes for snapGallery)
# 2.5.1 31.07.2017 sub composegallery (no polling necessary)
# 2.5.0 31.07.2017 logtext revised, new get snapGallery command
# 2.4.1 29.07.2017 fix behavior of state when starting lastsnap_fw, fix "uninitialized value in pattern match (m//)
# at ./FHEM/49_SSCam.pm line 2895"
# 2.4.0 28.07.2017 new set command runView lastsnap_fw, commandref revised, minor fixes
# 2.3.2 28.07.2017 code change of SSCam_getcaminfo (params of Internaltimer)
# 2.3.1 28.07.2017 code review creating log entries when pollnologging is set/unset
# 2.3.0 27.07.2017 new "get snapinfo" command, minor fixes
# 2.2.4 25.07.2017 avoid error "Operation Getptzlistpreset of Camera ... was not successful" if cam is disabled
# 2.2.3 30.06.2017 fix if SVSversion small "0", create events for "snap"
# 2.2.2 11.06.2017 bugfix SSCam_login, SSCam_login_return,
# Forum: https://forum.fhem.de/index.php/topic,45671.msg646701.html#msg646701
# 2.2.1 15.05.2017 avoid FW_detailFn because of FW_deviceOverview is active (double streams in detailview if on)
# 2.2.0 10.05.2017 check if JSON module has been loaded successfully, DeviceOverview available, options of
# runView changed image->live_fw, link->live_link, link_open->live_open, lastrec ->lastrec_fw,
# commandref revised
# 2.1.4 08.05.2017 commandref changed
# 2.1.3 05.05.2017 issue of operation error if CAMID is set and SID isn't valid, more login-errorcodes evaluation
# 2.1.2 04.05.2017 default login retries increased to 3
# 2.1.1 17.04.2017 SSCam_runliveview routine changed, {HELPER}{SID_STRM} deleted
# 2.1.0 12.04.2017 some codereview, getapisites cached, CAMID cached, rewrite logs from verbose 4 to 5,
# get scanVirgin, commandref replenished
# 2.0.0 10.04.2017 redesign login procedure, fix Reading SVSversion use SMALL version, new attr loginRetries
# 1.42 15.03.2017 SSCam_camop changed to get all cam id's and names
# 1.41 15.03.2017 minor bugfix of blank character in state "disabled" (row 3383)
# 1.40 21.01.2017 downgrade of API apicammaxver in SVS 8.0.0
# 1.39 20.01.2017 compatibility to SVS 8.0.0, Version in Internals, execute SSCam_getsvsinfo after set credentials
# 1.37 10.10.2016 bugfix Experimental keys on scalar is now forbidden (Perl >= 5.23)
# (Forum: #msg501709)
# 1.36 18.09.2016 bugfix of get presets, get patrols of zoom-cams without pan/tilt
# 1.35 17.09.2016 internal timer of start-routines optimized
# 1.34 15.09.2016 simu_SVSversion changed, added 407 errorcode message, external recording changed
# for SVS 7.2
# 1.33 21.08.2016 function get stmUrlPath added, fit to new commandref style, attribute showStmInfoFull added
# 1.32.1 18.08.2016 empty event LastSnapId fixed
# 1.32 17.08.2016 Logging of verbose 4 changed
# 1.31 15.08.2016 Attr "noQuotesForSID" added, avoid possible 402 - permission denied problems
# in some SVS/DS-combinations
# 1.30 15.08.2016 commandref revised, more v4 logging in special case
# 1.29 02.07.2016 add regex for adaption SVS version, url call for "snap" changed
# 1.28 30.06.2016 Attr "showPassInLog" added, per default no password will be shown in log
# 1.27 29.06.2016 Attr "simu_SVSversion" added, sub login_nonbl changed,
# sub camret_nonbl changed (getlistptzpreset) due to 7.2 problem
# 1.26.3 28.06.2016 Time::HiRes added
# 1.26.2 05.05.2016 change: get "snapfileinfo" will get back an Infomessage if Reading "LastSnapId"
# isn't available
# 1.26.1 27.04.2016 bugfix module will not load due to Unknown warnings category 'experimental'
# when using an older perl version
# 1.26 22.04.2016 Attribute "disable" to deactivate the module added
# 1.25 18.04.2016 motion detection parameters can be entered if
# motion detection by camera or SVS is used
# 1.24 16.04.2016 behavior of "set ... on" changed, Attr "recextend" added
# please have a look at commandref and Wiki
# bugfix: setstate-warning if FHEM will restarted and SVS is not reachable
# (Forum: #308)
# 1.23.2 12.04.2016 code review, no functional changes
# 1.23.1 07.04.2016 command check for set cmd's don't work completely
# 1.23 02.04.2016 change to RemoveInternalTimer for functions
# 1.22 27.03.2016 bugfix "link_open" doesn't work after last update
# 1.21 23.03.2016 added "lastrec"," lastrec_open" to playback last recording
# 1.20.3 19.03.2016 change: delay of InternalTimer(s) changed
# "ptzlistpresets" - "id" changed to "position" according to Synology-ticket
# run "SSCam_geteventlist" automatically after recording-stop
# 1.20.2 14.03.2016 change: routine "SSCam_initonboot" changed
# 1.20.1 12.03.2016 bugfix: default recordtime 15 s is used if attribute "rectime" is set to "0"
# 1.20 09.03.2016 command "extevent" added
# 1.19.3 07.03.2016 bugfix "uninitialized value $lastrecstarttime",
# "uninitialized value $lastrecstoptime",
# new attribute "videofolderMap"
# 1.19.2 06.03.2016 Reading "CamLastRec" added which contains Path/name
# of last recording
# 1.19.1 28.02.2016 enhanced command runView by option "link_open" to
# open a streamlink immediately
# 1.19 25.02.2016 functions for cam-livestream added
# 1.18.1 21.02.2016 fixed a problem that the state is "disable" instead of
# "disabled" if a camera is disabled and FHEM will be restarted
# 1.18 20.02.2016 function "get ... eventlist" added,
# Reading "CamEventNum" added which containes total number of
# camera events,
# change usage of reading "LastUpdateTime"
# 1.17 19.02.2016 function "runPatrol" added that starts predefined patrols
# of PTZ-cameras,
# Reading "CamDetMotSc" added
# 1.16.1 17.02.2016 Reading "CamExposureControl" added
# 1.16 16.02.2016 set up of motion detection source now possible
# 1.15 15.02.2016 control of exposure mode day, night & auto is possible now
# 1.14 14.02.2016 The port in DEF-String is optional now,
# if not given, default port 5000 is used
# 1.13.2 13.02.2016 fixed a problem that manual updates using "getcaminfoall" are
# leading to additional pollingloops if polling is used,
# attribute "debugactivetoken" added for debugging-use
# 1.13.1 12.02.2016 fixed a problem that a usersession won't be destroyed if a
# function couldn't be executed successfully
# 1.13 feature for retrieval snapfilename added
# 1.12.1 09.02.2016 bugfix: "goAbsPTZ" may be unavailable on Windows-systems
# 1.12 08.02.2016 added function "move" for continuous PTZ action
# 1.11.1 07.02.2016 entries with loglevel "2" reviewed, changed to loglevel "3"
# 1.11 05.02.2016 added function "goPreset" and "goAbsPTZ" to control the move of PTZ lense
# to absolute positions
# refere to commandref or have a look in forum at:
# http://forum.fhem.de/index.php/topic,45671.msg404275.html#msg404275 ,
# http://forum.fhem.de/index.php/topic,45671.msg404892.html#msg404892
# 1.10 02.02.2016 added function "svsinfo" to get informations about installed SVS-package,
# if Availability = " disconnected" then "state"-value will be "disconnected" too,
# saved Credentials were deleted from file if a device will be deleted
# 1.9.1 31.01.2016 a little bit code optimization
# 1.9 28.01.2016 fixed the problem a recording may still stay active if fhem
# will be restarted after a recording was triggered and
# the recordingtime wasn't be over,
# Enhancement of readings.
# 1.8 25.01.2016 changed define in order to remove credentials from string,
# added "set credentials" command to save username/password,
# added Attribute "session" to make login-session selectable,
# Note: You have to adapt your define-strings !!
# Refere to commandref or look in forum at:
# http://forum.fhem.de/index.php/topic,45671.msg397449.html#msg397449
# 1.7 18.01.2016 Attribute "httptimeout" added
# 1.6 16.01.2016 Change the define-string related to rectime.
# Note: See all changes to rectime usage in commandref or here:
# http://forum.fhem.de/index.php/topic,45671.msg391664.html#msg391664
# 1.5.1 11.01.2016 Vars "USERNAME" and "RECTIME" removed from internals,
# Var (Internals) "SERVERNAME" changed to "SERVERADDR",
# minor change of Log messages,
# Note: use rereadcfg in order to activate the changes
# 1.5 04.01.2016 Function "Get" for creating Camera-Readings integrated,
# Attributs pollcaminfoall, pollnologging added,
# Function for Polling Cam-Infos added.
# 1.4 23.12.2015 function "enable" and "disable" for SS-Cams added,
# changed timout of Http-calls to a higher value
# 1.3 19.12.2015 function "snap" for taking snapshots added,
# fixed a bug that functions may impact each other
# 1.2 14.12.2015 improve usage of verbose-modes
# 1.1 13.12.2015 use of InternalTimer instead of fhem(sleep)
# 1.0 12.12.2015 changed completly to HttpUtils_NonblockingGet for calling websites nonblocking,
# LWP is not needed anymore
#
#
# Definition: define SSCam [ServerPort]
#
# Example of defining a Cam-device: define CamCP1 SSCAM Carport 192.168.2.20 [5000] [HTTP(S)]
# Example of defining a SVS-device: define SDS1 SSCAM SVS 192.168.2.20 [5000] [HTTP(S)]
#
package main;
eval "use JSON qw( decode_json );1;" or my $SScamMMDBI = "JSON"; # Debian: apt-get install libjson-perl
use Data::Dumper; # Perl Core module
use strict;
use warnings;
use MIME::Base64;
use Time::HiRes;
use HttpUtils;
# no if $] >= 5.017011, warnings => 'experimental';
# Version und getestete SVS-Version
my $SSCamVersion = "7.1.0";
my $compstat = "8.2.0";
# Aufbau Errorcode-Hashes (siehe Surveillance Station Web API)
my %SSCam_errauthlist = (
100 => "Unknown error",
101 => "The account parameter is not specified",
102 => "API does not exist",
400 => "Invalid user or password",
401 => "Guest or disabled account",
402 => "Permission denied - DSM-Session: make sure user is member of Admin-group, SVS-Session: make sure SVS package is started, make sure FHEM-Server IP won't be blocked in DSM automated blocking list",
403 => "One time password not specified",
404 => "One time password authenticate failed",
405 => "method not allowd - maybe the password is too long",
407 => "Permission denied - make sure FHEM-Server IP won't be blocked in DSM automated blocking list",
);
my %SSCam_errlist = (
100 => "Unknown error",
101 => "Invalid parameters",
102 => "API does not exist",
103 => "Method does not exist",
104 => "This API version is not supported",
105 => "Insufficient user privilege",
106 => "Connection time out",
107 => "Multiple login detected",
117 => "need manager rights in SurveillanceStation for operation",
400 => "Execution failed",
401 => "Parameter invalid",
402 => "Camera disabled",
403 => "Insufficient license",
404 => "Codec activation failed",
405 => "CMS server connection failed",
407 => "CMS closed",
410 => "Service is not enabled",
412 => "Need to add license",
413 => "Reach the maximum of platform",
414 => "Some events not exist",
415 => "message connect failed",
417 => "Test Connection Error",
418 => "Object is not exist",
419 => "Visualstation name repetition",
439 => "Too many items selected",
502 => "Camera disconnected",
600 => "Presetname and PresetID not found in Hash",
);
# 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
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
sub SSCam_Initialize($) {
my ($hash) = @_;
$hash->{DefFn} = "SSCam_Define";
$hash->{UndefFn} = "SSCam_Undef";
$hash->{DeleteFn} = "SSCam_Delete";
$hash->{SetFn} = "SSCam_Set";
$hash->{GetFn} = "SSCam_Get";
$hash->{AttrFn} = "SSCam_Attr";
# Aufrufe aus FHEMWEB
$hash->{FW_summaryFn} = "SSCam_FWsummaryFn";
$hash->{FW_detailFn} = "SSCam_FWdetailFn";
$hash->{FW_deviceOverview} = 1;
$hash->{AttrList} =
"disable:1,0 ".
"genericStrmHtmlTag ".
"httptimeout ".
"htmlattr ".
"livestreamprefix ".
"loginRetries:1,2,3,4,5,6,7,8,9,10 ".
"videofolderMap ".
"pollcaminfoall ".
"snapGalleryBoost:0,1 ".
"snapGallerySize:Icon,Full ".
"snapGalleryNumber:$SSCAM_snum ".
"snapGalleryColumns ".
"snapGalleryHtmlAttr ".
"pollnologging:1,0 ".
"debugactivetoken:1,0 ".
"rectime ".
"recextend:1,0 ".
"noQuotesForSID:1,0 ".
"session:SurveillanceStation,DSM ".
"showPassInLog:1,0 ".
"showStmInfoFull:1,0 ".
"simu_SVSversion:7.2-xxxx,7.1-xxxx,8.0.0-xxxx,8.1.5-xxxx,8.2.0-xxxx ".
"webCmd ".
$readingFnAttributes;
return undef;
}
################################################################
sub SSCam_Define($@) {
# Die Define-Funktion eines Moduls wird von Fhem aufgerufen wenn der Define-Befehl für ein Gerät ausgeführt wird
# Welche und wie viele Parameter akzeptiert werden ist Sache dieser Funktion. Die Werte werden nach dem übergebenen Hash in ein Array aufgeteilt
# define CamCP1 SSCAM Carport 192.168.2.20 [5000]
# ($hash) [1] [2] [3] [4]
#
my ($hash, $def) = @_;
my $name = $hash->{NAME};
return "Error: Perl module ".$SScamMMDBI." is missing. Install it on Debian with: sudo apt-get install libjson-perl" if($SScamMMDBI);
my @a = split("[ \t][ \t]*", $def);
if(int(@a) < 4) {
return "You need to specify more parameters.\n". "Format: define SSCAM [Port]";
}
my $camname = $a[2];
my $serveraddr = $a[3];
my $serverport = $a[4] ? $a[4] : 5000;
my $proto = $a[5] ? lc($a[5]) : "http";
$hash->{SERVERADDR} = $serveraddr;
$hash->{SERVERPORT} = $serverport;
$hash->{CAMNAME} = $camname;
$hash->{VERSION} = $SSCamVersion;
$hash->{MODEL} = ($camname =~ m/^SVS$/i)?"SVS":"CAM"; # initial, CAM wird später ersetzt durch CamModel
$hash->{PROTOCOL} = $proto;
$hash->{COMPATIBILITY} = $compstat; # getestete SVS-version Kompatibilität
# benötigte API's in $hash einfügen
$hash->{HELPER}{APIINFO} = "SYNO.API.Info"; # Info-Seite für alle API's, einzige statische Seite !
$hash->{HELPER}{APIAUTH} = "SYNO.API.Auth"; # API used to perform session login and logout
$hash->{HELPER}{APISVSINFO} = "SYNO.SurveillanceStation.Info";
$hash->{HELPER}{APIEVENT} = "SYNO.SurveillanceStation.Event";
$hash->{HELPER}{APIEXTREC} = "SYNO.SurveillanceStation.ExternalRecording";
$hash->{HELPER}{APIEXTEVT} = "SYNO.SurveillanceStation.ExternalEvent";
$hash->{HELPER}{APICAM} = "SYNO.SurveillanceStation.Camera"; # stark geändert ab API v2.8
$hash->{HELPER}{APISNAPSHOT} = "SYNO.SurveillanceStation.SnapShot";
$hash->{HELPER}{APIPTZ} = "SYNO.SurveillanceStation.PTZ";
$hash->{HELPER}{APIPRESET} = "SYNO.SurveillanceStation.PTZ.Preset";
$hash->{HELPER}{APICAMEVENT} = "SYNO.SurveillanceStation.Camera.Event";
$hash->{HELPER}{APIVIDEOSTM} = "SYNO.SurveillanceStation.VideoStreaming"; # verwendet in Response von "SYNO.SurveillanceStation.Camera: GetLiveViewPath" -> StreamKey-Methode
# $hash->{HELPER}{APISTM} = "SYNO.SurveillanceStation.Streaming"; # provides methods to get Live View or Event video stream, removed in API v2.8
$hash->{HELPER}{APISTM} = "SYNO.SurveillanceStation.Stream"; # Beschreibung ist falsch und entspricht "SYNO.SurveillanceStation.Streaming" auch noch ab v2.8
$hash->{HELPER}{APIHM} = "SYNO.SurveillanceStation.HomeMode";
$hash->{HELPER}{APILOG} = "SYNO.SurveillanceStation.Log";
$hash->{HELPER}{APIAUDIOSTM} = "SYNO.SurveillanceStation.AudioStream"; # Audiostream mit SID, removed in API v2.8
$hash->{HELPER}{APIVIDEOSTMS} = "SYNO.SurveillanceStation.VideoStream"; # Videostream mit SID, removed in API v2.8
# Startwerte setzen
if(SSCam_IsModelCam($hash)) {
$attr{$name}{webCmd} = "on:off:snap:enable:disable:runView:stopView"; # initiale Webkommandos setzen
} else {
$attr{$name}{webCmd} = "homeMode";
$attr{$name}{webCmdLabel} = "HomeMode";
}
$hash->{HELPER}{ACTIVE} = "off"; # Funktionstoken "off", Funktionen können sofort starten
$hash->{HELPER}{OLDVALPOLLNOLOGGING} = "0"; # Loggingfunktion für Polling ist an
$hash->{HELPER}{OLDVALPOLL} = "0";
$hash->{HELPER}{RECTIME_DEF} = "15"; # Standard für rectime setzen, überschreibbar durch Attribut "rectime" bzw. beim "set .. on-for-time"
$hash->{HELPER}{OLDPTZHOME} = "";
$hash->{".ptzhtml"} = "";
$hash->{HELPER}{HLSSTREAM} = "inactive"; # Aktivitätsstatus HLS-Streaming
$hash->{HELPER}{SNAPLIMIT} = 0; # abgerufene Anzahl Snaps
$hash->{HELPER}{TOTALCNT} = 0; # totale Anzahl Snaps
readingsBeginUpdate($hash);
readingsBulkUpdate($hash,"PollState","Inactive"); # es ist keine Gerätepolling aktiv
if(SSCam_IsModelCam($hash)) {
readingsBulkUpdate($hash,"Availability", "???"); # Verfügbarkeit ist unbekannt
readingsBulkUpdate($hash,"state", "off"); # Init für "state" , Problemlösung für setstate, Forum #308
} else {
readingsBulkUpdate($hash,"state", "Initialized"); # Init für "state" wenn SVS
}
readingsEndUpdate($hash,1);
SSCam_getcredentials($hash,1); # Credentials lesen und in RAM laden ($boot=1)
# initiale Routinen nach Restart ausführen , verzögerter zufälliger Start
RemoveInternalTimer($hash, "SSCam_initonboot");
InternalTimer(gettimeofday()+int(rand(30)), "SSCam_initonboot", $hash, 0);
return undef;
}
################################################################
sub SSCam_Undef($$) {
my ($hash, $arg) = @_;
SSCam_logout($hash);
RemoveInternalTimer($hash);
return undef;
}
################################################################
sub SSCam_Delete($$) {
my ($hash, $arg) = @_;
my $index = $hash->{TYPE}."_".$hash->{NAME}."_credentials";
my $name = $hash->{NAME};
# gespeicherte Credentials löschen
setKeyValue($index, undef);
# löschen snapGallerie-Device falls vorhanden
my $sgdev = "SSCam.$hash->{NAME}.snapgallery";
CommandDelete($hash->{CL},"$sgdev");
# alle Streaming-Devices löschen falls vorhanden
CommandDelete($hash->{CL},"TYPE=SSCamSTRM:FILTER=PARENT=$name");
return undef;
}
################################################################
sub SSCam_Attr($$$$) {
my ($cmd,$name,$aName,$aVal) = @_;
my $hash = $defs{$name};
my ($do,$val);
# $cmd can be "del" or "set"
# $name is device name
# aName and aVal are Attribute name and value
# 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) {
$n = sprintf("%2.2d",$n);
addToDevAttrList($name, "ptzPanel_row$n");
}
addToDevAttrList($name, "ptzPanel_iconPrefix");
addToDevAttrList($name, "ptzPanel_iconPath");
}
if($aName =~ m/ptzPanel_row.*|ptzPanel_Home|ptzPanel_use/) {
InternalTimer(gettimeofday()+0.7, "SSCam_addptzattr", "$name", 0);
}
if ($aName eq "disable") {
if($cmd eq "set") {
$do = ($aVal) ? 1 : 0;
}
$do = 0 if($cmd eq "del");
if(SSCam_IsModelCam($hash)) {
$val = ($do == 1 ? "inactive" : "off");
} else {
$val = ($do == 1 ? "disabled" : "initialized");
}
readingsSingleUpdate($hash, "state", $val, 1);
readingsSingleUpdate($hash, "PollState", "Inactive", 1) if($do == 1);
readingsSingleUpdate($hash, "Availability", "???", 1) if($do == 1 && SSCam_IsModelCam($hash));
}
if ($aName eq "showStmInfoFull") {
if($cmd eq "set") {
$do = ($aVal) ? 1 : 0;
}
$do = 0 if($cmd eq "del");
if ($do == 0) {
delete($defs{$name}{READINGS}{StmKeymjpegHttp});
delete($defs{$name}{READINGS}{LiveStreamUrl});
delete($defs{$name}{READINGS}{StmKeyUnicst});
delete($defs{$name}{READINGS}{StmKeyUnicstOverHttp});
delete($defs{$name}{READINGS}{StmKeymxpegHttp});
}
}
if ($aName eq "snapGallerySize") {
if($cmd eq "set") {
$do = ($aVal eq "Icon")?1:2;
}
$do = 0 if($cmd eq "del");
if ($do == 0) {
delete($hash->{HELPER}{".SNAPHASH"}) if(AttrVal($name,"snapGalleryBoost",0)); # Snaphash nur löschen wenn Snaps gepollt werden
Log3($name, 4, "$name - Snapshot hash deleted");
} elsif (AttrVal($name,"snapGalleryBoost",0)) {
# snap-Infos abhängig ermitteln wenn gepollt werden soll
my ($slim,$ssize);
$hash->{HELPER}{GETSNAPGALLERY} = 1;
$slim = AttrVal($name,"snapGalleryNumber",$SSCam_slim); # Anzahl der abzurufenden Snaps
$ssize = $do;
RemoveInternalTimer("SSCam_getsnapinfo");
InternalTimer(gettimeofday()+0.7, "SSCam_getsnapinfo", "$name:$slim:$ssize", 0);
}
}
if ($aName eq "snapGalleryBoost") {
if($cmd eq "set") {
$do = ($aVal == 1)?1:0;
}
$do = 0 if($cmd eq "del");
if ($do == 0) {
delete($hash->{HELPER}{".SNAPHASH"}); # Snaphash löschen
Log3($name, 4, "$name - Snapshot hash deleted");
} else {
# snapgallery regelmäßig neu einlesen wenn Polling ein
return "When you want activate \"snapGalleryBoost\", you have to set the attribute \"pollcaminfoall\" first because the functionality depends on retrieving snapshots periodical."
if(!AttrVal($name,"pollcaminfoall",0));
my ($slim,$ssize);
$hash->{HELPER}{GETSNAPGALLERY} = 1;
$slim = AttrVal($name,"snapGalleryNumber",$SSCam_slim); # Anzahl der abzurufenden Snaps
my $sg = AttrVal($name,"snapGallerySize","Icon"); # Auflösung Image
$ssize = ($sg eq "Icon")?1:2;
RemoveInternalTimer("SSCam_getsnapinfo");
InternalTimer(gettimeofday()+0.7, "SSCam_getsnapinfo", "$name:$slim:$ssize", 0);
}
}
if ($aName eq "snapGalleryNumber" && AttrVal($name,"snapGalleryBoost",0)) {
my ($slim,$ssize);
if($cmd eq "set") {
$do = ($aVal != 0)?1:0;
}
$do = 0 if($cmd eq "del");
if ($do == 0) {
$slim = 3;
} else {
$slim = $aVal;
}
$hash->{HELPER}{GETSNAPGALLERY} = 1;
my $sg = AttrVal($name,"snapGallerySize","Icon"); # Auflösung Image
$ssize = ($sg eq "Icon")?1:2;
RemoveInternalTimer("SSCam_getsnapinfo");
InternalTimer(gettimeofday()+0.7, "SSCam_getsnapinfo", "$name:$slim:$ssize", 0);
}
if ($aName eq "simu_SVSversion") {
delete $hash->{HELPER}{APIPARSET};
delete $hash->{HELPER}{SID};
delete $hash->{CAMID};
RemoveInternalTimer($hash, "SSCam_getcaminfoall");
InternalTimer(gettimeofday()+0.5, "SSCam_getcaminfoall", $hash, 0);
}
if($aName =~ m/pollcaminfoall/ && $init_done == 1) {
RemoveInternalTimer($hash, "SSCam_getcaminfoall");
InternalTimer(gettimeofday()+1.0, "SSCam_getcaminfoall", $hash, 0);
RemoveInternalTimer($hash, "SSCam_wdpollcaminfo");
InternalTimer(gettimeofday()+1.5, "SSCam_wdpollcaminfo", $hash, 0);
}
if($aName =~ m/pollnologging/ && $init_done == 1) {
RemoveInternalTimer($hash, "SSCam_wdpollcaminfo");
InternalTimer(gettimeofday()+1.0, "SSCam_wdpollcaminfo", $hash, 0);
}
if ($cmd eq "set") {
if ($aName =~ m/httptimeout|snapGalleryColumns|rectime|pollcaminfoall/) {
unless ($aVal =~ /^\d+$/) { return " The Value for $aName is not valid. Use only figures 1-9 !";}
}
if($aName =~ m/pollcaminfoall/) {
return "The value of \"$aName\" has to be greater than 10 seconds." if($aVal <= 10);
}
}
if ($cmd eq "del") {
if ($aName =~ m/pollcaminfoall/ ) {
# Polling nicht ausschalten wenn snapGalleryBoost ein (regelmäßig neu einlesen)
return "Please switch off \"snapGalleryBoost\" first if you want to deactivate \"pollcaminfoall\" because the functionality of \"snapGalleryBoost\" depends on retrieving snapshots periodical."
if(AttrVal($name,"snapGalleryBoost",0));
}
}
return undef;
}
################################################################
sub SSCam_Set($@) {
my ($hash, @a) = @_;
return "\"set X\" needs at least an argument" if ( @a < 2 );
my $name = $a[0];
my $opt = $a[1];
my $prop = $a[2];
my $prop1 = $a[3];
my $prop2 = $a[4];
my $prop3 = $a[5];
my $camname = $hash->{CAMNAME};
my $success;
my $setlist;
my @prop;
return if(IsDisabled($name));
if(!$hash->{CREDENTIALS}) {
# initiale setlist für neue Devices
$setlist = "Unknown argument $opt, choose one of ".
"credentials "
;
} elsif(SSCam_IsModelCam($hash)) {
# selist für Cams
my $hlslfw = SSCam_IsHLSCap($hash)?",live_fw_hls,":",";
$setlist = "Unknown argument $opt, choose one of ".
"credentials ".
((ReadingsVal("$name", "CapPTZPan", "false") ne "false") ? "delPreset:".ReadingsVal("$name","Presets","")." " : "").
"expmode:auto,day,night ".
"on ".
"off:noArg ".
"motdetsc:disable,camera,SVS ".
"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 ".
((ReadingsVal("$name", "CapPTZPan", "false") ne "false") ? "createPTZcontrol:noArg ": "").
"enable:noArg ".
"disable:noArg ".
"optimizeParams ".
((ReadingsVal("$name", "CapPIR", "false") ne "false") ? "pirSensor:activate,deactivate ": "").
"runView:live_fw".$hlslfw."live_link,live_open,lastrec_fw,lastrec_fw_MJPEG,lastrec_fw_MPEG4/H.264,lastrec_open,lastsnap_fw ".
((ReadingsVal("$name", "CapPTZPan", "false") ne "false") ? "setPreset ": "").
((ReadingsVal("$name", "CapPTZPan", "false") ne "false") ? "setHome:---currentPosition---,".ReadingsVal("$name","Presets","")." " : "").
"stopView:noArg ".
((ReadingsVal("$name", "CapPTZObjTracking", "false") ne "false") ? "startTracking:noArg " : "").
((ReadingsVal("$name", "CapPTZObjTracking", "false") ne "false") ? "stopTracking:noArg " : "").
((ReadingsVal("$name", "CapPTZDirections", 0) > 0) ? "move"." " : "").
((ReadingsVal("$name", "CapPTZPan", "false") ne "false") ? "runPatrol:".ReadingsVal("$name", "Patrols", "")." " : "").
((ReadingsVal("$name", "CapPTZPan", "false") ne "false") ? "goPreset:".ReadingsVal("$name", "Presets", "")." " : "").
((ReadingsVal("$name", "CapPTZAbs", "false") ne "false") ? "goAbsPTZ"." " : "").
((ReadingsVal("$name", "CapPTZDirections", 0) > 0) ? "move"." " : "");
} else {
# setlist für SVS Devices
$setlist = "Unknown argument $opt, choose one of ".
"credentials ".
"extevent:1,2,3,4,5,6,7,8,9,10 ".
($hash->{HELPER}{APIHMMAXVER}?"homeMode:on,off ": "");
}
if ($opt eq "credentials") {
return "Credentials are incomplete, use username password" if (!$prop || !$prop1);
return "Password is too long. It is limited up to and including 20 characters." if (length $prop1 > 20);
delete $hash->{HELPER}{SID} if($hash->{HELPER}{SID});
($success) = SSCam_setcredentials($hash,$prop,$prop1);
$hash->{HELPER}{ACTIVE} = "off";
if($success) {
SSCam_getcaminfoall($hash,0);
RemoveInternalTimer($hash, "SSCam_getptzlistpreset");
InternalTimer(gettimeofday()+11, "SSCam_getptzlistpreset", $hash, 0);
RemoveInternalTimer($hash, "SSCam_getptzlistpatrol");
InternalTimer(gettimeofday()+12, "SSCam_getptzlistpatrol", $hash, 0);
return "Username and Password saved successfully";
} else {
return "Error while saving Username / Password - see logfile for details";
}
}
if ($opt eq "on" && 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 (defined($prop)) {
unless ($prop =~ /^\d+$/) { return " The Value for \"$opt\" is not valid. Use only figures 0-9 without decimal places !";}
$hash->{HELPER}{RECTIME_TEMP} = $prop;
}
SSCam_camstartrec($hash);
} elsif ($opt eq "off" && 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_camstoprec($hash);
} elsif ($opt eq "snap" && 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\"";}
$hash->{HELPER}{SNAPBYSTRMDEV} = 1 if ($prop); # $prop wird mitgegeben durch Snap by SSCamSTRM-Device
SSCam_camsnap($hash);
} elsif ($opt eq "startTracking" && 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 ($hash->{HELPER}{APIPTZMAXVER} < 5) {return "Function \"$opt\" needs a higher version of Surveillance Station";}
SSCam_starttrack($hash);
} elsif ($opt eq "stopTracking" && 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 ($hash->{HELPER}{APIPTZMAXVER} < 5) {return "Function \"$opt\" needs a higher version of Surveillance Station";}
SSCam_stoptrack($hash);
} elsif ($opt eq "snapGallery" && 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\"";}
my $ret = SSCam_getclhash($hash);
return $ret if($ret);
if(!AttrVal($name, "snapGalleryBoost",0)) {
# Snaphash ist nicht vorhanden und wird neu abgerufen und ausgegeben
$hash->{HELPER}{GETSNAPGALLERY} = 1;
# snap-Infos für Gallerie abrufen
my ($sg,$slim,$ssize);
$slim = $prop?AttrVal($name,"snapGalleryNumber",$prop):AttrVal($name,"snapGalleryNumber",$SSCam_slim); # Anzahl der abzurufenden Snapshots
$ssize = (AttrVal($name,"snapGallerySize","Icon") eq "Icon")?1:2; # Image Size 1-Icon, 2-Full
SSCam_getsnapinfo("$name:$slim:$ssize");
} else {
# Snaphash ist vorhanden und wird zur Ausgabe aufbereitet (Polling ist aktiv)
my $htmlCode = SSCam_composegallery($name);
for (my $k=1; (defined($hash->{HELPER}{CL}{$k})); $k++ ) {
if ($hash->{HELPER}{CL}{$k}->{COMP}) {
# CL zusammengestellt (Auslösung durch Notify)
asyncOutput($hash->{HELPER}{CL}{$k}, "$htmlCode");
} else {
# Output wurde über FHEMWEB ausgelöst
return $htmlCode;
}
}
delete($hash->{HELPER}{CL});
}
} elsif ($opt eq "createSnapGallery" && 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\"";}
my ($ret,$sgdev);
return "Before use \"$opt\" you have to set the attribute \"snapGalleryBoost\" first due to the technology of retrieving snapshots automatically is needed."
if(!AttrVal($name,"snapGalleryBoost",0));
$sgdev = "SSCamSTRM.$name.snapgallery";
$ret = CommandDefine($hash->{CL},"$sgdev SSCamSTRM {SSCam_composegallery('$name','$sgdev','snapgallery')}");
return $ret if($ret);
my $room = "SnapGallery";
$attr{$sgdev}{room} = $room;
return "Snapgallery device \"$sgdev\" created and assigned to room \"$room\".";
} elsif ($opt eq "createPTZcontrol" && 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\"";}
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");
$attr{$ptzcdev}{room} = $room;
$attr{$ptzcdev}{group} = $name."_PTZcontrol";
return "PTZ control device \"$ptzcdev\" created and assigned to room \"$room\".";
} elsif ($opt eq "createStreamDev" && 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\"";}
my ($livedev,$ret);
if($prop =~ /mjpeg/) {
$livedev = "SSCamSTRM.$name.mjpeg";
$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')}");
return $ret if($ret);
}
my $room = AttrVal($name,"room","Livestream");
$attr{$livedev}{room} = $room;
return "Livestream device \"$livedev\" created and assigned to room \"$room\".";
} elsif ($opt eq "enable" && 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_camenable($hash);
} elsif ($opt eq "disable" && 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_camdisable($hash);
} elsif ($opt eq "motdetsc" && 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 || $prop !~ /^(disable|camera|SVS)$/) { return " \"$opt\" needs one of those arguments: disable, camera, SVS !";}
$hash->{HELPER}{MOTDETSC} = $prop;
if ($prop1) {
# check ob Zahl zwischen 1 und 99
return "invalid value for sensitivity (SVS or camera) - use number between 1 - 99" if ($prop1 !~ /^([1-9]|[1-9][0-9])*$/);
$hash->{HELPER}{MOTDETSC_PROP1} = $prop1;
}
if ($prop2) {
# check ob Zahl zwischen 1 und 99
return "invalid value for threshold (SVS) / object size (camera) - use number between 1 - 99" if ($prop2 !~ /^([1-9]|[1-9][0-9])*$/);
$hash->{HELPER}{MOTDETSC_PROP2} = $prop2;
}
if ($prop3) {
# check ob Zahl zwischen 1 und 99
return "invalid value for threshold (SVS) / object size (camera) - use number between 1 - 99" if ($prop3 !~ /^([1-9]|[1-9][0-9])*$/);
$hash->{HELPER}{MOTDETSC_PROP3} = $prop3;
}
SSCam_cammotdetsc($hash);
} elsif ($opt eq "expmode" && 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\"";}
unless ($prop) { return " \"$opt\" needs one of those arguments: auto, day, night !";}
$hash->{HELPER}{EXPMODE} = $prop;
SSCam_camexpmode($hash);
} elsif ($opt eq "homeMode" && !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\"";}
unless ($prop) { return " \"$opt\" needs one of those arguments: on, off !";}
$hash->{HELPER}{HOMEMODE} = $prop;
SSCam_sethomemode($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";}
$hash->{HELPER}{GOPRESETNAME} = $prop;
$hash->{HELPER}{PTZACTION} = "gopreset";
SSCam_doptzaction($hash);
} elsif ($opt eq "optimizeParams" && 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\"";}
my %cpcl = (ntp => 1, mirror => 2, flip => 4, rotate => 8);
SSCam_extoptpar($hash,$prop,\%cpcl) if($prop);
SSCam_extoptpar($hash,$prop1,\%cpcl) if($prop1);
SSCam_extoptpar($hash,$prop2,\%cpcl) if($prop2);
SSCam_setoptpar($hash);
} elsif ($opt eq "pirSensor" && 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(ReadingsVal("$name", "CapPIR", "false") eq "false") {return "Function \"$opt\" not possible. Camera \"$name\" don't have a PIR sensor."}
if(!$prop) {return "Function \"$opt\" needs an argument";}
$hash->{HELPER}{PIRACT} = ($prop eq "activate")?0:($prop eq "deactivate")?-1:5;
if($hash->{HELPER}{PIRACT} == 5) {return " Illegal argument for \"$opt\" detected, use \"activate\" or \"activate\" !";}
SSCam_piract($hash);
} elsif ($opt eq "runPatrol" && 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 \"$opt\" needs a \"Patrolname\" as an argument";}
$hash->{HELPER}{GOPATROLNAME} = $prop;
$hash->{HELPER}{PTZACTION} = "runpatrol";
SSCam_doptzaction($hash);
} elsif ($opt eq "goAbsPTZ" && 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 eq "up" || $prop eq "down" || $prop eq "left" || $prop eq "right") {
if ($prop eq "up") {$hash->{HELPER}{GOPTZPOSX} = 320; $hash->{HELPER}{GOPTZPOSY} = 480;}
if ($prop eq "down") {$hash->{HELPER}{GOPTZPOSX} = 320; $hash->{HELPER}{GOPTZPOSY} = 0;}
if ($prop eq "left") {$hash->{HELPER}{GOPTZPOSX} = 0; $hash->{HELPER}{GOPTZPOSY} = 240;}
if ($prop eq "right") {$hash->{HELPER}{GOPTZPOSX} = 640; $hash->{HELPER}{GOPTZPOSY} = 240;}
$hash->{HELPER}{PTZACTION} = "goabsptz";
SSCam_doptzaction($hash);
return undef;
} else {
if ($prop !~ /\d+/ || $prop1 !~ /\d+/ || abs($prop) > 640 || abs($prop1) > 480) {
return "Function \"goAbsPTZ\" needs two coordinates, posX=0-640 and posY=0-480, as arguments or use up, down, left, right instead";
}
$hash->{HELPER}{GOPTZPOSX} = abs($prop);
$hash->{HELPER}{GOPTZPOSY} = abs($prop1);
$hash->{HELPER}{PTZACTION} = "goabsptz";
SSCam_doptzaction($hash);
return undef;
}
return "Function \"goAbsPTZ\" needs two coordinates, posX=0-640 and posY=0-480, as arguments or use up, down, left, right instead";
} elsif ($opt eq "move" && 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\"";}
return "PTZ version of Synology API isn't set. Use \"get $name scanVirgin\" first." if(!$hash->{HELPER}{APIPTZMAXVER});
if($hash->{HELPER}{APIPTZMAXVER} <= 4) {
if (!defined($prop) || ($prop !~ /^up$|^down$|^left$|^right$|^dir_\d$/)) {return "Function \"move\" needs an argument like up, down, left, right or dir_X (X = 0 to CapPTZDirections-1)";}
$hash->{HELPER}{GOMOVEDIR} = $prop;
} elsif ($hash->{HELPER}{APIPTZMAXVER} >= 5) {
if (!defined($prop) || ($prop !~ /^right$|^upright$|^up$|^upleft$|^left$|^downleft$|^down$|^downright$/)) {return "Function \"move\" needs an argument like right, upright, up, upleft, left, downleft, down, downright ";}
my %dirs = (
right => 0,
upright => 4,
up => 8,
upleft => 12,
left => 16,
downleft => 20,
down => 24,
downright => 28,
);
$hash->{HELPER}{GOMOVEDIR} = $dirs{$prop};
}
$hash->{HELPER}{GOMOVETIME} = defined($prop1) ? $prop1 : 1;
$hash->{HELPER}{PTZACTION} = "movestart";
SSCam_doptzaction($hash);
} elsif ($opt eq "runView" && 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 eq "live_open") {
if ($prop1) {$hash->{HELPER}{VIEWOPENROOM} = $prop1;} else {delete $hash->{HELPER}{VIEWOPENROOM};}
$hash->{HELPER}{OPENWINDOW} = 1;
$hash->{HELPER}{WLTYPE} = "link";
$hash->{HELPER}{ALIAS} = "LiveView";
$hash->{HELPER}{RUNVIEW} = "live_open";
$hash->{HELPER}{ACTSTRM} = ""; # sprechender Name des laufenden Streamtyps für SSCamSTRM
} elsif ($prop eq "live_link") {
$hash->{HELPER}{OPENWINDOW} = 0;
$hash->{HELPER}{WLTYPE} = "link";
$hash->{HELPER}{ALIAS} = "LiveView";
$hash->{HELPER}{RUNVIEW} = "live_link";
$hash->{HELPER}{ACTSTRM} = ""; # sprechender Name des laufenden Streamtyps für SSCamSTRM
} elsif ($prop eq "lastrec_open") {
if ($prop1) {$hash->{HELPER}{VIEWOPENROOM} = $prop1;} else {delete $hash->{HELPER}{VIEWOPENROOM};}
$hash->{HELPER}{OPENWINDOW} = 1;
$hash->{HELPER}{WLTYPE} = "link";
$hash->{HELPER}{ALIAS} = "LastRecording";
$hash->{HELPER}{RUNVIEW} = "lastrec_open";
$hash->{HELPER}{ACTSTRM} = ""; # sprechender Name des laufenden Streamtyps für SSCamSTRM
} elsif ($prop eq "lastrec_fw") { # Video in iFrame eingebettet
$hash->{HELPER}{OPENWINDOW} = 0;
$hash->{HELPER}{WLTYPE} = "iframe";
$hash->{HELPER}{ALIAS} = " ";
$hash->{HELPER}{RUNVIEW} = "lastrec";
$hash->{HELPER}{ACTSTRM} = "last Recording"; # sprechender Name des laufenden Streamtyps für SSCamSTRM
} elsif ($prop eq "lastrec_fw_MJPEG") { # “video/avi” – MJPEG format event
$hash->{HELPER}{OPENWINDOW} = 0;
$hash->{HELPER}{WLTYPE} = "image";
$hash->{HELPER}{ALIAS} = " ";
$hash->{HELPER}{RUNVIEW} = "lastrec";
$hash->{HELPER}{ACTSTRM} = "last Recording"; # sprechender Name des laufenden Streamtyps für SSCamSTRM
} elsif ($prop eq "lastrec_fw_MPEG4/H.264") { # “video/mp4” – MPEG4/H.264 format event
$hash->{HELPER}{OPENWINDOW} = 0;
$hash->{HELPER}{WLTYPE} = "video";
$hash->{HELPER}{ALIAS} = " ";
$hash->{HELPER}{RUNVIEW} = "lastrec";
$hash->{HELPER}{ACTSTRM} = "last Recording"; # sprechender Name des laufenden Streamtyps für SSCamSTRM
} elsif ($prop eq "live_fw") {
$hash->{HELPER}{OPENWINDOW} = 0;
$hash->{HELPER}{WLTYPE} = "image";
$hash->{HELPER}{ALIAS} = " ";
$hash->{HELPER}{RUNVIEW} = "live_fw";
$hash->{HELPER}{ACTSTRM} = "MJPEG Livestream"; # sprechender Name des laufenden Streamtyps für SSCamSTRM
} elsif ($prop eq "live_fw_hls") {
return "API \"SYNO.SurveillanceStation.VideoStream\" is not available or Reading \"CamStreamFormat\" is not \"HLS\". May be your API version is 2.8 or higher." if(!SSCam_IsHLSCap($hash));
$hash->{HELPER}{OPENWINDOW} = 0;
$hash->{HELPER}{WLTYPE} = "hls";
$hash->{HELPER}{ALIAS} = "View only on compatible browsers";
$hash->{HELPER}{RUNVIEW} = "live_fw_hls";
$hash->{HELPER}{ACTSTRM} = "HLS Livestream"; # sprechender Name des laufenden Streamtyps für SSCamSTRM
} elsif ($prop eq "lastsnap_fw") {
$hash->{HELPER}{LSNAPBYSTRMDEV} = 1 if($prop1); # Anzeige durch SSCamSTRM-Device ausgelöst
$hash->{HELPER}{LSNAPBYDEV} = 1 if(!$prop1); # Anzeige durch SSCam ausgelöst
$hash->{HELPER}{OPENWINDOW} = 0;
$hash->{HELPER}{WLTYPE} = "base64img";
$hash->{HELPER}{ALIAS} = " ";
$hash->{HELPER}{RUNVIEW} = "lastsnap_fw";
$hash->{HELPER}{ACTSTRM} = "last Snapshot"; # sprechender Name des laufenden Streamtyps für SSCamSTRM
} else {
return "$prop isn't a valid option of runview, use one of live_fw, live_link, live_open, lastrec_fw, lastrec_open, lastsnap_fw";
}
SSCam_runliveview($hash);
} elsif ($opt eq "hlsreactivate" && SSCam_IsModelCam($hash)) {
# ohne SET-Menüeintrag
if (!$hash->{CREDENTIALS}) {return "Credentials of $name are not set - make sure you've set it with \"set $name credentials username password\"";}
SSCam_hlsreactivate($hash);
} elsif ($opt eq "hlsactivate" && SSCam_IsModelCam($hash)) {
# ohne SET-Menüeintrag
if (!$hash->{CREDENTIALS}) {return "Credentials of $name are not set - make sure you've set it with \"set $name credentials username password\"";}
SSCam_hlsactivate($hash);
} elsif ($opt eq "refresh" && SSCam_IsModelCam($hash)) {
# ohne SET-Menüeintrag
if($prop =~ /STRM/) {
# Event in allen SSCamSTRM-Devices erzeugen um Contentwiedergabe aufzufrischen
SSCam_refresh($hash,0,0,1); # kein Room-Refresh, kein SSCam-state-Event, SSCamSTRM-Event
}
} elsif ($opt eq "extevent" && !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\"";}
$hash->{HELPER}{EVENTID} = $prop;
SSCam_extevent($hash);
} elsif ($opt eq "stopView" && 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_stopliveview($hash);
} elsif ($opt eq "setPreset" && 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 "Syntax of function \"$opt\" was wrong. Please use \"set $name setPreset []\" ";}
$hash->{HELPER}{PNUMBER} = $prop;
$hash->{HELPER}{PNAME} = $prop1?$prop1:$prop; # wenn keine Presetname angegeben -> Presetnummer als Name verwenden
$hash->{HELPER}{PSPEED} = $prop2 if($prop2);
SSCam_setPreset($hash);
} elsif ($opt eq "setHome" && 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 \"$opt\" needs a \"Presetname\" as argument";}
$hash->{HELPER}{SETHOME} = $prop;
SSCam_setHome($hash);
} elsif ($opt eq "delPreset" && 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 \"$opt\" needs a \"Presetname\" as argument";}
$hash->{HELPER}{DELPRESETNAME} = $prop;
SSCam_delPreset($hash);
} else {
return "$setlist";
}
return;
}
################################################################
sub SSCam_Get($@) {
my ($hash, @a) = @_;
return "\"get X\" needs at least an argument" if ( @a < 2 );
my $name = shift @a;
my $opt = shift @a;
my $arg = shift @a;
my $arg1 = shift @a;
my $arg2 = shift @a;
my $ret = "";
my $getlist;
if(!$hash->{CREDENTIALS}) {
return;
} elsif(SSCam_IsModelCam($hash)) {
# getlist für Cams
$getlist = "Unknown argument $opt, choose one of ".
"caminfoall:noArg ".
"caminfo:noArg ".
((AttrVal($name,"snapGalleryNumber",undef) || AttrVal($name,"snapGalleryBoost",0))
?"snapGallery:noArg ":"snapGallery:$SSCAM_snum ").
((ReadingsVal("$name", "CapPTZPresetNumber", 0) != 0) ? "listPresets:noArg " : "").
"snapinfo:noArg ".
"svsinfo:noArg ".
"snapfileinfo:noArg ".
"eventlist:noArg ".
"stmUrlPath:noArg ".
"storedCredentials:noArg ".
"scanVirgin:noArg "
;
} else {
# getlist für SVS Devices
$getlist = "Unknown argument $opt, choose one of ".
"caminfoall:noArg ".
($hash->{HELPER}{APIHMMAXVER}?"homeModeState:noArg ": "").
"svsinfo:noArg ".
"listLog ".
"storedCredentials:noArg ".
"scanVirgin:noArg "
;
}
return if(IsDisabled($name));
if ($opt eq "caminfo") {
# "1" ist Statusbit für manuelle Abfrage, kein Einstieg in Pollingroutine
if (!$hash->{CREDENTIALS}) {return "Credentials of $name are not set - make sure you've set it with \"set $name credentials username password\"";}
SSCam_getcaminfo($hash);
} elsif ($opt eq "caminfoall") {
# "1" ist Statusbit für manuelle Abfrage, kein Einstieg in Pollingroutine
if (!$hash->{CREDENTIALS}) {return "Credentials of $name are not set - make sure you've set it with \"set $name credentials username password\"";}
SSCam_getcaminfoall($hash,1);
} elsif ($opt eq "homeModeState" && !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_gethomemodestate($hash);
} elsif ($opt eq "listLog" && !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\"";}
# übergebenen CL-Hash (FHEMWEB) in Helper eintragen
SSCam_getclhash($hash,1);
SSCam_extlogargs($hash,$arg) if($arg);
SSCam_extlogargs($hash,$arg1) if($arg1);
SSCam_extlogargs($hash,$arg2) if($arg2);
SSCam_getsvslog($hash);
} elsif ($opt eq "listPresets" && 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\"";}
# übergebenen CL-Hash (FHEMWEB) in Helper eintragen
SSCam_getclhash($hash,1);
SSCam_getpresets($hash);
} elsif ($opt eq "svsinfo") {
if (!$hash->{CREDENTIALS}) {return "Credentials of $name are not set - make sure you've set it with \"set $name credentials username password\"";}
SSCam_getsvsinfo($hash);
} elsif ($opt eq "storedCredentials") {
if (!$hash->{CREDENTIALS}) {return "Credentials of $name are not set - make sure you've set it with \"set $name credentials username password\"";}
# Credentials abrufen
my ($success, $username, $password) = SSCam_getcredentials($hash,0);
unless ($success) {return "Credentials couldn't be retrieved successfully - see logfile"};
return "Stored Credentials for $name - Username: $username, Password: $password";
} elsif ($opt eq "snapGallery" && 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\"";}
my $txt = SSCam_getclhash($hash);
return $txt if($txt);
if(!AttrVal($name, "snapGalleryBoost",0)) {
# Snaphash ist nicht vorhanden und wird abgerufen
$hash->{HELPER}{GETSNAPGALLERY} = 1;
# snap-Infos für Gallerie abrufen
my ($sg,$slim,$ssize);
$slim = $arg?AttrVal($name,"snapGalleryNumber",$arg):AttrVal($name,"snapGalleryNumber",$SSCam_slim); # Anzahl der abzurufenden Snapshots
$ssize = (AttrVal($name,"snapGallerySize","Icon") eq "Icon")?1:2; # Image Size 1-Icon, 2-Full
SSCam_getsnapinfo("$name:$slim:$ssize");
} else {
# Snaphash ist vorhanden und wird zur Ausgabe aufbereitet
my $htmlCode = SSCam_composegallery($name);
for (my $k=1; (defined($hash->{HELPER}{CL}{$k})); $k++ ) {
if ($hash->{HELPER}{CL}{$k}->{COMP}) {
# CL zusammengestellt (Auslösung durch Notify)
asyncOutput($hash->{HELPER}{CL}{$k}, "$htmlCode");
} else {
# Output wurde über FHEMWEB ausgelöst
return $htmlCode;
}
}
delete($hash->{HELPER}{CL});
}
} elsif ($opt eq "snapinfo" && SSCam_IsModelCam($hash)) {
# Schnappschußgalerie abrufen (snapGalleryBoost) oder nur Info des letzten Snaps
if (!$hash->{CREDENTIALS}) {return "Credentials of $name are not set - make sure you've set it with \"set $name credentials username password\"";}
my ($slim,$ssize) = SSCam_snaplimsize($hash);
SSCam_getsnapinfo("$name:$slim:$ssize");
} elsif ($opt eq "snapfileinfo" && 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 (!ReadingsVal("$name", "LastSnapId", undef)) {return "Reading LastSnapId is empty - please take a snapshot before !"}
SSCam_getsnapfilename($hash);
} elsif ($opt eq "eventlist" && 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_geteventlist ($hash);
} elsif ($opt eq "stmUrlPath" && 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_getStmUrlPath ($hash);
} elsif ($opt eq "scanVirgin") {
if (!$hash->{CREDENTIALS}) {return "Credentials of $name are not set - make sure you've set it with \"set $name credentials username password\"";}
SSCam_sessionoff($hash);
delete $hash->{HELPER}{APIPARSET};
delete $hash->{CAMID};
# alte Readings außer state löschen
my @allrds = keys%{$defs{$name}{READINGS}};
foreach my $key(@allrds) {
# Log3 ($name, 1, "DbRep $name - Reading Schlüssel: $key");
delete($defs{$name}{READINGS}{$key}) if($key ne "state");
}
# "1" ist Statusbit für manuelle Abfrage, kein Einstieg in Pollingroutine
SSCam_getcaminfoall($hash,1);
} else {
return "$getlist";
}
return $ret; # not generate trigger out of command
}
######################################################################################
# Kamera Liveview Anzeige in FHEMWEB
######################################################################################
# wird von FW aufgerufen. $FW_wname = aufrufende Webinstanz, $d = aufrufendes
# Device (z.B. CamCP1)
sub SSCam_FWsummaryFn ($$$$) {
my ($FW_wname, $d, $room, $pageHash) = @_; # pageHash is set for summaryFn in FHEMWEB
my $hash = $defs{$d};
my $name = $hash->{NAME};
my $link = $hash->{HELPER}{LINK};
my $wltype = $hash->{HELPER}{WLTYPE};
my $ret;
my $alias;
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 .= "";
}
} elsif($wltype eq "iframe") {
$ret = "";
$ret .= " ";
$ret .= "$imgstop ";
if($hash->{HELPER}{AUDIOLINK} && ReadingsVal($d, "CamAudioType", "Unknown") !~ /Unknown/) {
$ret .= "";
}
} elsif($wltype eq "embed") {
$ret = "