China2MP IPCAM Zoneminder V1.25.0 running on Debian wheezy

Chinese 2 megapixel IP ONVIF camera with pan/tilt capabilities. It can connect to the wired or wireless network. 

The camera management is done in a web browser, in MS Windows, a specific plugin is needed to display the camera image in the browser.

Camera pan angle is 350 degrees, while the tilt angle is 90 degrees.

 

HTTP port: 80
RTSP port: 554
Onvif port: 1018

Image streams:
rtsp://:@192.168.1.172:554/11 - 1920*1080 (Main Stream)

rtsp://:@192.168.1.172:554/12 - 704*576 (Sub Stream)
rtsp://:@192.168.1.172:554/13 - 320*180 (Mobile Stream)

Camera commands:
Movement:
http://<IP>/cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=left
http://<IP>/cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=right
http://<IP>/cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=up
http://<IP>/cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=down
http://<IP>/cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=stop

Image controls:
http://<IP>/cgi-bin/hi3510/setvdisplayattr.cgi?&-hue=96&-brightness=50&-saturation=50&-contrast=50

Flip, Mirror, Powerfreq
http://<IP>/cgi-bin/hi35110/setvdisplayattr.cgi?&-flip=on&-mirror=off&-powerfreq=50

Auto, Indoor, Outdoor
http://<IP>/cgi-bin/hi3510/setvdisplayattr.cgi?&-scene=auto
http://<IP>/cgi-bin/hi3510/setvdisplayattr.cgi?&-scene=indoor
http://<IP>/cgi-bin/hi3510/setvdisplayattr.cgi?&-scene=outdoor

IRCut
http://<IP>/cgi-bin/hi3510/setvdisplayattr.cgi?&-ircutmode=1
(1=day&night; 2=color; 3=black&white)

Set ptz point 1-8
http://<IP>/cgi-bin/hi3510/ptzsetpoint.cgi?&-chn=0&-point=1

Go to ptz point 1-8
http://<IP>/cgi-bin/hi3510/ptzgotopoint.cgi?&-chn=0&-point=1

Clear ptz point 1-8
http://<IP>/cgi-bin/hi3510/ptzclearpoint.cgi?&-chn=0&-point=1

 

Interface with Zoneminder

For an unknown reason, even if the camera has a rtsp video stream, it can't be configured in Zoneminder to work as source type "Remote". The only way it works is as a "Ffmpeg" device. Zoneminder 1.25.0 does not allow us to define controls in Ffmpeg mode, so it is necessary to operate a few changes to the program.

Edit:
/usr/share/zoneminder/skins/classic/views/controlcap.php
at line 348 change
$types = array( 'Local'=>$SLANG['Local'], 'Remote'=>$SLANG['Remote'] );
into
$types = array( 'Local'=>$SLANG['Local'], 'Remote'=>$SLANG['Remote'] , 'Ffmpeg'=>$SLANG['Ffmpeg'] );

 Edit:
/usr/share/zoneminder/db/zm_create.sql
at line 66 change
`Type` enum('Local','Remote') NOT NULL default 'Local',
into
`Type` enum('Local','Remote','Ffmpeg') NOT NULL default 'Local',

Find section "Add in some sample control protocol definitions" and add:
(IPCAM2MP will be our new camera protocol)
insert into Controls values (7,'IPCAM2MP','Ffmpeg','IPCAM2MP',1,1,0,1,1,0,0,1,NULL,NULL,NULL,NULL,1,0,3,1,1,0,0,1, NULL,NULL,NULL,NULL,0,NULL,NULL,1,1,0,1,0,NULL,NULL,NULL,NULL,0,NULL,NULL, 0,0,0,0,0,NULL,NULL,NULL,NULL,0,NULL,NULL,1,1,0,1,0,NULL,NULL,NULL,NULL,0,NULL, NULL,1,20,1,1,1,1,0,0,0,1,1,NULL,NULL,NULL,NULL,1,0,63,1,254,1,NULL,NULL,NULL,NULL, 1,0,63,1,254,0,0);

In the database edit:
Controls/Indexes/Type and change the value from 'Local','Remote' to 'Local','Remote','Ffmpeg'

Create the new control script:
#touch /usr/share/perl5/ZoneMinder/Control/IPCAM2MP.pm

Insert the code below into the control script:

# ==========================================================================
#
# ZoneMinder IPCAM2MP Control Protocol Module, $Date: 2009-11-25 09:20:00 +0000 (Wed, 04 Nov 2009) $, $Revision: 0001 $
# Copyright (C) 2001-2008  Philip Coombes
#
# Modified for China 2MP NetIpCam camera by Radmilo Feliox n 2015-05-05 00:03:00
#
# 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 China 2MP NetIpCam camera
# control protocol.
#
# ==========================================================================
package ZoneMinder::Control::IPCAM2MP;

use 5.006;
use strict;
use warnings;

require ZoneMinder::Base;
require ZoneMinder::Control;

our @ISA = qw(ZoneMinder::Control);

our $VERSION = $ZoneMinder::Base::VERSION;

# ==========================================================================
#
# China 2MP NetIpCam Control Protocol
#
# ==========================================================================

use ZoneMinder::Logger qw(:all);
use ZoneMinder::Config qw(:all);
use Time::HiRes qw( usleep );

my $loopfactor=100000;

sub new
{
    my $class = shift;
    my $id = shift;
    my $self = ZoneMinder::Control->new( $id );
    my $logindetails = "";
    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/".ZM_VERSION );
    $self->{ua}->agent( "ZoneMinder Control Agent" );


    $self->{state} = 'open';
}

sub close
{
    my $self = shift;
    $self->{state} = 'closed';
}

sub sendCmd
{
    my $self = shift;
    my $cmd = shift;
    my $result = undef;
    my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd" );
    my $res = $self->{ua}->request($req);
    if ( $res->is_success )
    {
        $result = $res->decoded_content;
    }
    else
    {
        Error( "Error check failed: '".$res->status_line()."'" );
    }
    return( $result );
}

# Reboot camera
sub reset
{
    my $self = shift;
    Debug( "Camera Reset" );
    my $cmd = "cgi-bin/hi3510/sysreboot.cgi";
    $self->sendCmd( $cmd );
}

# Flip image on vertically
sub wake
{
    my $self = shift;
    Debug( "Flip on" );
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setvdisplayattr&-flip=on";
    $self->sendCmd( $cmd );
}


# Flip image off vertically
sub sleep
{
    my $self = shift;
    Debug( "Flip off" );
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setvdisplayattr&-flip=off";
    $self->sendCmd( $cmd );
}

sub moveConUp
{
    my $self = shift;
    my $params = shift;
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=up";
    $self->sendCmd( $cmd );
    my $autostop = $self->getParam( $params, 'autostop', 0 );
    if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
    {
        usleep( $self->{Monitor}->{AutoStopTimeout} );
        $self->moveStop( $params );
    }
    else
    {
    $self->moveStop( $params );
    }
}

sub moveConDown
{
    my $self = shift;
    my $params = shift;
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=down";
    $self->sendCmd( $cmd );
    my $autostop = $self->getParam( $params, 'autostop', 0 );
    if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
    {
        usleep( $self->{Monitor}->{AutoStopTimeout} );
        $self->moveStop( $params );
    }
    else
    {
    $self->moveStop( $params );
    }
}

sub moveConRight
{
    my $self = shift;
    my $params = shift;
    Debug( "Move Right" );
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=right";
    $self->sendCmd( $cmd );
    my $autostop = $self->getParam( $params, 'autostop', 0 );
    if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
    {
        usleep( $self->{Monitor}->{AutoStopTimeout} );
        $self->moveStop( $params );
    }
    else
    {
    $self->moveStop( $params );
    }
}

sub moveConLeft
{
    my $self = shift;
    my $params = shift;
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=left";
    $self->sendCmd( $cmd );
    my $autostop = $self->getParam( $params, 'autostop', 0 );
    if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
    {
        usleep( $self->{Monitor}->{AutoStopTimeout} );
        $self->moveStop( $params );
    }
    else
    {
    $self->moveStop( $params );
    }
}

# The camera can not move diagonally, so we will implement those movements in the next 4 subroutines:
sub moveConUpLeft
{
    my $self = shift;
    my $params = shift;
    my $loopcount=int($self->{Monitor}->{AutoStopTimeout}/$loopfactor);
    my $autostop = $self->getParam( $params, 'autostop', 0 );
    if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
    {
        while ( $loopcount  )
        {
             $loopcount--;
             my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=up";
             $self->sendCmd( $cmd );
             my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=left";
             $self->sendCmd( $cmd );

         }
        $self->moveStop( $params );
    }
}

sub moveConUpRight
{
   my $self = shift;
   my $params = shift;
   my $loopcount=int($self->{Monitor}->{AutoStopTimeout}/$loopfactor);
   my $autostop = $self->getParam( $params, 'autostop', 0 );
   if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
   {
         while ( $loopcount  )
         {
             $loopcount--;
             my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=up";
             $self->sendCmd( $cmd );
             my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=right";
             $self->sendCmd( $cmd );
         }
            $self->moveStop( $params );
  }
}

sub moveConDownRight
{
    my $self = shift;
    my $params = shift;
    my $loopcount=int($self->{Monitor}->{AutoStopTimeout}/$loopfactor);
    my $autostop = $self->getParam( $params, 'autostop', 0 );
    if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
    {
        while ( $loopcount  )
        {
            $loopcount--;
            my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=down";
            $self->sendCmd( $cmd );
            my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=right";
            $self->sendCmd( $cmd );
        }
        $self->moveStop( $params );
    }
}

sub moveConDownLeft
{
    my $self = shift;
    my $params = shift;
    my $loopcount=int($self->{Monitor}->{AutoStopTimeout}/$loopfactor);
    my $autostop = $self->getParam( $params, 'autostop', 0 );
    if ( $autostop && $self->{Monitor}->{AutoStopTimeout} )
    {
        while ( $loopcount  )
        {
            $loopcount--;
            my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=down";
            $self->sendCmd( $cmd );
            my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=left";
            $self->sendCmd( $cmd );
        }
        $self->moveStop( $params );
    }
}

sub moveStop
{
    my $self = shift;
    print("autostop\n");
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzctrl&-step=0&-speed=10&-act=stop";
    $self->sendCmd( $cmd );
}

sub getDisplayAttr
{
    my $self = shift;
    my $param = shift;
    my $cmdget = "cgi-bin/hi3510/param.cgi?cmd=getvdisplayattr&-brightness";
    my $resp = $self->sendCmd( $cmdget );
    my @buffer=split(';',$resp);
    my $response=$buffer[$param];
    my @buffer=split('"',$response);
    my $response=$buffer[1];
    return ($response);
}

# presetHome is used to normalize the brightness/contrast/hue/saturation values
sub presetHome
{
    my $self = shift;
    Debug( "Home Preset" );
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setvdisplayattr&-brightness=50&-contrast=50&-saturation=50&-hue=50";
    $self->sendCmd( $cmd );
}

sub presetSet
{
    my $self = shift;
    my $params = shift;
    my $preset = $self->getParam( $params, 'preset' );
    Debug( "Set Preset $preset " );
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzsetpoint&-chn=0&-point=$preset";
    $self->sendCmd( $cmd );
}

sub presetGoto
{
    my $self = shift;
    my $params = shift;
    my $preset = $self->getParam( $params, 'preset' );
    Debug( "Goto Preset $preset" );
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=ptzgotopoint&-chn=0&-point=$preset";
    $self->sendCmd( $cmd );
}

# Contrast control
sub whiteAbsIn
{
    my $self = shift;
    my $params = shift;
    Debug( "Contrast up" );
    my $dvalue=$self->getDisplayAttr(6);
    if ( $dvalue < 100 )
    {
    $dvalue=$dvalue+5;
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setvdisplayattr&-contrast=$dvalue";
    $self->sendCmd( $cmd );
    }
}

# Contrast control
sub whiteAbsOut
{
    my $self = shift;
    my $params = shift;
    Debug( "Contrast down" );
    my $dvalue=$self->getDisplayAttr(6);
    if ( $dvalue > 0 )
    {
    $dvalue=$dvalue-5;
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setvdisplayattr&-contrast=$dvalue";
    $self->sendCmd( $cmd );
    }
}

# Brightness control
sub irisAbsOpen
{
    my $self = shift;
    my $params = shift;
    Debug( "Brightness up" );
    my $dvalue=$self->getDisplayAttr(4);
    if ( $dvalue < 100 )
    {
    $dvalue=$dvalue+5;
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setvdisplayattr&-brightness=$dvalue";
    $self->sendCmd( $cmd );
    }
}

# Brightness control
sub irisAbsClose
{
    my $self = shift;
    my $params = shift;
    Debug( "Brightness down" );
    my $dvalue=$self->getDisplayAttr(4);
    if ( $dvalue > 0 )
    {
    $dvalue=$dvalue-5;
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setvdisplayattr&-brightness=$dvalue";
    $self->sendCmd( $cmd );
    }
}

# Saturation control
sub zoomAbsTele
{
    my $self = shift;
    my $params = shift;
    Debug( "Saturation up" );
    my $dvalue=$self->getDisplayAttr(5);
    if ( $dvalue < 100 )
    {
    $dvalue=$dvalue+5;
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setvdisplayattr&-saturation=$dvalue";
    $self->sendCmd( $cmd );
    }
}

# Saturation control
sub zoomAbsWide
{
    my $self = shift;
    my $params = shift;
    Debug( "Saturation down" );
    my $dvalue=$self->getDisplayAttr(5);
    if ( $dvalue > 0 )
    {
    $dvalue=$dvalue-5;
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setvdisplayattr&-saturation=$dvalue";
    $self->sendCmd( $cmd );
    }
}

# Hue control
sub focusAbsNear
{
    my $self = shift;
    my $params = shift;
    Debug( "Hue up" );
    my $dvalue=$self->getDisplayAttr(7);
    if ( $dvalue < 100 )
    {
    $dvalue=$dvalue+5;
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setvdisplayattr&-hue=$dvalue";
    $self->sendCmd( $cmd );
    }
}

# Hue control
sub focusAbsFar
{
    my $self = shift;
    my $params = shift;
    Debug( "Hue down" );
    my $dvalue=$self->getDisplayAttr(7);
    if ( $dvalue > 0 )
    {
    $dvalue=$dvalue-5;
    my $cmd = "cgi-bin/hi3510/param.cgi?cmd=setvdisplayattr&-hue=$dvalue";
    $self->sendCmd( $cmd );
    }
}

1;

Be shure that the name defined in the package statement, in the script, matches with the script filename (IPCAM2MP)

When working on the control script (changing/testing/debugging), have in mind that the control process (zmcontrol.pl) stays resident into memory even if the control monitor is closed and even if Zoneminder itself is stopped. So, every time, after making changes to the script, you have to kill the zmcontrol.pl process, otherwise there will be no changes in the script behaviour, as you will not be runing the new script, but a previous form of it from the memory.

The following controls are used for other purposes than defined in the graphic interface:
Wake button - Flip image vertically on;

Sleep button - Flip image vertically off;

Home button - Reset hue/saturation/contrast/brightness to normal values;

Focus controls - set hue value (5% increase/decrease);

Zoom controls - set saturation value (5% increase/decrease);

White controls - set contrast value (5% increase/decrease);

Iris controls - set brightness value (5% increase/decrease).

 

Monitor configuration:

    in the "General" tab, set Source Type to Ffmpeg.

    in the "Source" tab, set:
            Source Path to rtsp://<user>:<password>@192.168.1.172/11,
            Source Colours to 24 bit colour,
            Capture Width (pixels) to 1920,
            Capture Height (pixels) to 1080,

     in the "Control" tab, at Control type, click on the "Edit" link to create the new control.
        Click "Add New Control" button, in the new window set the following:
                "Main" tab:
                           Name-IPCAM2MP,
                           Type-Ffmpeg,
                           Protocol-IPCAM2MP,
                           Can Wake-tick
                           Can Sleep-tick
                           Can Reset-tick.
                "Move" tab:
                           Can Move-tick,
                           Can Move Diagonally-tick,
                           Can Move Continuous-tick,
                "Pan" tab: Can Pan-tick.
                 "Tilt" tab: Can Tilt-tick.
                 "Zoom" tab:
                           Can Zoom-tick
                           Can Zoom Absolute-tick
                 "Focus" tab:
                           Can Focus-tick
                           Can Focus Absolute-tick
                 "White" tab:
                           Can White Balance-tick
                           Can White Balance Absolute-tick
                 "Iris" tab:
                           Can Iris-tick
                           Can Iris Absolute-tick
                 "Presets" tab:
                           Has Presets-tick
                           Num Presets-8
                          
Has Home Preset-tick
                           Can Set Presets-tick

Hit "Save" button to save the settings, the new control should now be in the control capabilities list, close the ZM-Control Capabilities window.
      Back, in the "Control" tab:
           Controllable-tick,
           Select IPCAM2MP as control type (you will have to close the monitor and open it again for the new control to be shown in the drop-down list),
           Control Device-username:password,
           Control Address-192.168.1.172:80,
           AutoStopTimeout-0.20.

Save and that's all.

 

 

 

 

Add comment


Security code
Refresh