Difference between revisions of "D-Link DCS-5020L Control Script"

From ZoneMinder Wiki
Jump to navigationJump to search
m (Fix: -->Bareword "VERSION" not allowed while "strict subs" in use at test.pm line 82)
 
(3 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 23: Line 24:
# protocol.  
# protocol.  
#
#
package ZoneMinder::Control::DLink-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
 
Nobody
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 08: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