diff --git a/fhem/contrib/DS_Starter/49_SSCam.pm b/fhem/contrib/DS_Starter/49_SSCam.pm index 3b4e94f14..d3dbf0491 100644 --- a/fhem/contrib/DS_Starter/49_SSCam.pm +++ b/fhem/contrib/DS_Starter/49_SSCam.pm @@ -1,9 +1,9 @@ ######################################################################################################################## -# $Id: 49_SSCam.pm 17956 2018-12-11 19:34:15Z DS_Starter $ +# $Id: 49_SSCam.pm 18006 2018-12-19 20:52:15Z DS_Starter $ ######################################################################################################################### # 49_SSCam.pm # -# (c) 2015-2018 by Heiko Maaz +# (c) 2015-2019 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. @@ -41,10 +41,15 @@ use Data::Dumper; # Perl Core mo use MIME::Base64; use Time::HiRes; use HttpUtils; +use Blocking; # für EMail-Versand +use Encode; # no if $] >= 5.017011, warnings => 'experimental'; # Versions History intern our %SSCam_vNotesIntern = ( + "8.2.0" => "02.01.2019 store SMTP credentials with \"smtpcredentials\", SMTP Email integrated ", + "8.1.0" => "19.12.2018 tooltipps in camera device for control buttons, commandref revised ", + "8.0.0" => "13.12.2018 HLS with sscam_hls.js integrated for SSCamSTRM type hls, realize tooltipps in streaming devices, minor fixes", "7.7.1" => "12.12.2018 change autocreateCams: define new device only if ne device with Internal CAMNAME is defined, ". "fix getsnapinfo function get wrong snapid or none if cam is new defined ", "7.7.0" => "10.12.2018 SVS-Device: autocreateCams command added, some other fixes and improvements, minor code rewrite, ". @@ -101,6 +106,9 @@ our %SSCam_vNotesIntern = ( # Versions History extern our %SSCam_vNotesExtern = ( + "8.1.0" => "19.12.2018 Tooltipps added to camera device control buttons.", + "8.0.0" => "18.12.2018 HLS is integrated using sscam_hls.js in Streaming device types \"hls\". HLS streaming is now available ". + "for all common used browser types. Tooltipps are added to streaming devices and snapgallery.", "7.7.0" => "10.12.2018 autocreateCams command added to SVS device. By this command all cameras installed in SVS can be ". "defined automatically.
". "In SSCamSTRM devices the \"set <name> popupStream\" command is implemented which may open a popup window with the ". @@ -277,9 +285,40 @@ my %SSCam_errlist = ( 600 => "Presetname and PresetID not found in Hash", ); +# Tooltipps Textbausteine (http://www.walterzorn.de/tooltip/tooltip.htm#download), §NAME§ wird durch Kameranamen ersetzt +our %SSCam_ttips_en = ( + ttrefresh => "The playback of streaming content of camera of "§NAME§" will be restartet.", + ttrecstart => "Start an endless recording of camera "§NAME§".
You have to stop the recording manually.", + ttrecstop => "Stopp the recording of camera "§NAME§".", + ttsnap => "Take a snapshot of camera "§NAME§".", + ttcmdstop => "Stopp playback of camera "§NAME§"", + tthlsreact => "Reactivate HTTP Livestreaming Interface of camera "§NAME§".
The camera is enforced to restart HLS transmission.", + ttmjpegrun => "Playback the MJPEG Livestream of camera "§NAME§".", + tthlsrun => "Playback the native HTTP Livestream of camera "§NAME§".", + ttlrrun => "Playback of last recording of camera "§NAME§" in an iFrame.
Both MJPEG and H.264 recordings are rendered.", + tth264run => "Playback of last H.264 recording of camera "§NAME§".
It only starts if the recording is type H.264", + ttlmjpegrun => "Playback of last MJPEG recording of camera "§NAME§".
It only starts if the recording is type MJPEG", + ttlsnaprun => "Playback of last snapshot of camera "§NAME§".", +); + +our %SSCam_ttips_de = ( + ttrefresh => "Die Wiedergabe des Streams von Kamera "§NAME§" wird neu gestartet.", + ttrecstart => "Startet eine Endlosaufnahme von Kamera "§NAME§".
Die Aufnahme muß manuell gestoppt werden.", + ttrecstop => "Stoppt die laufende Aufnahme von Kamera "§NAME§".", + ttsnap => "Ein Schnappschuß von Kamera "§NAME§" wird aufgenommen.", + ttcmdstop => "Stopp Wiedergabe von Kamera "§NAME§"", + tthlsreact => "Reaktiviert das HTTP Livestreaming Interface von Kamera "§NAME§".
Die Kamera wird aufgefordert die HLS Übertragung zu restarten.", + ttmjpegrun => "Wiedergabe des MJPEG Livestreams von Kamera "§NAME§"", + tthlsrun => "Wiedergabe des HTTP Livestreams von Kamera "§NAME§".
Es wird die HLS Funktion der Synology Surveillance Station verwendet.", + ttlrrun => "Wiedergabe der letzten Aufnahme von Kamera "§NAME§" in einem iFrame.
Es werden sowohl MJPEG als auch H.264 Aufnahmen wiedergegeben.", + tth264run => "Wiedergabe der letzten H.264 Aufnahme von Kamera "§NAME§".
Die Wiedergabe startet nur wenn die Aufnahme vom Typ H.264 ist.", + ttlmjpegrun => "Wiedergabe der letzten MJPEG Aufnahme von Kamera "§NAME§".
Die Wiedergabe startet nur wenn die Aufnahme vom Typ MJPEG ist.", + ttlsnaprun => "Wiedergabe des letzten Schnappschusses von Kamera "§NAME§".", +); + # 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 +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 @@ -288,6 +327,7 @@ use vars qw($FW_detail); # currently selected device for detail view use vars qw($FW_wname); # Web instance sub FW_pH(@); # add href +################################################################ sub SSCam_Initialize($) { my ($hash) = @_; $hash->{DefFn} = "SSCam_Define"; @@ -304,12 +344,22 @@ sub SSCam_Initialize($) { $hash->{AttrList} = "disable:1,0 ". "genericStrmHtmlTag ". + "hlsNetScript:1,0 ". + "hlsStrmObject ". "httptimeout ". "htmlattr ". "livestreamprefix ". "loginRetries:1,2,3,4,5,6,7,8,9,10 ". "videofolderMap ". "pollcaminfoall ". + "smtpCc ". + "smtpDebug:1,0 ". + "smtpFrom ". + "smtpHost ". + "smtpPort ". + "smtpTo ". + "smtpNoUseSSL:1,0 ". + "snapEmailTxt ". "snapGalleryBoost:0,1 ". "snapGallerySize:Icon,Full ". "snapGalleryNumber:$SSCAM_snum ". @@ -399,7 +449,7 @@ sub SSCam_Define($@) { $hash->{HELPER}{TOTALCNT} = 0; # totale Anzahl Snaps readingsBeginUpdate($hash); - readingsBulkUpdate($hash,"PollState","Inactive"); # es ist keine Gerätepolling aktiv + 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 @@ -408,7 +458,8 @@ sub SSCam_Define($@) { } readingsEndUpdate($hash,1); - SSCam_getcredentials($hash,1); # Credentials lesen und in RAM laden ($boot=1) + SSCam_getcredentials($hash,1,"svs"); # Credentials lesen und in RAM laden ($boot=1) + SSCam_getcredentials($hash,1,"smtp"); # initiale Routinen nach Restart ausführen , verzögerter zufälliger Start RemoveInternalTimer($hash, "SSCam_initonboot"); @@ -419,9 +470,10 @@ return undef; ################################################################ sub SSCam_Undef($$) { - my ($hash, $arg) = @_; - SSCam_logout($hash); - RemoveInternalTimer($hash); + my ($hash, $arg) = @_; + SSCam_logout($hash); + RemoveInternalTimer($hash); + return undef; } @@ -454,6 +506,10 @@ sub SSCam_Attr($$$$) { # $name is device name # aName and aVal are Attribute name and value + if ($aName =~ /hlsNetScript/ && SSCam_IsModelCam($hash)) { + return " The attribute \"$aName\" is only valid for devices of type \"SVS\"! Please set this attribute in a device of this type."; + } + # 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) { @@ -631,6 +687,7 @@ sub SSCam_Set($@) { my $hlslfw = SSCam_IsHLSCap($hash)?",live_fw_hls,":","; $setlist = "Unknown argument $opt, choose one of ". "credentials ". + "smtpcredentials ". ((ReadingsVal("$name", "CapPTZPan", "false") ne "false") ? "delPreset:".ReadingsVal("$name","Presets","")." " : ""). "expmode:auto,day,night ". "on ". @@ -639,7 +696,7 @@ sub SSCam_Set($@) { "snap:noArg ". (AttrVal($name, "snapGalleryBoost",0)?(AttrVal($name,"snapGalleryNumber",undef) || AttrVal($name,"snapGalleryBoost",0))?"snapGallery:noArg ":"snapGallery:$SSCAM_snum ":" "). "createSnapGallery:noArg ". - "createStreamDev:generic,mjpeg,switched ". + "createStreamDev:generic,hls,mjpeg,switched ". ((ReadingsVal("$name", "CapPTZPan", "false") ne "false") ? "createPTZcontrol:noArg ": ""). "enable:noArg ". "disable:noArg ". @@ -671,7 +728,7 @@ sub SSCam_Set($@) { 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); + ($success) = SSCam_setcredentials($hash,"svs",$prop,$prop1); $hash->{HELPER}{ACTIVE} = "off"; if($success) { @@ -688,6 +745,17 @@ sub SSCam_Set($@) { } + if ($opt eq "smtpcredentials") { + return "Credentials are incomplete, use username password" if (!$prop || !$prop1); + ($success) = SSCam_setcredentials($hash,"smtp",$prop,$prop1); + + if($success) { + return "SMTP-Username and SMTP-Password saved successfully"; + } else { + return "Error while saving SMTP-Username / SMTP-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)) { @@ -702,9 +770,19 @@ sub SSCam_Set($@) { } 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 + $hash->{HELPER}{SNAPBYSTRMDEV} = 1 if ($prop =~ /STRM/); # $prop wird mitgegeben durch Snap by SSCamSTRM-Device + + if (AttrVal($name, "snapEmailTxt", "")) { + # Snap soll nach Erstellung per Email versendet werden + # snapEmailTxt muss sein: subject => , body => + if (!$hash->{CREDENTIALS}) {return "Credentials of $name are not set - make sure you've set it with \"set $name credentials username password\"";} + if (!$hash->{SMTPCREDENTIALS}) { + return "Due to attribute \"snapEmailTxt\" is set, you want to send snapshots by email but SMTP credentials are not set - make sure you've set credentials with \"set $name smtpcredentials username password\""; + } + } + 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";} @@ -754,7 +832,7 @@ sub SSCam_Set($@) { $sgdev = "SSCamSTRM.$name.snapgallery"; $ret = CommandDefine($hash->{CL},"$sgdev SSCamSTRM {SSCam_composegallery('$name','$sgdev','snapgallery')}"); return $ret if($ret); - my $room = "SnapGallery"; + my $room = "SSCam"; $attr{$sgdev}{room} = $room; return "Snapgallery device \"$sgdev\" created and assigned to room \"$room\"."; @@ -763,7 +841,7 @@ sub SSCam_Set($@) { 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"); + my $room = AttrVal($name,"room","SSCam"); $attr{$ptzcdev}{room} = $room; $attr{$ptzcdev}{group} = $name."_PTZcontrol"; return "PTZ control device \"$ptzcdev\" created and assigned to room \"$room\"."; @@ -781,6 +859,13 @@ sub SSCam_Set($@) { $livedev = "SSCamSTRM.$name.generic"; $ret = CommandDefine($hash->{CL},"$livedev SSCamSTRM {SSCam_StreamDev('$name','$livedev','generic')}"); return $ret if($ret); + } + if($prop =~ /hls/) { + $livedev = "SSCamSTRM.$name.hls"; + $ret = CommandDefine($hash->{CL},"$livedev SSCamSTRM {SSCam_StreamDev('$name','$livedev','hls')}"); + return $ret if($ret); + my $c = "The device needs to set attribute \"hlsStrmObject\" in camera device \"$name\" to a valid HLS videostream"; + CommandAttr($hash->{CL},"$livedev comment $c"); } if($prop =~ /switched/) { $livedev = "SSCamSTRM.$name.switched"; @@ -788,7 +873,7 @@ sub SSCam_Set($@) { return $ret if($ret); } - my $room = AttrVal($name,"room","Livestream"); + my $room = AttrVal($name,"room","SSCam"); $attr{$livedev}{room} = $room; return "Livestream device \"$livedev\" created and assigned to room \"$room\"."; @@ -802,7 +887,7 @@ sub SSCam_Set($@) { '< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >'."\n". '< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >'."\n". '<%it_server>,On/Off>,< >,,< >, >,< >,< >,< >,< >, >,< >,< >,< >,< >,< >,< >,< >,< >,< >,< >'."\n". - 'TYPE=SSCam:FILTER=MODEL=SVS:HomeModeState,< >,state,< >,< >,< >,< >,< >,< >, >,< >,< >,< >,?!disable,< >,< >,< >,< >,< >'."\n". + 'TYPE=SSCam:FILTER=MODEL=SVS:!HomeModeState,< >,state,< >,< >,< >,< >,< >,< >, >,< >,< >,< >,?!disable,< >,< >,< >,< >,< >'."\n". ''; my $ret = CommandDefine($hash->{CL},"$rgdev readingsGroup $rgdef"); @@ -1215,9 +1300,23 @@ sub SSCam_Get($@) { } 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); + my ($success, $username, $password) = SSCam_getcredentials($hash,0,"svs"); unless ($success) {return "Credentials couldn't be retrieved successfully - see logfile"}; - return "Stored Credentials for $name - Username: $username, Password: $password"; + + my ($smtpsuccess, $smtpuname, $smtpword) = SSCam_getcredentials($hash,0,"smtp"); + my $so; + if($smtpsuccess) { + $so = "SMTP-Username: $smtpuname, SMTP-Password: $smtpword"; + } else { + $so = "SMTP credentials are not set"; + } + return "Stored Credentials to access surveillance station or DSM:\n". + "=========================================================\n". + "Username: $username, Password: $password\n". + "\n". + "Stored Credentials to access SMTP server:\n". + "=========================================\n". + "$so\n"; } 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\"";} @@ -1382,7 +1481,7 @@ sub SSCam_FWsummaryFn ($$$$) { my $name = $hash->{NAME}; my $link = $hash->{HELPER}{LINK}; my $wltype = $hash->{HELPER}{WLTYPE}; - my $ret; + my $ret = ""; my $alias; return if(!$hash->{HELPER}{LINK} || ReadingsVal($d, "state", "") =~ /^dis.*/ || IsDisabled($name)); @@ -1411,24 +1510,43 @@ sub SSCam_FWsummaryFn ($$$$) { 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"); + # Javascript Bibliothek für Tooltips (http://www.walterzorn.de/tooltip/tooltip.htm#download) und Texte + my $calias = $hash->{CAMNAME}; # Alias der Kamera + my $ttjs = "/fhem/pgm2/sscam_tooltip.js"; + my ($ttrefresh, $ttrecstart, $ttrecstop, $ttsnap, $ttcmdstop, $tthlsreact, $ttmjpegrun, $tthlsrun, $ttlrrun, $tth264run, $ttlmjpegrun, $ttlsnaprun); + if(AttrVal("global","language","EN") =~ /EN/) { + $ttrecstart = $SSCam_ttips_en{"ttrecstart"}; $ttrecstart =~ s/§NAME§/$calias/g; + $ttrecstop = $SSCam_ttips_en{"ttrecstop"}; $ttrecstop =~ s/§NAME§/$calias/g; + $ttsnap = $SSCam_ttips_en{"ttsnap"}; $ttsnap =~ s/§NAME§/$calias/g; + $ttcmdstop = $SSCam_ttips_en{"ttcmdstop"}; $ttcmdstop =~ s/§NAME§/$calias/g; + $tthlsreact = $SSCam_ttips_en{"tthlsreact"}; $tthlsreact =~ s/§NAME§/$calias/g; + } else { + $ttrecstart = $SSCam_ttips_de{"ttrecstart"}; $ttrecstart =~ s/§NAME§/$calias/g; + $ttrecstop = $SSCam_ttips_de{"ttrecstop"}; $ttrecstop =~ s/§NAME§/$calias/g; + $ttsnap = $SSCam_ttips_de{"ttsnap"}; $ttsnap =~ s/§NAME§/$calias/g; + $ttcmdstop = $SSCam_ttips_de{"ttcmdstop"}; $ttcmdstop =~ s/§NAME§/$calias/g; + $tthlsreact = $SSCam_ttips_de{"tthlsreact"}; $tthlsreact =~ s/§NAME§/$calias/g; + } + + $ret .= ""; + if($wltype eq "image") { - $ret = "
"; - $ret .= "$imgstop "; + $ret .= "
"; + $ret .= "$imgstop "; $ret .= $imgblank; if($hash->{HELPER}{RUNVIEW} =~ /live_fw/) { if(ReadingsVal($d, "Record", "Stop") eq "Stop") { # Aufnahmebutton endlos Start - $ret .= "$imgrecendless "; + $ret .= "$imgrecendless "; } else { # Aufnahmebutton Stop - $ret .= "$imgrecstop "; + $ret .= "$imgrecstop "; } - $ret .= "$imgdosnap "; + $ret .= "$imgdosnap "; } $ret .= "
"; if($hash->{HELPER}{AUDIOLINK} && ReadingsVal($d, "CamAudioType", "Unknown") !~ /Unknown/) { @@ -1438,11 +1556,11 @@ sub SSCam_FWsummaryFn ($$$$) { } } elsif($wltype eq "iframe") { - $ret = ""; $ret .= "
"; - $ret .= "$imgstop "; + $ret .= "$imgstop "; if($hash->{HELPER}{AUDIOLINK} && ReadingsVal($d, "CamAudioType", "Unknown") !~ /Unknown/) { $ret .= "