From a942b22541e5bf3ff95d1b42f3662f0c89cc6042 Mon Sep 17 00:00:00 2001 From: Robin Daermann Date: Wed, 23 Sep 2015 16:18:49 +0200 Subject: [PATCH 1/5] Add camera control module for Vivotek ePTZ protocol --- .../lib/ZoneMinder/Control/Vivotek_ePTZ.pm | 227 ++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm new file mode 100644 index 000000000..b407a9bde --- /dev/null +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm @@ -0,0 +1,227 @@ +# ========================================================================== +# +# ZoneMinder Vivotek ePTZ Control Protocol Module +# Copyright (C) 2015 Robin Daermann +# +# 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 the implementation of the Vivotek ePTZ camera control +# protocol +# +package ZoneMinder::Control::Vivotek_ePTZ; + +use 5.006; +use strict; +use warnings; + +require ZoneMinder::Base; +require ZoneMinder::Control; + +our @ISA = qw(ZoneMinder::Control); + +# ========================================================================== +# +# Vivotek ePTZ Control Protocol +# +# ========================================================================== + +use ZoneMinder::Logger qw(:all); +use ZoneMinder::Config qw(:all); + +use Time::HiRes qw( usleep ); + +sub new +{ + my $class = shift; + my $id = shift; + my $self = ZoneMinder::Control->new( $id ); + Debug( "Camera New" ); + 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; + Debug( "Camera 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(); + Debug( "Camera open" ); + use LWP::UserAgent; + $self->{ua} = LWP::UserAgent->new; + $self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION ); + + $self->{state} = 'open'; +} + +sub close +{ + my $self = shift; + $self->{state} = 'closed'; +} + +sub printMsg +{ + my $msg = shift; + my $msg_len = length($msg); + + Debug( $msg."[".$msg_len."]" ); +} + +sub sendCmd +{ + my ($self, $cmd, $speedcmd) = @_; + + my $result = undef; + + printMsg( $speedcmd, "Tx" ); + printMsg( $cmd, "Tx" ); + + my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/cgi-bin/camctrl/eCamCtrl.cgi?stream=0&$speedcmd&$cmd" ); + my $res = $self->{ua}->request($req); + + if ( $res->is_success ) + { + $result = !undef; + } + else + { + Error( "Error check failed: '".$res->status_line()."'" ); + } + + return( $result ); +} + +sub moveConUp +{ + my ($self, $params) = @_; + my $speed = 'speedtilt=' . ($params->{tiltspeed} - 6); + Debug( "Move Up" ); + $self->sendCmd( 'move=up', $speed ); +} + +sub moveConDown +{ + my ($self, $params) = @_; + my $speed = 'speedtilt=' . ($params->{tiltspeed} - 6); + Debug( "Move Down" ); + $self->sendCmd( 'move=down', $speed ); +} + +sub moveConLeft +{ + my ($self, $params) = @_; + my $speed = 'speedpan=-' . $params->{panspeed}; + Debug( "Move Left" ); + $self->sendCmd( 'move=left', $speed ); +} + +sub moveConRight +{ + my ($self, $params) = @_; + my $speed = 'speedpan=' . ($params->{panspeed} - 6); + Debug( "Move Right" ); + $self->sendCmd( 'move=right', $speed ); +} + +sub moveStop +{ + my $self = shift; + Debug( "Move Stop" ); + # not implemented +} + +sub zoomConTele +{ + my ($self, $params) = @_; + my $speed = 'speedzoom=' . ($params->{speed} - 6); + Debug( "Zoom In" ); + $self->sendCmd( 'zoom=tele', $speed ); +} + +sub zoomConWide +{ + my ($self, $params) = @_; + my $speed = 'speedzoom=' . ($params->{speed} - 6); + Debug( "Zoom Out" ); + $self->sendCmd( 'zoom=wide', $speed ); +} + +sub reset +{ + my $self = shift; + Debug( "Camera Reset" ); + $self->sendCmd( 'move=home' ); +} + +1; +__END__ + +=head1 NAME + +ZoneMinder::Control::Vivotek_ePTZ - ZoneMinder Perl extension for Vivotek ePTZ +camera control protocol + +=head1 SYNOPSIS + + use ZoneMinder::Control::Vivotek_ePTZ; + +=head1 DESCRIPTION + +This module implements the ePTZ protocol used in various Vivotek IP cameras, +developed with a Vivotek IB8369 model. + +Currently, only simple pan, tilt and zoom function is implemented. Presets will +follow later. + +=head2 EXPORT + +None. + +=head1 SEE ALSO + +I would say, see ZoneMinder::Control documentation. But it is a stub. + +=head1 AUTHOR + +Robin Daermann Er.daermann@ids-services.deE + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2015 by Robin Daermann + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.8.3 or, +at your option, any later version of Perl 5 you may have available. + +=cut From 330e0d7adf431f6798c1e1fd53f920467705cf6c Mon Sep 17 00:00:00 2001 From: Robin Daermann Date: Wed, 4 Nov 2015 17:29:07 +0100 Subject: [PATCH 2/5] Add Vivotek ePTZ control module to database --- db/zm_update-1.28.109.sql | 110 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 db/zm_update-1.28.109.sql diff --git a/db/zm_update-1.28.109.sql b/db/zm_update-1.28.109.sql new file mode 100644 index 000000000..298668e08 --- /dev/null +++ b/db/zm_update-1.28.109.sql @@ -0,0 +1,110 @@ +-- +-- This updates a 1.28.108 database to 1.28.109 +-- + +-- +-- Add Controls definition for Vivotek ePTZ +-- +INSERT INTO Controls +SELECT * FROM (SELECT NULL as Id, + 'Vivotek ePTZ' as Name, + 'Remote' as Type, + 'Vivotek_ePTZ' as Protocol, + 0 as CanWake, + 0 as CanSleep, + 1 as CanReset, + 1 as CanZoom, + 0 as CanAutoZoom, + 0 as CanZoomAbs, + 0 as CanZoomRel, + 1 as CanZoomCon, + 0 as MinZoomRange, + 0 as MaxZoomRange, + 0 as MinZoomStep, + 0 as MaxZoomStep, + 1 as HasZoomSpeed, + 0 as MinZoomSpeed, + 5 as MaxZoomSpeed, + 0 as CanFocus, + 0 as CanAutoFocus, + 0 as CanFocusAbs, + 0 as CanFocusRel, + 0 as CanFocusCon, + 0 as MinFocusRange, + 0 as MaxFocusRange, + 0 as MinFocusStep, + 0 as MaxFocusStep, + 0 as HasFocusSpeed, + 0 as MinFocusSpeed, + 0 as MaxFocusSpeed, + 0 as CanIris, + 0 as CanAutoIris, + 0 as CanIrisAbs, + 0 as CanIrisRel, + 0 as CanIrisCon, + 0 as MinIrisRange, + 0 as MaxIrisRange, + 0 as MinIrisStep, + 0 as MaxIrisStep, + 0 as HasIrisSpeed, + 0 as MinIrisSpeed, + 0 as MaxIrisSpeed, + 0 as CanGain, + 0 as CanAutoGain, + 0 as CanGainAbs, + 0 as CanGainRel, + 0 as CanGainCon, + 0 as MinGainRange, + 0 as MaxGainRange, + 0 as MinGainStep, + 0 as MaxGainStep, + 0 as HasGainSpeed, + 0 as MinGainSpeed, + 0 as MaxGainSpeed, + 0 as CanWhite, + 0 as CanAutoWhite, + 0 as CanWhiteAbs, + 0 as CanWhiteRel, + 0 as CanWhiteCon, + 0 as MinWhiteRange, + 0 as MaxWhiteRange, + 0 as MinWhiteStep, + 0 as MaxWhiteStep, + 0 as HasWhiteSpeed, + 0 as MinWhiteSpeed, + 0 as MaxWhiteSpeed, + 0 as HasPresets, + 0 as NumPresets, + 0 as HasHomePreset, + 0 as CanSetPresets, + 1 as CanMove, + 0 as CanMoveDiag, + 0 as CanMoveMap, + 0 as CanMoveAbs, + 0 as CanMoveRel, + 1 as CanMoveCon, + 1 as CanPan, + 0 as MinPanRange, + 0 as MaxPanRange, + 0 as MinPanStep, + 0 as MaxPanStep, + 1 as HasPanSpeed, + 0 as MinPanSpeed, + 5 as MaxPanSpeed, + 0 as HasTurboPan, + 0 as TurboPanSpeed, + 1 as CanTilt, + 0 as MinTiltRange, + 0 as MaxTiltRange, + 0 as MinTiltStep, + 0 as MaxTiltStep, + 1 as HasTiltSpeed, + 0 as MinTiltSpeed, + 5 as MaxTiltSpeed, + 0 as HasTurboTilt, + 0 as TurboTiltSpeed, + 0 as CanAutoScan, + 0 as NumScanPaths) AS tmp +WHERE NOT EXISTS ( + SELECT Name FROM Controls WHERE name = 'Vivotek ePTZ' +) LIMIT 1; From b611d9fcae619a662a7fb439218c9bb01bf721f9 Mon Sep 17 00:00:00 2001 From: Robin Daermann Date: Wed, 4 Nov 2015 17:29:37 +0100 Subject: [PATCH 3/5] Bump database version to 1.28.109 --- CMakeLists.txt | 2 +- configure.ac | 2 +- version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ea67474d6..c7be1ceec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ # cmake_minimum_required (VERSION 2.6) project (zoneminder) -set(zoneminder_VERSION "1.28.108") +set(zoneminder_VERSION "1.28.109") # make API version a minor of ZM version set(zoneminder_API_VERSION "${zoneminder_VERSION}.1") diff --git a/configure.ac b/configure.ac index 436be34cf..b9d4ef2ee 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ # For instructions on building with cmake, please see INSTALL # AC_PREREQ(2.59) -AC_INIT(zm,1.28.108,[http://www.zoneminder.com/forums/ - Please check FAQ first],zoneminder,http://www.zoneminder.com/downloads.html) +AC_INIT(zm,1.28.109,[http://www.zoneminder.com/forums/ - Please check FAQ first],zoneminder,http://www.zoneminder.com/downloads.html) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR(src/zm.h) AC_CONFIG_HEADERS(config.h) diff --git a/version b/version index ca2c9c84c..a960d2a6d 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.28.108 +1.28.109 From 1f1b48ed5137e33e026647f8e02825a33db29469 Mon Sep 17 00:00:00 2001 From: Robin Daermann Date: Wed, 4 Nov 2015 19:17:47 +0100 Subject: [PATCH 4/5] Added Vivotek ePTZ control to zm_create.sql --- db/zm_create.sql.in | 1 + 1 file changed, 1 insertion(+) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 53bfa1fa8..22c9af7f6 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -588,6 +588,7 @@ INSERT INTO Controls VALUES (NULL,'ONVIF Camera','Ffmpeg','onvif',0,0,1,1,0,0,0, INSERT INTO `Controls` VALUES (NULL,'Foscam 9831W','Ffmpeg','FI9831W',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,16,1,1,1,1,0,0,0,1,1,0,360,0,360,1,0,4,0,0,1,0,90,0,90,0,0,0,0,0,0,0); INSERT INTO `Controls` VALUES (NULL,'Foscam FI8918W','Ffmpeg','FI8918W',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,8,0,1,1,1,0,0,0,1,1,0,360,0,360,1,0,4,0,0,1,0,90,0,90,1,0,4,0,0,0,0); INSERT INTO `Controls` VALUES (NULL,'SunEyes SP-P1802SWPTZ','Libvlc','SPP1802SWPTZ',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,8,0,1,1,0,0,0,0,1,1,0,0,0,0,1,0,64,0,0,1,0,0,0,0,1,0,64,0,0,0,0); +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); From 49a89b75a851ddbbace2766b938e13c008a7052f Mon Sep 17 00:00:00 2001 From: Robin Daermann Date: Mon, 9 Nov 2015 16:15:53 +0100 Subject: [PATCH 5/5] More verbose error reporting --- scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm index b407a9bde..3649b35bc 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Vivotek_ePTZ.pm @@ -107,7 +107,7 @@ sub sendCmd printMsg( $speedcmd, "Tx" ); printMsg( $cmd, "Tx" ); - my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/cgi-bin/camctrl/eCamCtrl.cgi?stream=0&$speedcmd&$cmd" ); + my $req = HTTP::Request->new( GET => "http://" . $self->{Monitor}->{ControlAddress} . "/cgi-bin/camctrl/eCamCtrl.cgi?stream=0&$speedcmd&$cmd" ); my $res = $self->{ua}->request($req); if ( $res->is_success ) @@ -116,7 +116,7 @@ sub sendCmd } else { - Error( "Error check failed: '".$res->status_line()."'" ); + Error( "Request failed: '" . $res->status_line() . "' (URI: '" . $req->as_string() . "')" ); } return( $result );