Apexis

From ZoneMinder Wiki
Revision as of 16:16, 27 June 2012 by Marcusbrutus (talk | contribs) (Add Auto Stop Timeout)
Jump to navigationJump to search

Apexis J12 IP Camera

Remote Protocol: HTTP
Remote Method: Simple
Remote Host Name: <ip of camera>
Remote Host Port: 80
Remote Host Path: videostream.cgi?user=<USERNAME>&pwd=<PASSWORD>
Remote Image colors: 24 bit
Capture Width: 640
Capture Height: 480

It is recommended to set Max FPS to 20.

Apexis APM-J011-WS IP Camera

Remote Protocol: HTTP
Remote Method: Simple
Remote Host Name: <IP_ADDRESS_OF_CAMERA>
Remote Host Port: 80
Remote Host Path: videostream.cgi?user=<USERNAME>&pwd=<PASSWORD>
Remote Image colors: 24 bit
Capture Width: 640
Capture Height: 480

Maximum frame rate this IP web camera can handle is 15 fps at 640x480. The <USERNAME> and <PASSWORD> are found in the "Users Settings" section of the IP Camera's web setup page. Pan Tilt Control is not available in Zoneminder 1.25.0 at this time (Feb 2012.) This IP camera does not have a zoom function, only pan and tilt.

Apexis APM-J901-Z-WS PTZ IP Wireless/Wired Camera

Apexis APM-J901-Z-WS

Features

Wired and Wireless Ethernet. 802.11b/g with WEP & WPA WPA2 encryption
3x Optical zoom
POE
DDNS
Supports VLC (apparenty!)
Supports MSN
Supports Firefox/Chrome (ie: Push-mode)
Two-way audio capable (microphone and speaker not included)
FTP uploads
Email alerts


Settings

Source
Remote Protocol HTTP
Remote Method Simple
Remote Host Name <IP_ADDRESS_OF_CAMERA>
Remote Host Port 80
Remote Host Path videostream.cgi?user=<USERNAME>&pwd=<PASSWORD>

or
snapshot.cgi?user=<USERNAME>&pwd=<PASSWORD>&resolution=32&rate=0

Remote Image colors 24 bit
Capture Width 640
Capture Height 480
Control
Controllable
Error creating thumbnail: Unable to save thumbnail to destination
Control Type Apexis Mjpeg IP (Select Edit to access Control Capabilities)
Control Address admin::@<IP_ADDRESS_OF_CAMERA>
Auto Stop Timeout 0.10


Control Capability - Apexis Mjpeg IP
Main
Name Apexis Mjpeg IP
Type Remote
Protocol ApexisMjpegIP (Refer to control protocol below)
Can Reset
Error creating thumbnail: Unable to save thumbnail to destination
Move
Can Move
Error creating thumbnail: Unable to save thumbnail to destination
Can Move Continuous
Error creating thumbnail: Unable to save thumbnail to destination
Pan
Can Pan
Error creating thumbnail: Unable to save thumbnail to destination
Tilt
Can Tilt
Error creating thumbnail: Unable to save thumbnail to destination
Zoom
Can Zoom
Error creating thumbnail: Unable to save thumbnail to destination
Can Zoom Continuous
Error creating thumbnail: Unable to save thumbnail to destination
Presets
Has Presets
Error creating thumbnail: Unable to save thumbnail to destination
Num Presets 8 (to be confirmed)
Can Set Presets
Error creating thumbnail: Unable to save thumbnail to destination


Control protocol for Apexis MJPEG Cameras

Save the following code as /usr/share/perl5/ZoneMinder/Control/ApexisMjpegIP.pm
Don't forget to set the user and password as I haven't figured that bit out yet ;).

# ==========================================================================
#
# ZoneMinder Apexis MJPEG IP Camera Control Protocol Module
# Copyright (C) 2012 Marcus Brown
# Shamefully copied from the Loftek module by Philip Coombes
#
# 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 Apexis MJPEG IP camera control
# protocol
#
package ZoneMinder::Control::ApexisMjpegIP;

use 5.006;
use strict;
use warnings;

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

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

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

our %CamParams = ();

# ==========================================================================
#
# Apexis MJPEG IP Control Protocol
#
# On ControlAddress use the format :
#   USERNAME:PASSWORD@ADDRESS:PORT
#   eg : admin:@10.1.2.1:80
#        zoneminder:zonepass@10.0.100.1:40000
#
# ==========================================================================

# Change "ZoneMinder::Logger" to "ZoneMinder::Debug" for zoneminder < 1.25.0
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 );
    my $logindetails = "";
    bless( $self, $class );
    srand( time() );
    return $self;
}

our $AUTOLOAD;

sub AUTOLOAD
{
    my $self = shift;
    my $class = ref( ) || 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->{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" );

    # ############################################################################################
    #
    #  CHANGE THE FOLLOWING LINE IF NECESSARY
    #  IT SHOULD WORK WITH A DEFAULT CAMERA, BUT SURELY YOU WILL BE SETTING AN ADMIN PASSWORD? :)
    #  
    # ############################################################################################
    my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/$cmd\&user=admin\&pwd="  );
    my $res = $self->{ua}->request($req);

    if ( $res->is_success )
    {
        $result = !undef;
    }
    else
    {
        Error( "Error check failed:'".$res->status_line()."'" );
    }

    return( $result );
}

sub getCamParams
{
    my $self = shift;

    my $req = HTTP::Request->new( GET=>"http://".$self->{Monitor}->{ControlAddress}."/get_params.cgi" );
    my $res = $self->{ua}->request($req);

    if ( $res->is_success )
    {
        # Parse results setting values in %FCParams
        my $content = $res->decoded_content;

        while ($content =~ s/var\s+([^=]+)=([^;]+);//ms) {
            $CamParams{$1} = $2;
        }
    }
    else
    {
        Error( "Error check failed:'".$res->status_line()."'" );
    }
}

#autoStop
#This makes use of the ZoneMinder Auto Stop Timeout on the Control Tab
sub autoStop
{
    my $self = shift;
    my $stop_command = shift;
    my $autostop = shift;
    if( $stop_command && $autostop)
    {
        Debug( "Auto Stop" );
        usleep( $autostop );
        my $cmd = "decoder_control.cgi?command=".$stop_command;
        $self->sendCmd( $cmd );
    }

}

# Reset the Camera
sub reset
{
    my $self = shift;
    Debug( "Camera Reset" );
    my $cmd = "reboot.cgi?";
    $self->sendCmd( $cmd );
}

#Up Arrow
sub moveConUp
{
    my $self = shift;
    my $stop_command = "1";
    Debug( "Move Up" );
    my $cmd = "decoder_control.cgi?command=0";
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}

#Down Arrow
sub moveConDown
{
    my $self = shift;
    my $stop_command = "3";
    Debug( "Move Down" );
    my $cmd = "decoder_control.cgi?command=2";
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}

#Left Arrow
sub moveConLeft
{
    my $self = shift;
    my $stop_command = "5";
    Debug( "Move Left" );
    my $cmd = "decoder_control.cgi?command=4";
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}

#Right Arrow
sub moveConRight
{
    my $self = shift;
    my $stop_command = "7";
    Debug( "Move Right" );
    my $cmd = "decoder_control.cgi?command=6";
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}

#####################################################################################
# Single-step movements
#

# 'onestep' and 'degree' don't appear to work for the J901

sub moveRelUp
{
    my $self = shift;
    Debug( "Move Up" );
    my $cmd = "decoder_control.cgi?command=0&onestep=1";
    $self->sendCmd( $cmd );
}
#~ #~
sub moveRelDown
{
    my $self = shift;
    Debug( "Move Down" );
    my $cmd = "decoder_control.cgi?command=2&onestep=1";
    $self->sendCmd( $cmd );
}
#~ #~
sub moveRelLeft
{
    my $self = shift;
    Debug( "Move Left" );
    my $cmd = "decoder_control.cgi?command=4&onestep=1";
    $self->sendCmd( $cmd );
}
#~ #~
sub moveRelRight
{
    my $self = shift;
    Debug( "Move Right" );
    my $cmd = "decoder_control.cgi?command=6&onestep=1";
    $self->sendCmd( $cmd );
}

#This camera does not have builtin diagonal commands so we emulate them
sub moveRelUpRight
{
    my $self = shift;
    Debug( "Step Diagonally Up Right" );
    $self->stepConUp( );
    $self->stepConRight( );
}
#~ #~
sub moveRelDownRight
{
    my $self = shift;
    Debug( "Step Diagonally Down Right" );
    $self->stepConDown( );
    $self->stepConRight( );
}
#~ #~
sub moveRelUpLeft
{
    my $self = shift;
    Debug( "Step Diagonally Up Left" );
    $self->stepConUp( );
    $self->stepConLeft( );
}
#~ #~
sub moveRelDownLeft
{
    my $self = shift;
    Debug( "Step Diagonally Down Left" );
    $self->stepConDown( );
    $self->stepConLeft( );
}

#
#####################################################################################
# Iris/Aperture control ... this is *NOT* 'iris' as 'brightness' ?
#
# Doubt this works on J901

sub irisConClose
{
    my $self = shift;
    my $stop_command = "8";
    Debug( "Focus Near" );
    my $cmd = "decoder_control.cgi?command=9";
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}
#~ #~
sub irisConOpen
{
    my $self = shift;
    my $stop_command = "10";
    Debug( "Focus Near" );
    my $cmd = "decoder_control.cgi?command=11";
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}

#
#####################################################################################
# Focus control
#
# J901 is manual focus

sub focusConNear
{
    my $self = shift;
    my $stop_command = "13";
    Debug( "Focus Near" );
    my $cmd = "decoder_control.cgi?command=12";
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}
#~ #~
sub focusConFar
{
    my $self = shift;
    my $stop_command = "15";
    Debug( "Focus Near" );
    my $cmd = "decoder_control.cgi?command=14";
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}


#
#####################################################################################

#Zoom In
sub zoomConTele
{
    my $self = shift;
    my $stop_command = "19";
    Debug( "Zoom Tele" );
    my $cmd = "decoder_control.cgi?command=18";
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}

#~ #Zoom Out
sub zoomConWide
{
    my $self = shift;
    my $stop_command = "17";
    Debug( "Zoom Wide" );
    my $cmd = "decoder_control.cgi?command=16";
    $self->sendCmd( $cmd );
    $self->autoStop( $stop_command, $self->{Monitor}->{AutoStopTimeout} );
}

#~ #Diagonally Up Right Arrow
#This camera does not have builtin diagonal commands so we emulate them
sub moveConUpRight
{
    my $self = shift;
    Debug( "Move Diagonally Up Right" );
    $self->moveConUp( );
    $self->moveConRight( );
}

#Diagonally Down Right Arrow
#This camera does not have builtin diagonal commands so we emulate them
sub moveConDownRight
{
    my $self = shift;
    Debug( "Move Diagonally Down Right" );
    $self->moveConDown( );
    $self->moveConRight( );
}
#~
#Diagonally Up Left Arrow
#This camera does not have builtin diagonal commands so we emulate them
sub moveConUpLeft
{
    my $self = shift;
    Debug( "Move Diagonally Up Left" );
    $self->moveConUp( );
    $self->moveConLeft( );
}
#~
#Diagonally Down Left Arrow
#This camera does not have builtin diagonal commands so we emulate them
sub moveConDownLeft
{
    my $self = shift;
    Debug( "Move Diagonally Down Left" );
    $self->moveConDown( );
    $self->moveConLeft( );
}

#Stop
#~ sub moveStop
#~ {
    #~ my $self = shift;
    #~ Debug( "Move Stop" );
    #~ my $cmd = "decoder_control.cgi?command=1";
    #~ $self->sendCmd( $cmd );
#~ }

#Set Camera Preset
#Presets must be translated into values internal to the camera
#Those values are: 30,32,34 ... 88,90,92 for presets 1-32 respectively
sub presetSet
{
    my $self = shift;
    my $params = shift;
    my $preset = $self->getParam( $params, 'preset' );
    Debug( "Set Preset $preset" );
#~
    if (( $preset >= 1 ) && ( $preset <= 32 )) {
        my $cmd = "decoder_control.cgi?command=".(($preset*2) + 28);
        $self->sendCmd( $cmd );
    }
}

#Recall Camera Preset
#Presets must be translated into values internal to the camera
#Those values are: 31,33,35 ... 89,91,93 for presets 1-32 respectively
sub presetGoto
{
    my $self = shift;
    my $params = shift;
    my $preset = $self->getParam( $params, 'preset' );
    Debug( "Goto Preset $preset" );
#~
    if (( $preset >= 1 ) && ( $preset <= 32 )) {
        my $cmd = "decoder_control.cgi?command=".(($preset*2) + 29);
        $self->sendCmd( $cmd );
    }

    #~ if ( $preset == 9 ) {
        #~ $self->horizontalPatrol();
    #~ }
    #~ if ( $preset == 10 ) {
        #~ $self->horizontalPatrolStop();
    #~ }
}

#~ sub presetHome
#~ {
    #~ my $self = shift;
    #~ Debug( "Home Preset" );
    #~ my $cmd = "decoder_control.cgi?command=25";
    #~ $self->sendCmd( $cmd );
#~ }

#Horizontal Patrol - Vertical Patrols are not supported
sub horizontalPatrol
{
    my $self = shift;
    Debug( "Horizontal Patrol" );
    my $cmd = "decoder_control.cgi?command=20";
    $self->sendCmd( $cmd );
}

#Horizontal Patrol Stop
sub horizontalPatrolStop
{
    my $self = shift;
    Debug( "Horizontal Patrol Stop" );
    my $cmd = "decoder_control.cgi?command=21";
    $self->sendCmd( $cmd );
}

# Set Absolute Brightness
#~ sub setAbsBrightness
#~ {
    #~ my $self = shift;
    #~ my $brightness = shift;
    #~ $brightness = 255 if $brightness > 255;
    #~ $brightness = 0   if $brightness < 0;
    #~ Debug( "Setting brightness to $brightness" };
    #~ $CamParams{'brightness'} = $brightness;
    #~ my $cmd = "camera_control.cgi?param=1&value=".$brightness;
    #~ $self->sendCmd( $cmd );
#~ }

# Increase Brightness
#~ sub irisAbsOpen
#~ {
    #~ my $self = shift;
    #~ my $params = shift;
    #~ $self->getCamParams() unless($CamParams{'brightness'});
    #~ my $step = $self->getParam( $params, 'step' );
#~
    #~ $CamParams{'brightness'} += $step;
    #~ $CamParams{'brightness'} = 255 if ($CamParams{'brightness'} > 255);
    #~ Debug( "Iris $CamParams{'brightness'}" );
    #~ my $cmd = "camera_control.cgi?param=1&value=".$CamParams{'brightness'};
    #~ $self->sendCmd( $cmd );
#~ }

# Decrease Brightness
#~ sub irisAbsClose
#~ {
    #~ my $self = shift;
    #~ my $params = shift;
    #~ $self->getCamParams() unless($CamParams{'brightness'});
    #~ my $step = $self->getParam( $params, 'step' );
#~
    #~ $CamParams{'brightness'} -= $step;
    #~ $CamParams{'brightness'} = 0 if ($CamParams{'brightness'} < 0);
    #~ Debug( "Iris $CamParams{'brightness'}" );
    #~ my $cmd = "camera_control.cgi?param=1&value=".$CamParams{'brightness'};
    #~ $self->sendCmd( $cmd );
#~ }

# Set Absolute Contrast
#~ sub setAbsContrast
#~ {
    #~ my $self = shift;
    #~ my $contrast = shift;
    #~ $contrast = 255 if $contrast > 255;
    #~ $contrast = 0   if $contrast < 0;
    #~ Debug( "Setting contrast to $contrast" };
    #~ $CamParams{'contrast'} = $contrast;
    #~ my $cmd = "camera_control.cgi?param=2&value=".$contrast;
    #~ $self->sendCmd( $cmd );
#~ }

# Increase Contrast
#~ sub whiteAbsIn
#~ {
    #~ my $self = shift;
    #~ my $params = shift;
    #~ $self->getCamParams() unless($CamParams{'contrast'});
    #~ my $step = $self->getParam( $params, 'step' );
#~
    #~ $CamParams{'contrast'} += $step;
    #~ $CamParams{'contrast'} = 6 if ($CamParams{'contrast'} > 6);
    #~ Debug( "Contrast $CamParams{'contrast'}" );
    #~ my $cmd = "camera_control.cgi?param=2&value=".$CamParams{'contrast'};
    #~ $self->sendCmd( $cmd );
#~ }

# Decrease Contrast
#~ sub whiteAbsOut
#~ {
    #~ my $self = shift;
    #~ my $params = shift;
    #~ $self->getCamParams() unless($CamParams{'contrast'});
    #~ my $step = $self->getParam( $params, 'step' );
#~
    #~ $CamParams{'contrast'} -= $step;
    #~ $CamParams{'contrast'} = 0 if ($CamParams{'contrast'} < 0);
    #~ Debug( "Iris $CamParams{'contrast'}" );
    #~ my $cmd = "camera_control.cgi?param=2&value=".$CamParams{'contrast'};
    #~ $self->sendCmd( $cmd );
#~ }

1;