Difference between revisions of "D-Link DCS-5020L Control Script"
From ZoneMinder Wiki
Jump to navigationJump to search
Utahjarhead (talk | contribs) |
m (Fix: -->Bareword "VERSION" not allowed while "strict subs" in use at test.pm line 82) |
||
| (5 intermediate revisions by 2 users not shown) | |||
| Line 1: | Line 1: | ||
<pre> | |||
# =========================================================================r | # =========================================================================r | ||
# | # | ||
# ZoneMinder D-Link DCS-5020L IP Control Protocol Module, $Date: $, $Revision: $ | # ZoneMinder D-Link DCS-5020L IP Control Protocol Module, $Date: $, $Revision: $ | ||
# Copyright (C) 2013 Art Scheel | |||
# | # | ||
# This program is free software; you can redistribute it and/or | # This program is free software; you can redistribute it and/or | ||
| Line 23: | Line 24: | ||
# protocol. | # protocol. | ||
# | # | ||
package ZoneMinder::Control:: | package ZoneMinder::Control::DCS5020L; | ||
use 5.006; | use 5.006; | ||
use strict; | use strict; | ||
use warnings; | use warnings; | ||
require ZoneMinder::Base; | require ZoneMinder::Base; | ||
require ZoneMinder::Control; | require ZoneMinder::Control; | ||
our @ISA = qw(ZoneMinder::Control); | our @ISA = qw(ZoneMinder::Control); | ||
our $VERSION = $ZoneMinder::Base::VERSION; | our $VERSION = $ZoneMinder::Base::VERSION; | ||
# ========================================================================== | # ========================================================================== | ||
# | # | ||
| Line 41: | Line 42: | ||
# | # | ||
# ========================================================================== | # ========================================================================== | ||
use ZoneMinder::Logger qw(:all); | use ZoneMinder::Logger qw(:all); | ||
use ZoneMinder::Config qw(:all); | use ZoneMinder::Config qw(:all); | ||
use Time::HiRes qw( usleep ); | use Time::HiRes qw( usleep ); | ||
sub new | sub new | ||
{ | { | ||
| Line 56: | Line 57: | ||
return $self; | return $self; | ||
} | } | ||
our $AUTOLOAD; | our $AUTOLOAD; | ||
sub AUTOLOAD | sub AUTOLOAD | ||
{ | { | ||
| Line 71: | Line 72: | ||
Fatal( "Can't access $name member of object of class $class" ); | Fatal( "Can't access $name member of object of class $class" ); | ||
} | } | ||
sub open | sub open | ||
{ | { | ||
my $self = shift; | my $self = shift; | ||
$self->loadMonitor(); | $self->loadMonitor(); | ||
use LWP::UserAgent; | use LWP::UserAgent; | ||
$self->{ua} = LWP::UserAgent->new; | $self->{ua} = LWP::UserAgent->new; | ||
$self->{ua}->agent( "ZoneMinder Control Agent/".ZM_VERSION ); | $self->{ua}->agent( "ZoneMinder Control Agent/" . ZoneMinder::Base::ZM_VERSION ); | ||
$self->{state} = 'open'; | $self->{state} = 'open'; | ||
} | } | ||
sub close | sub close | ||
{ | { | ||
| Line 90: | Line 90: | ||
$self->{state} = 'closed'; | $self->{state} = 'closed'; | ||
} | } | ||
sub printMsg | sub printMsg | ||
{ | { | ||
| Line 96: | Line 96: | ||
my $msg = shift; | my $msg = shift; | ||
my $msg_len = length($msg); | my $msg_len = length($msg); | ||
Debug( $msg."[".$msg_len."]" ); | Debug( $msg."[".$msg_len."]" ); | ||
} | } | ||
sub sendCmd | sub sendCmd | ||
{ | { | ||
my $self = shift; | my $self = shift; | ||
my $cmd = shift; | my $cmd = shift; | ||
my $result = undef; | my $result = undef; | ||
printMsg( $cmd, "Tx" ); | printMsg( $cmd, "Tx" ); | ||
my $req = HTTP::Request->new( POST=>"http://".$self->{Monitor}->{ControlAddress}."/PANTILTCONTROL.CGI" ); | my $req = HTTP::Request->new( POST=>"http://".$self->{Monitor}->{ControlAddress}."/PANTILTCONTROL.CGI" ); | ||
$req->content($cmd); | $req->content($cmd); | ||
my $res = $self->{ua}->request($req); | my $res = $self->{ua}->request($req); | ||
if ( $res->is_success ) | if ( $res->is_success ) | ||
{ | { | ||
| Line 121: | Line 121: | ||
Error( "Error check failed: '".$res->status_line()."'" ); | Error( "Error check failed: '".$res->status_line()."'" ); | ||
} | } | ||
return( $result ); | return( $result ); | ||
} | } | ||
sub sendCmd2 | |||
{ | |||
my $self = shift; | |||
my $cmd = shift; | |||
my $result = undef; | |||
printMsg( $cmd, "Tx" ); | |||
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd".$self->{Monitor}->{ControlDevice} ); | |||
my $res = $self->{ua}->request($req); | |||
if ($res->is_success ) | |||
{ | |||
$result = !undef; | |||
} | |||
else | |||
{ | |||
Error( "Error check failed:'".$res->status_line()."'" ); | |||
} | |||
return( $result ); | |||
} | |||
sub move | sub move | ||
{ | { | ||
| Line 131: | Line 154: | ||
my $panSteps = shift; | my $panSteps = shift; | ||
my $tiltSteps = shift; | my $tiltSteps = shift; | ||
my $cmd = "PanSingleMoveDegree=$panSteps&TiltSingleMoveDegree=$tiltSteps&PanTiltSingleMove=$dir"; | my $cmd = "PanSingleMoveDegree=$panSteps&TiltSingleMoveDegree=$tiltSteps&PanTiltSingleMove=$dir"; | ||
$self->sendCmd( $cmd ); | $self->sendCmd( $cmd ); | ||
} | } | ||
sub moveRelUpLeft | sub moveRelUpLeft | ||
{ | { | ||
| Line 142: | Line 165: | ||
$self->move( 0, 1, 1 ); | $self->move( 0, 1, 1 ); | ||
} | } | ||
sub moveRelUp | sub moveRelUp | ||
{ | { | ||
| Line 149: | Line 172: | ||
$self->move( 1, 1, 1 ); | $self->move( 1, 1, 1 ); | ||
} | } | ||
sub moveRelUpRight | sub moveRelUpRight | ||
{ | { | ||
| Line 156: | Line 179: | ||
$self->move( 2, 1, 1 ); | $self->move( 2, 1, 1 ); | ||
} | } | ||
sub moveRelLeft | sub moveRelLeft | ||
{ | { | ||
| Line 163: | Line 186: | ||
$self->move( 3, 1, 1 ); | $self->move( 3, 1, 1 ); | ||
} | } | ||
sub moveRelRight | sub moveRelRight | ||
{ | { | ||
| Line 170: | Line 193: | ||
$self->move( 5, 1, 1 ); | $self->move( 5, 1, 1 ); | ||
} | } | ||
sub moveRelDownLeft | sub moveRelDownLeft | ||
{ | { | ||
| Line 177: | Line 200: | ||
$self->move( 6, 1, 1 ); | $self->move( 6, 1, 1 ); | ||
} | } | ||
sub moveRelDown | sub moveRelDown | ||
{ | { | ||
| Line 184: | Line 207: | ||
$self->move( 7, 1, 1 ); | $self->move( 7, 1, 1 ); | ||
} | } | ||
sub moveRelDownRight | sub moveRelDownRight | ||
{ | { | ||
| Line 191: | Line 214: | ||
$self->move( 8, 1, 1 ); | $self->move( 8, 1, 1 ); | ||
} | } | ||
# moves the camera to center on the point that the user clicked on in the video image. | # moves the camera to center on the point that the user clicked on in the video image. | ||
# This isn't extremely accurate but good enough for most purposes | # This isn't extremely accurate but good enough for most purposes | ||
| Line 198: | Line 221: | ||
# if the camera moves too much or too little, try increasing or decreasing this value | # if the camera moves too much or too little, try increasing or decreasing this value | ||
my $f = 11; | my $f = 11; | ||
my $self = shift; | my $self = shift; | ||
my $params = shift; | my $params = shift; | ||
my $xcoord = $self->getParam( $params, 'xcoord' ); | my $xcoord = $self->getParam( $params, 'xcoord' ); | ||
my $ycoord = $self->getParam( $params, 'ycoord' ); | my $ycoord = $self->getParam( $params, 'ycoord' ); | ||
my $hor = $xcoord * 100 / $self->{Monitor}->{Width}; | my $hor = $xcoord * 100 / $self->{Monitor}->{Width}; | ||
my $ver = $ycoord * 100 / $self->{Monitor}->{Height}; | my $ver = $ycoord * 100 / $self->{Monitor}->{Height}; | ||
| Line 236: | Line 259: | ||
$self->move( $direction, $h, $v ); | $self->move( $direction, $h, $v ); | ||
} | } | ||
# this clear function works, but should probably be disabled because | # this clear function works, but should probably be disabled because | ||
# it isn't possible to set presets yet. | # it isn't possible to set presets yet. | ||
| Line 248: | Line 271: | ||
$self->sendCmd( $cmd ); | $self->sendCmd( $cmd ); | ||
} | } | ||
# not working yet | # not working yet | ||
sub presetSet | sub presetSet | ||
| Line 260: | Line 283: | ||
#$self->sendCmd( $cmd ); | #$self->sendCmd( $cmd ); | ||
} | } | ||
sub presetGoto | sub presetGoto | ||
{ | { | ||
| Line 270: | Line 293: | ||
$self->sendCmd( $cmd ); | $self->sendCmd( $cmd ); | ||
} | } | ||
sub presetHome | sub presetHome | ||
{ | { | ||
| Line 278: | Line 301: | ||
$self->sendCmd( $cmd ); | $self->sendCmd( $cmd ); | ||
} | } | ||
# IR Controls | |||
# | |||
# wake = IR on | |||
# sleep = IR off | |||
# reset = IR auto | |||
sub wake | |||
{ | |||
my $self = shift; | |||
Debug( "Wake - IR on" ); | |||
my $cmd = "setDaynightMode?ReplySuccessPage=night.htm&ReplyErrorPage=errrnight.htm&DayNightMode=3&ConfigDayNightMode=Save"; | |||
$self->sendCmd2( $cmd ); | |||
} | |||
sub sleep | |||
{ | |||
my $self = shift; | |||
Debug( "Sleep - IR off" ); | |||
my $cmd = "setDaynightMode?ReplySuccessPage=night.htm&ReplyErrorPage=errrnight.htm&DayNightMode=2&ConfigDayNightMode=Save"; | |||
$self->sendCmd2( $cmd ); | |||
} | |||
sub reset | |||
{ | |||
my $self = shift; | |||
Debug( "Reset - IR auto" ); | |||
my $cmd = "setDaynightMode?ReplySuccessPage=night.htm&ReplyErrorPage=errrnight.htm&DayNightMode=0&ConfigDayNightMode=Save"; | |||
$self->sendCmd2( $cmd ); | |||
} | |||
1; | 1; | ||
__END__ | __END__ | ||
# Below is stub documentation for your module. You'd better edit it! | # Below is stub documentation for your module. You'd better edit it! | ||
=head1 NAME | =head1 NAME | ||
ZoneMinder::Database - Perl extension for DCS-5020L | ZoneMinder::Database - Perl extension for DCS-5020L | ||
=head1 SYNOPSIS | =head1 SYNOPSIS | ||
use ZoneMinder::Database; | use ZoneMinder::Database; | ||
DLINK DCS-5020L | DLINK DCS-5020L | ||
=head1 DESCRIPTION | =head1 DESCRIPTION | ||
ZoneMinder driver for the D-Link consumer camera DCS-5020L. | ZoneMinder driver for the D-Link consumer camera DCS-5020L. | ||
=head2 EXPORT | =head2 EXPORT | ||
None by default. | None by default. | ||
=head1 SEE ALSO | =head1 SEE ALSO | ||
See if there are better instructions for the DCS-5020L at | See if there are better instructions for the DCS-5020L at | ||
http://www.zoneminder.com/wiki/index.php/Dlink | http://www.zoneminder.com/wiki/index.php/Dlink | ||
=head1 AUTHOR | =head1 AUTHOR | ||
Art Scheel <lt>ascheel (at) gmail<gt> | Art Scheel <lt>ascheel (at) gmail<gt> | ||
=head1 COPYRIGHT AND LICENSE | =head1 COPYRIGHT AND LICENSE | ||
LGPLv3 | LGPLv3 | ||
=cut | =cut | ||
</pre> | |||
Latest revision as of 07:38, 25 August 2015
# =========================================================================r
#
# ZoneMinder D-Link DCS-5020L IP Control Protocol Module, $Date: $, $Revision: $
# Copyright (C) 2013 Art Scheel
#
# 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 D-Link DCS-5020L IP camera control
# protocol.
#
package ZoneMinder::Control::DCS5020L;
use 5.006;
use strict;
use warnings;
require ZoneMinder::Base;
require ZoneMinder::Control;
our @ISA = qw(ZoneMinder::Control);
our $VERSION = $ZoneMinder::Base::VERSION;
# ==========================================================================
#
# D-Link DCS-5020L 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 );
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();
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 $self = shift;
my $msg = shift;
my $msg_len = length($msg);
Debug( $msg."[".$msg_len."]" );
}
sub sendCmd
{
my $self = shift;
my $cmd = shift;
my $result = undef;
printMsg( $cmd, "Tx" );
my $req = HTTP::Request->new( POST=>"http://".$self->{Monitor}->{ControlAddress}."/PANTILTCONTROL.CGI" );
$req->content($cmd);
my $res = $self->{ua}->request($req);
if ( $res->is_success )
{
$result = !undef;
}
else
{
Error( "Error check failed: '".$res->status_line()."'" );
}
return( $result );
}
sub sendCmd2
{
my $self = shift;
my $cmd = shift;
my $result = undef;
printMsg( $cmd, "Tx" );
my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd".$self->{Monitor}->{ControlDevice} );
my $res = $self->{ua}->request($req);
if ($res->is_success )
{
$result = !undef;
}
else
{
Error( "Error check failed:'".$res->status_line()."'" );
}
return( $result );
}
sub move
{
my $self = shift;
my $dir = shift;
my $panSteps = shift;
my $tiltSteps = shift;
my $cmd = "PanSingleMoveDegree=$panSteps&TiltSingleMoveDegree=$tiltSteps&PanTiltSingleMove=$dir";
$self->sendCmd( $cmd );
}
sub moveRelUpLeft
{
my $self = shift;
Debug( "Move Up Left" );
$self->move( 0, 1, 1 );
}
sub moveRelUp
{
my $self = shift;
Debug( "Move Up" );
$self->move( 1, 1, 1 );
}
sub moveRelUpRight
{
my $self = shift;
Debug( "Move Up" );
$self->move( 2, 1, 1 );
}
sub moveRelLeft
{
my $self = shift;
Debug( "Move Left" );
$self->move( 3, 1, 1 );
}
sub moveRelRight
{
my $self = shift;
Debug( "Move Right" );
$self->move( 5, 1, 1 );
}
sub moveRelDownLeft
{
my $self = shift;
Debug( "Move Down" );
$self->move( 6, 1, 1 );
}
sub moveRelDown
{
my $self = shift;
Debug( "Move Down" );
$self->move( 7, 1, 1 );
}
sub moveRelDownRight
{
my $self = shift;
Debug( "Move Down" );
$self->move( 8, 1, 1 );
}
# moves the camera to center on the point that the user clicked on in the video image.
# This isn't extremely accurate but good enough for most purposes
sub moveMap
{
# if the camera moves too much or too little, try increasing or decreasing this value
my $f = 11;
my $self = shift;
my $params = shift;
my $xcoord = $self->getParam( $params, 'xcoord' );
my $ycoord = $self->getParam( $params, 'ycoord' );
my $hor = $xcoord * 100 / $self->{Monitor}->{Width};
my $ver = $ycoord * 100 / $self->{Monitor}->{Height};
my $direction;
my $horSteps;
my $verSteps;
if ($hor < 50 && $ver < 50) {
# up left
$horSteps = (50 - $hor) / $f;
$verSteps = (50 - $ver) / $f;
$direction = 0;
} elsif ($hor >= 50 && $ver < 50) {
# up right
$horSteps = ($hor - 50) / $f;
$verSteps = (50 - $ver) / $f;
$direction = 2;
} elsif ($hor < 50 && $ver >= 50) {
# down left
$horSteps = (50 - $hor) / $f;
$verSteps = ($ver - 50) / $f;
$direction = 6;
} elsif ($hor >= 50 && $ver >= 50) {
# down right
$horSteps = ($hor - 50) / $f;
$verSteps = ($ver - 50) / $f;
$direction = 8;
}
my $v = int($verSteps + .5);
my $h = int($horSteps + .5);
Debug( "Move Map to $xcoord,$ycoord, hor=$h, ver=$v with direction $direction" );
$self->move( $direction, $h, $v );
}
# this clear function works, but should probably be disabled because
# it isn't possible to set presets yet.
sub presetClear
{
my $self = shift;
my $params = shift;
my $preset = $self->getParam( $params, 'preset' );
Debug( "Clear Preset $preset" );
my $cmd = "ClearPosition=$preset";
$self->sendCmd( $cmd );
}
# not working yet
sub presetSet
{
my $self = shift;
my $params = shift;
my $preset = $self->getParam( $params, 'preset' );
Debug( "Set Preset $preset" );
# TODO need to first get current position $horPos and $verPos
#my $cmd = "PanTiltHorizontal=$horPos&PanTiltVertical=$verPos&SetName=$preset&SetPosition=$preset";
#$self->sendCmd( $cmd );
}
sub presetGoto
{
my $self = shift;
my $params = shift;
my $preset = $self->getParam( $params, 'preset' );
Debug( "Goto Preset $preset" );
my $cmd = "PanTiltPresetPositionMove=$preset";
$self->sendCmd( $cmd );
}
sub presetHome
{
my $self = shift;
Debug( "Home Preset" );
my $cmd = "PanTiltSingleMove=4";
$self->sendCmd( $cmd );
}
# IR Controls
#
# wake = IR on
# sleep = IR off
# reset = IR auto
sub wake
{
my $self = shift;
Debug( "Wake - IR on" );
my $cmd = "setDaynightMode?ReplySuccessPage=night.htm&ReplyErrorPage=errrnight.htm&DayNightMode=3&ConfigDayNightMode=Save";
$self->sendCmd2( $cmd );
}
sub sleep
{
my $self = shift;
Debug( "Sleep - IR off" );
my $cmd = "setDaynightMode?ReplySuccessPage=night.htm&ReplyErrorPage=errrnight.htm&DayNightMode=2&ConfigDayNightMode=Save";
$self->sendCmd2( $cmd );
}
sub reset
{
my $self = shift;
Debug( "Reset - IR auto" );
my $cmd = "setDaynightMode?ReplySuccessPage=night.htm&ReplyErrorPage=errrnight.htm&DayNightMode=0&ConfigDayNightMode=Save";
$self->sendCmd2( $cmd );
}
1;
__END__
# Below is stub documentation for your module. You'd better edit it!
=head1 NAME
ZoneMinder::Database - Perl extension for DCS-5020L
=head1 SYNOPSIS
use ZoneMinder::Database;
DLINK DCS-5020L
=head1 DESCRIPTION
ZoneMinder driver for the D-Link consumer camera DCS-5020L.
=head2 EXPORT
None by default.
=head1 SEE ALSO
See if there are better instructions for the DCS-5020L at
http://www.zoneminder.com/wiki/index.php/Dlink
=head1 AUTHOR
Art Scheel <lt>ascheel (at) gmail<gt>
=head1 COPYRIGHT AND LICENSE
LGPLv3
=cut