D-Link 5020L e ZoneMinder

 D-Link 5020L e ZoneMinder

D-Link 5020L e ZoneMinder. Guida su come configurare ZoneMinder con telecamere D.Link 5020L Nel wiki di ZoneMinder si trovano i riferimenti a tutte le telecamere supportate, comprese queste, ma in questa guida ci saranno immagini per tutti i passaggi. I parametri da inserire quando si aggiunge la telecamera sono i seguenti:

Source Type: Remote
Remote Protocol: HTTP
Remote Method: Simple
Remote Host Name: user:pass@IP-Camera
Remote Host Port: 80 (Default)
Remote Host Path: /video.cgi
Colors: 24 bit
Capture width: 640
Capture Height: 480

D-Link 5020L e ZoneMinderD-Link 5020L e ZoneMinder

 

PTZ Settings:

esiste uno script nel wiki che serve a far funzionare il tutto:

# =========================================================================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

e va copiato nel PATH: /usr/share/perl5/ZoneMinder/Control. Dopodichè andare nel menu Control-Edit-Add New Control:

DLink 5020L e ZoneMinder

ed inserire i parametri  seguenti:

Main: Type: Remote, Protocol: DCS5020L, Name: DCS5020L, Can Wake, Can Sleep, Can Reset
Move: Can Move, Can Move Diagonally, Can Move Mapped, Can Move Relative
Pan: Can Pan, Min Pan Step 1, Max Pan Step 30
Tilt: Can Tilt, Min Tilt Step 1, Max Pan Step 30
Presets: Has Presets, Number: 24, Has Home Preset

Nel Tab Control inserire:

Controllable, Control Type: DCS5020L, Control address: user:pass@ipaddress

D-Link 5020L e ZoneMinder

D-Link 5020L e ZoneMinder

adesso tutto è pronto per la video sorveglianza.

enjoy 😉

 

Zoneminder su Raspberry pi 3 B+ Raspbian Stretch

Zoneminder su Raspberry pi 3 B+ Raspbian Stretch

Zoneminder su Raspberry pi 3 B+ Raspbian Stretch

Con l’arrivo del nuovo Raspberry pi 3 B+ nella mia collezione, ho deciso di dedicarlo alla video sorveglianza installando Zoneminder. Per avere delle ottime performance, è necessrio avere una sd card performante, io ho optato per una SanDisk Extreme PRO 64GB, MicroSDXC Classe 10. Si può anche utilizzare un ssd esterno come capiente storage. Tutti i comandi sotto saranno eseguiti come root:

# apt update; apt upgrade -y
# apt install -y build-essential openssh-server apache2 mysql-server mysql-client bison flex php php7.0-curl php7.0-cli php7.0-mysql php-pear php7.0-gd curl sox libncurses5-dev libssl-dev mpg123 libxml2-dev libnewt-dev sqlite3 libsqlite3-dev libasound2-dev libogg-dev libapache2-mod-php7.0 sendmail ffmpeg vlc vlc-data zoneminder
# rm -rf /etc/mysql/my.cnf
# cp /etc/mysql/mariadb.conf.d/50-server.cnf /etc/mysql/my.cnf
# nano /etc/mysql/my.cnf

ed aggiungere:

sql_mode = NO_ENGINE_SUBSTITUTION

come sotto:

# * Basic Settings
#
user            = mysql
sql_mode = NO_ENGINE_SUBSTITUTION
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
port            = 3306
basedir         = /usr
datadir         = /var/lib/mysql
tmpdir          = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
# systemctl restart mysql

mettere in sicurezza mysql

# mysql_secure_installation
# service mariadb restart
# systemctl status mariadb.service

Creazione del database:

# mysql -uroot -p < /usr/share/zoneminder/db/zm_create.sql
# mysql -uroot -p -e "grant all on zm.* to 'zmuser'@localhost identified by 'zmpass';"
# mysqladmin -uroot -p reload
# chmod 740 /etc/zm/zm.conf
# chown root:www-data /etc/zm/zm.conf
# adduser www-data video
# a2enmod cgi
# a2enconf zoneminder
# a2enmod rewrite
# systemctl restart apache2
# chown -R www-data:www-data /usr/share/zoneminder/
# systemctl enable zoneminder
# service zoneminder start

per evitare errori modificare il file php.ini aggiungendo Europe/Rome nella sezione Module Settings:

# nano /etc/php/7.0/apache2/php.ini

date.timezone = Europe/Rome

# systemctl restart apache2

a questo punto zoneminder sarà raggiungibile all’indirizzo http://ip_seerver/zm

Per utilizzare un ssd esterno come storage, bisogna configurare /etc/fstab per il montaggio automatico:

# systemctl stop zoneminder
# mkdir -p /ssd/zoneminder/events/
# rm -rf /var/cache/zoneminder/events/
# nano /etc/fstab

ed aggiungere qualcosa del genere:

/dev/sdX1 /ssd ext4 defaults 0 2
/ssd/zoneminder/images /var/cache/zoneminder/images none defaults,bind  0 2
/ssd/zoneminder/events /var/cache/zoneminder/events none defaults,bind 0 2

per poter scrivere sul nuovo storage:

# chown -R www-data:www-data /ssd/zoneminder/
# reboot

Zoneminder su Raspberry pi 3 B+ Raspbian Stretch

al riavvio tutto dovrebbe funzionare, e si potrà procedere alla configurazione di Zoneminder

enjoy 😉