Difference between revisions of "D-Link DCS-5020L Control Script"
From ZoneMinder Wiki
Jump to navigationJump to search
(Change control package name from Dlink-DCS5020L to DCS5020L.) |
m (Fix: -->Bareword "VERSION" not allowed while "strict subs" in use at test.pm line 82) |
||
(2 intermediate revisions by 2 users not shown) | |||
Line 3: | Line 3: | ||
# | # | ||
# 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 24: | Line 25: | ||
# | # | ||
package ZoneMinder::Control::DCS5020L; | 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> | |||
=head1 COPYRIGHT AND LICENSE | =head1 COPYRIGHT AND LICENSE | ||
LGPLv3 | LGPLv3 | ||
=cut | =cut | ||
</pre> | </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