diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 13d1f07b8..dc0fadd53 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -625,6 +625,7 @@ INSERT INTO `Controls` VALUES (NULL,'IPCC 7210W','Libvlc','IPCC7210W', 1, 1, 1, INSERT INTO `Controls` VALUES (NULL,'Vivotek ePTZ','Remote','Vivotek_ePTZ',0,0,1,1,0,0,0,1,0,0,0,0,1,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,1,0,5,0,0,1,0,0,0,0,1,0,5,0,0,0,0); INSERT INTO `Controls` VALUES (NULL,'Netcat ONVIF','Ffmpeg','Netcat',0,0,1,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,100,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,100,5,5,0,0,0,1,255,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0); INSERT INTO `Controls` VALUES (NULL,'Keekoon','Remote','Keekoon', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); +INSERT INTO `Controls` VALUES (NULL,'HikVision','Local','',0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,20,1,1,1,1,0,0,0,1,1,0,0,0,0,1,1,100,0,0,1,0,0,0,0,1,1,100,1,0,0,0); -- -- Add some monitor preset values @@ -697,6 +698,8 @@ INSERT INTO MonitorPresets VALUES (NULL,'Foscam FI9821W FFMPEG H.264','Ffmpeg',N INSERT INTO MonitorPresets VALUES (NULL,'Loftek Sentinel PTZ, 640x480, mjpeg','Remote','http',0,0,NULL,NULL,'','80','/videostream.cgi?user=&pwd=&resolution=32&rate=11',NULL,640,480,4,NULL,1,'13','',':@',100,100); INSERT INTO MonitorPresets VALUES (NULL,'Airlink 777W PTZ, 640x480, mjpeg','Remote','http',0,0,NULL,NULL,':@','80','/cgi/mjpg/mjpg.cgi',NULL,640,480,4,NULL,1,'7','',':@',100,100); INSERT INTO MonitorPresets VALUES (NULL,'SunEyes SP-P1802SWPTZ','Libvlc','/dev/video','0',255,'','rtpMulti','','80','rtsp://:554/11','',1920,1080,0,0.00,1,'16','-speed=64',':',100,33); +INSERT INTO MonitorPresets VALUES (NULL,'Qihan IP, 1280x720, RTP/RTSP','Ffmpeg','rtsp','rtpRtsp',255,'rtsp','rtpRtsp',NULL,554,'rtsp:///tcp_live/ch0_0',NULL,1280,720,3,NULL,0,NULL,NULL,NULL,100,100); +INSERT INTO MonitorPresets VALUES (NULL,'Qihan IP, 1920x1080, RTP/RTSP','Ffmpeg','rtsp','rtpRtsp',255,'rtsp','rtpRtsp',NULL,554,'rtsp:///tcp_live/ch0_0',NULL,1920,1080,3,NULL,0,NULL,NULL,NULL,100,100); -- -- Add some zone preset values diff --git a/distros/redhat/CMakeLists.txt b/distros/redhat/CMakeLists.txt index df3edf7d9..f8acef552 100644 --- a/distros/redhat/CMakeLists.txt +++ b/distros/redhat/CMakeLists.txt @@ -49,10 +49,8 @@ endif("${unzip_jsc}" STREQUAL "") file(MAKE_DIRECTORY sock swap zoneminder zoneminder-upload events images temp) # Install the empty folders -#install(DIRECTORY run DESTINATION /var DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_WRITE GROUP_READ GROUP_EXECUTE WORLD_WRITE WORLD_READ WORLD_EXECUTE) install(DIRECTORY sock swap DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY zoneminder DESTINATION /var/log DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) -install(DIRECTORY zoneminder DESTINATION /run DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY zoneminder-upload DESTINATION /var/spool DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY events images temp DESTINATION /var/lib/zoneminder DIRECTORY_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) diff --git a/distros/redhat/nginx/zoneminder.service.in b/distros/redhat/nginx/zoneminder.service.in index da569423d..7e2e36585 100644 --- a/distros/redhat/nginx/zoneminder.service.in +++ b/distros/redhat/nginx/zoneminder.service.in @@ -8,12 +8,15 @@ Requires=mariadb.service nginx.service php-fpm.service fcgiwrap.service [Service] User=@WEB_USER@ +Group=@WEB_GROUP@ Type=forking ExecStart=@BINDIR@/zmpkg.pl start ExecReload=@BINDIR@/zmpkg.pl restart ExecStop=@BINDIR@/zmpkg.pl stop PIDFile=@ZM_RUNDIR@/zm.pid Environment=TZ=/etc/localtime +RuntimeDirectory=zoneminder +RuntimeDirectoryMode=0755 [Install] WantedBy=multi-user.target diff --git a/distros/redhat/nginx/zoneminder.tmpfiles.in b/distros/redhat/nginx/zoneminder.tmpfiles.in index d92ceaafd..8040a7877 100644 --- a/distros/redhat/nginx/zoneminder.tmpfiles.in +++ b/distros/redhat/nginx/zoneminder.tmpfiles.in @@ -1,4 +1,3 @@ -D @ZM_RUNDIR@ 0755 @WEB_USER@ @WEB_GROUP@ D @ZM_TMPDIR@ 0755 @WEB_USER@ @WEB_GROUP@ D @ZM_SOCKDIR@ 0755 @WEB_USER@ @WEB_GROUP@ D /var/lib/php/session 770 root @WEB_GROUP@ diff --git a/distros/redhat/systemd/zoneminder.conf.in b/distros/redhat/systemd/zoneminder.conf.in index 564e4ccbd..005c959a6 100644 --- a/distros/redhat/systemd/zoneminder.conf.in +++ b/distros/redhat/systemd/zoneminder.conf.in @@ -11,6 +11,9 @@ RewriteRule ^/?(zm)(.*) https://%{SERVER_NAME}/$1$2 [R,L] Alias /zm "@ZM_WEBDIR@" + # explicitly set index.php as the only directoryindex + DirectoryIndex disabled + DirectoryIndex index.php SSLRequireSSL Options -Indexes +MultiViews +FollowSymLinks AllowOverride All diff --git a/distros/redhat/systemd/zoneminder.service.in b/distros/redhat/systemd/zoneminder.service.in index 030ca8065..2234af036 100644 --- a/distros/redhat/systemd/zoneminder.service.in +++ b/distros/redhat/systemd/zoneminder.service.in @@ -7,12 +7,15 @@ Requires=mariadb.service httpd.service [Service] User=@WEB_USER@ +Group=@WEB_GROUP@ Type=forking ExecStart=@BINDIR@/zmpkg.pl start ExecReload=@BINDIR@/zmpkg.pl restart ExecStop=@BINDIR@/zmpkg.pl stop PIDFile=@ZM_RUNDIR@/zm.pid Environment=TZ=/etc/localtime +RuntimeDirectory=zoneminder +RuntimeDirectoryMode=0755 [Install] WantedBy=multi-user.target diff --git a/distros/redhat/systemd/zoneminder.tmpfiles.in b/distros/redhat/systemd/zoneminder.tmpfiles.in index f655a9c9f..f3acd0af7 100644 --- a/distros/redhat/systemd/zoneminder.tmpfiles.in +++ b/distros/redhat/systemd/zoneminder.tmpfiles.in @@ -1,3 +1,2 @@ -D @ZM_RUNDIR@ 0755 @WEB_USER@ @WEB_GROUP@ D @ZM_TMPDIR@ 0755 @WEB_USER@ @WEB_GROUP@ D @ZM_SOCKDIR@ 0755 @WEB_USER@ @WEB_GROUP@ diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 58a5a1a44..a3bb48865 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -1,14 +1,14 @@ %global zmuid_final apache %global zmgid_final apache -# In some cases older distros do not have this macro defined -%{!?make_build: %global make_build %{__make} %{?_smp_mflags} } +# Crud is configured as a git submodule +%global crud_version 3.0.10 %if "%{zmuid_final}" == "nginx" - %global with_nginx 1 - %global wwwconfdir /etc/nginx/default.d +%global with_nginx 1 +%global wwwconfdir /etc/nginx/default.d %else - %global wwwconfdir /etc/httpd/conf.d +%global wwwconfdir /etc/httpd/conf.d %endif %global sslcert %{_sysconfdir}/pki/tls/certs/localhost.crt @@ -42,38 +42,76 @@ Group: System Environment/Daemons # jscalendar is LGPL (any version): http://www.dynarch.com/projects/calendar/ # Mootools is inder the MIT license: http://mootools.net/ # CakePHP is under the MIT license: https://github.com/cakephp/cakephp +# Crud is under the MIT license: https://github.com/FriendsOfCake/crud License: GPLv2+ and LGPLv2+ and MIT URL: http://www.zoneminder.com/ -Source: ZoneMinder-%{version}.tar.gz +Source0: https://github.com/ZoneMinder/ZoneMinder/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz +Source1: https://github.com/FriendsOfCake/crud/archive/v%{crud_version}.tar.gz#/crud-%{crud_version}.tar.gz -%{?with_init_systemd:BuildRequires: systemd-devel mariadb-devel perl-podlators} +%{?with_init_systemd:BuildRequires: systemd-devel} +%{?with_init_systemd:BuildRequires: mariadb-devel} +%{?with_init_systemd:BuildRequires: perl-podlators} %{?with_init_sysv:BuildRequires: mysql-devel} BuildRequires: cmake >= 2.8.7 -BuildRequires: gnutls-devel bzip2-devel -BuildRequires: pcre-devel libjpeg-turbo-devel -BuildRequires: perl(Archive::Tar) perl(Archive::Zip) -BuildRequires: perl(Date::Manip) perl(DBD::mysql) -BuildRequires: perl(ExtUtils::MakeMaker) perl(LWP::UserAgent) -BuildRequires: perl(MIME::Entity) perl(MIME::Lite) -BuildRequires: perl(PHP::Serialization) perl(Sys::Mmap) -BuildRequires: perl(Time::HiRes) perl(Net::SFTP::Foreign) -BuildRequires: perl(Expect) perl(Sys::Syslog) -BuildRequires: gcc gcc-c++ vlc-devel libcurl-devel libv4l-devel -BuildRequires: ffmpeg-devel polkit-devel +BuildRequires: gnutls-devel +BuildRequires: bzip2-devel +BuildRequires: pcre-devel +BuildRequires: libjpeg-turbo-devel +BuildRequires: findutils +BuildRequires: coreutils +BuildRequires: perl +BuildRequires: perl-generators +BuildRequires: perl(Archive::Tar) +BuildRequires: perl(Archive::Zip) +BuildRequires: perl(Date::Manip) +BuildRequires: perl(DBD::mysql) +BuildRequires: perl(ExtUtils::MakeMaker) +BuildRequires: perl(LWP::UserAgent) +BuildRequires: perl(MIME::Entity) +BuildRequires: perl(MIME::Lite) +BuildRequires: perl(PHP::Serialization) +BuildRequires: perl(Sys::Mmap) +BuildRequires: perl(Time::HiRes) +BuildRequires: perl(Net::SFTP::Foreign) +BuildRequires: perl(Expect) +BuildRequires: perl(Sys::Syslog) +BuildRequires: gcc +BuildRequires: gcc-c++ +BuildRequires: vlc-devel +BuildRequires: libcurl-devel +BuildRequires: libv4l-devel +BuildRequires: ffmpeg-devel +BuildRequires: polkit-devel -%{?with_nginx:Requires: nginx fcgiwrap php-fpm} -%{!?with_nginx:Requires: httpd} +%{?with_nginx:Requires: nginx} +%{?with_nginx:Requires: fcgiwrap} +%{?with_nginx:Requires: php-fpm} +%{!?with_nginx:Requires: httpd php} +%{!?with_nginx:Requires: php} %{?with_php_mysqlnd:Requires: php-mysqlnd} %{?with_php_mysql:Requires: php-mysql} -Requires: php-common php-gd cambozola polkit net-tools psmisc -Requires: libjpeg-turbo vlc-core libcurl ffmpeg +Requires: php-common +Requires: php-gd +Requires: cambozola +Requires: net-tools +Requires: psmisc +Requires: polkit +Requires: libjpeg-turbo +Requires: vlc-core +Requires: ffmpeg Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version)) -Requires: perl(DBD::mysql) perl(Archive::Tar) perl(Archive::Zip) -Requires: perl(MIME::Entity) perl(MIME::Lite) perl(Net::SMTP) perl(Net::FTP) -Requires: perl(LWP::Protocol::https) perl(X10::ActiveHome) perl(Astro::SunTime) +Requires: perl(DBD::mysql) +Requires: perl(Archive::Tar) +Requires: perl(Archive::Zip) +Requires: perl(MIME::Entity) +Requires: perl(MIME::Lite) +Requires: perl(Net::SMTP) +Requires: perl(Net::FTP) +Requires: perl(LWP::Protocol::https) -%{?with_init_systemd:Requires(post): systemd systemd-sysv} +%{?with_init_systemd:Requires(post): systemd} +%{?with_init_systemd:Requires(post): systemd-sysv} %{?with_init_systemd:Requires(preun): systemd} %{?with_init_systemd:Requires(postun): systemd} @@ -99,13 +137,16 @@ designed to support as many cameras as you can attach to your computer without too much degradation of performance. %prep -%autosetup -n ZoneMinder-%{version} +%autosetup +%autosetup -a 1 +rmdir ./web/api/app/Plugin/Crud +mv -f crud-%{crud_version} ./web/api/app/Plugin/Crud # Change the following default values ./utils/zmeditconfigdata.sh ZM_PATH_ZMS /cgi-bin-zm/nph-zms ./utils/zmeditconfigdata.sh ZM_OPT_CAMBOZOLA yes ./utils/zmeditconfigdata.sh ZM_PATH_SWAP /dev/shm -./utils/zmeditconfigdata.sh ZM_UPLOAD_FTP_LOC_DIR /var/spool/zoneminder-upload +./utils/zmeditconfigdata.sh ZM_UPLOAD_FTP_LOC_DIR %{_localstatedir}/spool/zoneminder-upload ./utils/zmeditconfigdata.sh ZM_OPT_CONTROL yes ./utils/zmeditconfigdata.sh ZM_CHECK_FOR_UPDATES no ./utils/zmeditconfigdata.sh ZM_DYN_SHOW_DONATE_REMINDER no @@ -284,11 +325,9 @@ rm -rf %{_docdir}/%{name}-%{version} %{perl_vendorlib}/WSSecurity* %{perl_vendorlib}/WSNotification* %{_mandir}/man*/* -%dir %{_libexecdir}/zoneminder -%{_libexecdir}/zoneminder/cgi-bin -%dir %{_datadir}/zoneminder -%{_datadir}/zoneminder/db -%{_datadir}/zoneminder/www + +%{_libexecdir}/zoneminder/ +%{_datadir}/zoneminder/ %{_datadir}/polkit-1/actions/com.zoneminder.systemctl.policy %{_datadir}/polkit-1/rules.d/com.zoneminder.systemctl.rules @@ -299,9 +338,9 @@ rm -rf %{_docdir}/%{name}-%{version} %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/sock %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/swap %dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_sharedstatedir}/zoneminder/temp -%dir %attr(755,%{zmuid_final},%{zmgid_final}) /var/log/zoneminder -%dir %attr(755,%{zmuid_final},%{zmgid_final}) /var/spool/zoneminder-upload -%dir %attr(755,%{zmuid_final},%{zmgid_final}) %ghost /run/zoneminder +%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/log/zoneminder +%dir %attr(755,%{zmuid_final},%{zmgid_final}) %{_localstatedir}/spool/zoneminder-upload +%dir %attr(755,%{zmuid_final},%{zmgid_final}) %ghost %{_localstatedir}/run/zoneminder %changelog * Wed Dec 28 2016 Andrew Bauer - 1.30.1-2 diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/HikVision.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/HikVision.pm new file mode 100644 index 000000000..2c665b4ad --- /dev/null +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/HikVision.pm @@ -0,0 +1,411 @@ +# ========================================================================== +# +# ZoneMinder HikVision Control Protocol Module +# Copyright (C) 2016 Terry Sanders +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ========================================================================== +# +# This module contains an implementation of the HikVision ISAPI camera control +# protocol +# +package ZoneMinder::Control::HikVision; + +use 5.006; +use strict; +use warnings; + +require ZoneMinder::Base; +require ZoneMinder::Control; + +our @ISA = qw(ZoneMinder::Control); + +# ========================================================================== +# +# HiKVision ISAPI Control Protocol +# +# Set the following: +# ControlAddress: username:password@camera_webaddress:port +# ControlDevice: IP Camera Model +# +# ========================================================================== + +use ZoneMinder::Logger qw(:all); + +use Time::HiRes qw( usleep ); + +use LWP::UserAgent; +use HTTP::Cookies; + +my $ChannelID = 1; # Usually... +my $DefaultFocusSpeed = 50; # Should be between 1 and 100 +my $DefaultIrisSpeed = 50; # Should be between 1 and 100 + +sub new { + my $class = shift; + my $id = shift; + my $self = ZoneMinder::Control->new( $id ); + bless( $self, $class ); + srand( time() ); + return $self; +} + +our $AUTOLOAD; + +sub AUTOLOAD { + my $self = shift; + my $class = ref($self) || croak( "$self not object" ); + my $name = $AUTOLOAD; + $name =~ s/.*://; + if ( exists($self->{$name}) ) + { + return( $self->{$name} ); + } + Fatal( "Can't access $name member of object of class $class" ); +} +sub open { + my $self = shift; + $self->loadMonitor(); + # + # Create a UserAgent for the requests + # + $self->{UA} = LWP::UserAgent->new(); + $self->{UA}->cookie_jar( {} ); + # + # Extract the username/password host/port from ControlAddress + # + my ($user,$pass,$host,$port); + if( $self->{Monitor}{ControlAddress} =~ /^([^:]+):([^@]+)@(.+)/ ) { # user:pass@host... + $user = $1; + $pass = $2; + $host = $3; + } + elsif( $self->{Monitor}{ControlAddress} =~ /^([^@]+)@(.+)/ ) { # user@host... + $user = $1; + $host = $2; + } + else { # Just a host + $host = $self->{Monitor}{ControlAddress}; + } + # Check if it is a host and port or just a host + if( $host =~ /([^:]+):(.+)/ ) { + $host = $1; + $port = $2; + } + else { + $port = 80; + } + # Save the credentials + if( defined($user) ) { + $self->{UA}->credentials( "$host:$port", $self->{Monitor}{ControlDevice}, $user, $pass ); + } + # Save the base url + $self->{BaseURL} = "http://$host:$port"; +} +sub PutCmd { + my $self = shift; + my $cmd = shift; + my $content = shift; + my $req = HTTP::Request->new(PUT => "$self->{BaseURL}/$cmd"); + if(defined($content)) { + $req->content_type("application/x-www-form-urlencoded; charset=UTF-8"); + $req->content('' . "\n" . $content); + } + my $res = $self->{UA}->request($req); + unless( $res->is_success ) { + # + # The camera timeouts connections at short intervals. When this + # happens the user agent connects again and uses the same auth tokens. + # The camera rejects this and asks for another token but the UserAgent + # just gives up. Because of this I try the request again and it should + # succeed the second time if the credentials are correct. + # + if($res->code == 401) { + $res = $self->{UA}->request($req); + unless( $res->is_success ) { + # + # It has failed authentication. The odds are + # that the user has set some paramater incorrectly + # so check the realm against the ControlDevice + # entry and send a message if different + # + my $auth = $res->headers->www_authenticate; + foreach (split(/\s*,\s*/,$auth)) { + if( $_ =~ /^realm\s*=\s*"([^"]+)"/i ) { + if( $self->{Monitor}{ControlDevice} ne $1 ) { + Info "Control Device appears to be incorrect."; + Info "Control Device should be set to \"$1\"."; + Info "Control Device currently set to \"$self->{Monitor}{ControlDevice}\"."; + } + } + } + # + # Check for username/password + # + if( $self->{Monitor}{ControlAddress} =~ /.+:(.+)@.+/ ) { + Info "Check username/password is correct"; + } elsif ( $self->{Monitor}{ControlAddress} =~ /^[^:]+@.+/ ) { + Info "No password in Control Address. Should there be one?"; + } elsif ( $self->{Monitor}{ControlAddress} =~ /^:.+@.+/ ) { + Info "Password but no username in Control Address."; + } else { + Info "Missing username and password in Control Address."; + } + Fatal $res->status_line; + } + } + else { + Fatal $res->status_line; + } + } +} +# +# The move continuous functions all call moveVector +# with the direction to move in. This includes zoom +# +sub moveVector { + my $self = shift; + my $pandirection = shift; + my $tiltdirection = shift; + my $zoomdirection = shift; + my $params = shift; + my $command; # The ISAPI/PTZ command + + # Calculate autostop time + my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; + # Change from microseconds to milliseconds + $duration = int($duration/1000); + my $momentxml; + if( $duration ) { + $momentxml = "$duration"; + $command = "ISAPI/PTZCtrl/channels/$ChannelID/momentary"; + } + else { + $momentxml = ""; + $command = "ISAPI/PTZCtrl/channels/$ChannelID/continuous"; + } + # Calculate movement speeds + my $x = $pandirection * $self->getParam( $params, 'panspeed', 0 ); + my $y = $tiltdirection * $self->getParam( $params, 'tiltspeed', 0 ); + my $z = $zoomdirection * $self->getParam( $params, 'speed', 0 ); + # Create the XML + my $xml = "$x$y$z$momentxml"; + # Send it to the camera + $self->PutCmd($command,$xml); +} +sub moveStop { $_[0]->moveVector( 0, 0, 0, splice(@_,1)); } +sub moveConUp { $_[0]->moveVector( 0, 1, 0, splice(@_,1)); } +sub moveConUpRight { $_[0]->moveVector( 1, 1, 0, splice(@_,1)); } +sub moveConRight { $_[0]->moveVector( 1, 0, 0, splice(@_,1)); } +sub moveConDownRight { $_[0]->moveVector( 1, -1, 0, splice(@_,1)); } +sub moveConDown { $_[0]->moveVector( 0, -1, 0, splice(@_,1)); } +sub moveConDownLeft { $_[0]->moveVector( -1, -1, 0, splice(@_,1)); } +sub moveConLeft { $_[0]->moveVector( -1, 0, 0, splice(@_,1)); } +sub moveConUpLeft { $_[0]->moveVector( -1, 1, 0, splice(@_,1)); } +sub zoomConTele { $_[0]->moveVector( 0, 0, 1, splice(@_,1)); } +sub zoomConWide { $_[0]->moveVector( 0, 0,-1, splice(@_,1)); } +# +# Presets including Home set and clear +# +sub presetGoto { + my $self = shift; + my $params = shift; + my $preset = $self->getParam($params,'preset'); + $self->PutCmd("ISAPI/PTZCtrl/channels/$ChannelID/presets/$preset/goto"); +} +sub presetSet { + my $self = shift; + my $params = shift; + my $preset = $self->getParam($params,'preset'); + my $xml = "$preset"; + $self->PutCmd("ISAPI/PTZCtrl/channels/$ChannelID/presets/$preset",$xml); +} +sub presetHome { + my $self = shift; + my $params = shift; + $self->PutCmd("ISAPI/PTZCtrl/channels/$ChannelID/homeposition/goto"); +} +# +# Focus controls all call Focus with a +/- speed +# +sub Focus { + my $self = shift; + my $speed = shift; + my $xml = "$speed"; + $self->PutCmd("ISAPI/System/Video/inputs/channels/$ChannelID/focus",$xml); +} +sub focusConNear { + my $self = shift; + my $params = shift; + + # Calculate autostop time + my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; + # Get the focus speed + my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); + $self->Focus(-$speed); + if($duration) { + usleep($duration); + $self->moveStop($params); + } +} +sub Near { + my $self = shift; + my $params = shift; + $self->Focus(-$DefaultFocusSpeed); +} +sub focusAbsNear { + my $self = shift; + my $params = shift; + + # Get the focus speed + my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); + $self->Focus(-$speed); +} +sub focusRelNear { + my $self = shift; + my $params = shift; + # Get the focus speed + my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); + $self->Focus(-$speed); +} +sub focusConFar { + my $self = shift; + my $params = shift; + + # Calculate autostop time + my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; + # Get the focus speed + my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); + $self->Focus($speed); + if($duration) { + usleep($duration); + $self->moveStop($params); + } +} +sub Far { + my $self = shift; + my $params = shift; + $self->Focus($DefaultFocusSpeed); +} +sub focusAbsFar { + my $self = shift; + my $params = shift; + + # Get the focus speed + my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); + $self->Focus($speed); +} +sub focusRelFar { + my $self = shift; + my $params = shift; + + # Get the focus speed + my $speed = $self->getParam( $params, 'speed', $DefaultFocusSpeed ); + $self->Focus($speed); +} +# +# Iris controls all call Iris with a +/- speed +# +sub Iris { + my $self = shift; + my $speed = shift; + + my $xml = "$speed"; + $self->PutCmd("ISAPI/System/Video/inputs/channels/$ChannelID/iris",$xml); +} +sub irisConClose { + my $self = shift; + my $params = shift; + + # Calculate autostop time + my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; + # Get the iris speed + my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); + $self->Iris(-$speed); + if($duration) { + usleep($duration); + $self->moveStop($params); + } +} +sub Close { + my $self = shift; + my $params = shift; + + $self->Iris(-$DefaultIrisSpeed); +} +sub irisAbsClose { + my $self = shift; + my $params = shift; + + # Get the iris speed + my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); + $self->Iris(-$speed); +} +sub irisRelClose { + my $self = shift; + my $params = shift; + + # Get the iris speed + my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); + $self->Iris(-$speed); +} +sub irisConOpen { + my $self = shift; + my $params = shift; + + # Calculate autostop time + my $duration = $self->getParam( $params, 'autostop', 0 ) * $self->{Monitor}{AutoStopTimeout}; + # Get the iris speed + my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); + $self->Iris($speed); + if($duration) { + usleep($duration); + $self->moveStop($params); + } +} +sub Open { + my $self = shift; + my $params = shift; + + $self->Iris($DefaultIrisSpeed); +} +sub irisAbsOpen { + my $self = shift; + my $params = shift; + + # Get the iris speed + my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); + $self->Iris($speed); +} +sub irisRelOpen { + my $self = shift; + my $params = shift; + + # Get the iris speed + my $speed = $self->getParam( $params, 'speed', $DefaultIrisSpeed ); + $self->Iris($speed); +} +# +# reset (reboot) the device +# +sub reset { + my $self = shift; + + $self->PutCmd("ISAPI/System/reboot"); +} + +1; + diff --git a/web/includes/control_functions.php b/web/includes/control_functions.php index dfbc8cb3e..d5fa06675 100644 --- a/web/includes/control_functions.php +++ b/web/includes/control_functions.php @@ -9,7 +9,7 @@ function buildControlCommand( $monitor ) $slow = 0.9; // Threshold for slow speed/timeouts $turbo = 0.9; // Threshold for turbo speed - if ( preg_match( '/^([a-z]+)([A-Z][a-z]+)([A-Z][a-z]+)+$/', $_REQUEST['control'], $matches ) ) + if ( preg_match( '/^([a-z]+)([A-Z][a-z]+)([A-Za-z]+)+$/', $_REQUEST['control'], $matches ) ) { $command = $matches[1]; $mode = $matches[2]; @@ -278,6 +278,8 @@ function buildControlCommand( $monitor ) } } } + } else { + Error("Invalid control parameter: " . $_REQUEST['control'] ); } } elseif ( isset($_REQUEST['x']) && isset($_REQUEST['y']) )