Si están buscando la mejor manera de deshacerse de una buena cantidad de dinero en el modo más inútil, les aconsejo vivamente comprar una cámara D-Link DSC-5222L. No tiene nada de nuevo. Una calidad bastante triste. Lenta. Para compensar toda esta la depresión y no sentirnos tan solos en el mundo de los estafados existe un remedio: ZoneMinder.
ZoneMinder es una solución open source que tal vez no sea la más completa de todas, pero es muy simple de instalar, configurar y utilizar. Hoy, no vamos a explicar nada de esto, que tan bien explicado está en los manuales de ZoneMinder.
Comfigurar y agregar una cámara D-Link DSC-5222L a ZoneMinder y poder comandarla desde la interfáz web.
Con la cámara viene un antiguo CD con el software que configura todo con dos clicks. Claro, es necesario tener un lector y Windows (y un mouse para hacer los clicks). Si nos falta una de estas cosas, podemos simplemente conectarnos a la cámara a través de la dirección IP 192.168.0.20 e ingresar con el usuario admin sin contraseña.
Una vez dentro, configurar los siguientes puntos:
Entrar a la web de ZoneMinder e ingresar a add new monitor. Por ahora, configurar los siguientes parámetros:
Una vez configurados estos parámetros, ya deberíamos poder acceder al video de la D-Link. Si así no fuera, probar los parámetros remote host name y path en un browser para estar seguros de que el canal de video sea accesible.
Lamentablemente, ZoneMinder no entenderá como controlar este modelo de cámara. Sí otras que son mejores, pero esta no. Para controlar la DSC-5222L será necesario primero cargar un script que le permitirá a ZoneMinder "conocer" los controles de la cámara.
En mi caso, ZoneMinder está instalado en un CentOS. La ubicación de los archivos puede cambiar de distribución a distribución. Para encontrar la que corresponde en nuestra instalación, podemos ejecutar:
find / -name "PanasonicIP.pm"
En el caso de CentOS, la ubicación es: /usr/share/perl5/vendor_perl/ZoneMinder/Control. Dentro este directorio creamos el archivo DCS_5222LB.pm
# =========================================================================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::DCS_5222LB;
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( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$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";
#action=move&direction=rightup&panstep=1&tiltstep=1
my $cmd = "cgi-bin/longcctvmove.cgi?action=move&direction=$dir&panstep=$panSteps&tiltstep=$tiltSteps";
$self->sendCmd( $cmd );
}
sub moveRelUpLeft
{
my $self = shift;
Debug( "Move Up Left" );
$self->move( "leftup", 1, 1 );
}
sub moveRelUp
{
my $self = shift;
Debug( "Move Up" );
$self->move( "up", 1, 1 );
}
sub moveRelUpRight
{
my $self = shift;
Debug( "Move Up" );
$self->move( "rightup", 1, 1 );
}
sub moveRelLeft
{
my $self = shift;
Debug( "Move Left" );
$self->move( "left", 1, 1 );
}
sub moveRelRight
{
my $self = shift;
Debug( "Move Right" );
$self->move( "right", 1, 1 );
}
sub moveRelDownLeft
{
my $self = shift;
Debug( "Move Down" );
$self->move( "leftdown", 1, 1 );
}
sub moveRelDown
{
my $self = shift;
Debug( "Move Down" );
$self->move( "down", 1, 1 );
}
sub moveRelDownRight
{
my $self = shift;
Debug( "Move Down" );
$self->move( "rightdown", 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 = "upleft";
} elsif ($hor >= 50 && $ver < 50) {
# up right
$horSteps = ($hor - 50) / $f;
$verSteps = (50 - $ver) / $f;
$direction = "upright";
} elsif ($hor < 50 && $ver >= 50) {
# down left
$horSteps = (50 - $hor) / $f;
$verSteps = ($ver - 50) / $f;
$direction = "downleft";
} elsif ($hor >= 50 && $ver >= 50) {
# down right
$horSteps = ($hor - 50) / $f;
$verSteps = ($ver - 50) / $f;
$direction = "downright";
}
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 = "cgi-bin/longcctvhome.cgi?action=gohome";
$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
Una vez cargado el script será necesario agregarlo a la lista de controladores de ZoneMinder. Entrar en la cámara cargada y seleccionar la pestaña control. Tildar la opción controllable y hacer click en edit al costado del select del control type.
En la parte inferior de la ventana emergente, hacer click en add new control y configurar los siguientes parámetros:
Una vez configurado todo, seleccionar el nuevo controller type en la ventana de la cámara y configurar el campo control address con admin:password@ip_camara