Sumpple S610 PTZ control module

If you've made a patch to quick fix a bug or to add a new feature not yet in the main tree then post it here so others can try it out.
Post Reply
eurcew
Posts: 1
Joined: Wed Feb 12, 2020 5:31 pm

Sumpple S610 PTZ control module

Post by eurcew »

I was unable to find an existing module for the Sumpple S610 so I've created my own and thought I'd share it here. Perl is not one of my main languages so this may not be optimally coded - feel free to suggest any changes.

Instructions for use are at the bottom of the code

Code: Select all

# ==========================================================================
#
# ZoneMinder Sumpple S610 Control Protocol Module
# Copyright (C) C Ward 2/2020
#
# Based largely on the following work:
# amcrest841.pm by alabamatoy
# onvif.pm by Jan M. Hochstein
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# ==========================================================================
#
# This module contains the implementation of the Sumpple S610 device control
# protocol
#
# Research showed that the sumpple camera is based on APM-H803-MPC
# This is also used in many other cameras.
# This script may also work on other cameras.
# Try http://<my_cam>//cgi-bin/get_status.cgi
# no uid / pwd required.  If you get "var ret_prot_mode='APM-H803-MPC';" 
# then this should work.
#
# http://www.apexis.sk/download/CGI/Apexis%20H.264%20CGI%20document.pdf
#
# ==========================================================================
# type=0 (ordinary PTZ operating cmd: 0-20)
# cmd Order type description
# 0 Up
# 1 Down
# 2 Left
# 3 Right
# 4 Short focal distance
# 5 Long focal distance
# 6 short Optical zoom
# 7 long Optical zoom
# 8 open aperture
# 9 close aperture
# 10 Stop
# 11 Auto open
# 12 Auto close
# 13 Upleft
# 14 Downleft
# 15 Upright
# 16 Downright
# 17 Level rotation
# 18 Vertical rotation
# 19 Stop level rotation
# 20 Stop vertical rotation
# type=1 (set preset position)
# cmd Set preset position number 0-31
# type=2 (call preset position)
# cmd Call preset position number 0-31
# type=3(relay operating)
# cmd Relay 0:close 1:open

# tested with camera where UI states 10 presets.  API supported 32
package ZoneMinder::Control::sumpple;

use 5.006;
use strict;
use warnings;

require ZoneMinder::Control;

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

our %CamParams = ();

# ==========================================================================
#
# Sumpple Control Protocol
#
# On ControlDevice use the format :
#   USERNAME:PASSWORD
#   eg : admin:pwd
#        zoneminder:zonepass
#
# On ControlAddress use the format :
#   ADDRESS:PORT
#   eg : 10.1.2.1:80
#        10.0.100.1:40000
#
# ==========================================================================

use ZoneMinder::Logger qw(:all);
use ZoneMinder::Config qw(:all);

use Time::HiRes qw( usleep );

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 sendCmd {
  my $self = shift;
  my $p1 = shift;
  my $p2 = shift;
  my $result = undef;

  my ($user, $password) = split /:/, $self->{Monitor}->{ControlDevice};

  if ( !defined $password ) {
      # If value of "Control device" does not consist of two parts, then only password is given and we fallback to default user:
      $password = $user;
      $user = 'admin';
  }

  my $cmd = "http://".$self->{Monitor}->{ControlAddress}.
      "/cgi-bin/decoder_control.cgi?type=$p1&cmd=$p2&onestep=1&user=$user&pwd=$password";

  # $cmd = "http://".$self->{Monitor}->{ControlAddress}."/".$cmd;

  Info("url :".$cmd);

  my $req = HTTP::Request->new(GET=>$cmd);
  my $res = $self->{ua}->request($req);

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

  return $result;
}

sub moveConUp
{
  my $self = shift;
  Debug( "Move Up" );
  $self->sendCmd(0, 0);
}

#Down Arrow
sub moveConDown
{
  my $self = shift;
  Debug( "Move Down" );
  $self->sendCmd( 0, 1 );
}

#Left Arrow
sub moveConLeft
{
  my $self = shift;
  Debug( "Move Left" );
  $self->sendCmd(0, 2);
}

#Right Arrow
sub moveConRight
{
  my $self = shift;
  Debug( "Move Right" );
  $self->sendCmd( 0, 3 );
}

# Zoom In
sub zoomConTele
{
  my $self = shift;
  Debug( "Zoom Tele" );
  $self->sendCmd( 0,6 );
}

# Zoom Out
sub zoomConWide
{
  my $self = shift;
  Debug( "Zoom Wide" );
  $self->sendCmd( 0, 7 );
}

#Stop
sub moveStop
{
  my $self = shift;
  Debug( "Move Stop" );
  $self->sendCmd(0, 10);
}

#Diagonally Up Left Arrow
sub moveConUpLeft
{
  my $self = shift;
  Debug( "Move Right" );
  $self->sendCmd(0, 13);
}

#Diagonally Down Left Arrow
sub moveConDownLeft
{
  my $self = shift;
  Debug( "Move Right" );
  $self->sendCmd(0, 14);
}

#Diagonally Up Right Arrow
sub moveConUpRight
{
  my $self = shift;
  Debug( "Move Right" );
  $self->sendCmd(0, 15);
}

#Diagonally Down Right Arrow
sub moveConDownRight
{
  my $self = shift;
  Debug( "Move Right" );
  $self->sendCmd(0, 16);
}

#Set Camera Preset
#Presets must be translated into values internal to the camera
#Those values are: 0-31 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 )) {
    $self->sendCmd(1, ($preset - 1));
  }
}

#Recall Camera Preset
#Presets must be translated into values internal to the camera
#Those values are: 0-1 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 )) {
    $self->sendCmd(2, ($preset - 1));
  }

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


1;

__END__
=pod

=head1 NAME

ZoneMinder::Control::sumpple - S610 camera control

=head1 DESCRIPTION

NOTE: This module implements interaction with the camera in clear text.
It is not possible to get around this.  The login and password are
transmitted from ZM to the camera in clear text, and as such, this module
should be used ONLY on a blind LAN implementation where interception of the
packets is very low risk.

Copy the file sumpple.pm to /usr/share/perl5/ZoneMinder/Control folder.
This is where it belongs in Ubuntu 18.04, your setup may be different.

Next, in the camera monitor, under the control tab, select "Controllable".

Select "edit" beside the "Control Type" text box, and a new window will open,
click on "ADD NEW CONTROL" and give it whatever name you want, I used
"Sumpple".  Select "TYPE as "FFMPEG" and "PROTOCOL" as "sumpple".
Leave the rest unchecked.

Under the "Move" tab, select "CAN MOVE, "CAN MOVE DIAGONALLY" and "CAN MOVE CONTINUOUS".
Under the "Pan" tab, select "CAN PAN".
Under the "Tilt" tab, select "CAN TILT".
Under the "Zoom" tab, select "CAN ZOOM" and "CAN ZOOM CONTINUOUS".
Under "Presets" tab, select "HAS PRESETS", I used 32 for num presets,
but your camera documentation should tell you how many you actually can have  (the UI lists 10, but the doc 32),
also select "CAN SET PRESETS".
Click on "SAVE" at the bottom.  You should have a new control capability listed
with whatever name you gave it.

Set "Control Type" to whatever you named the new control.  This choice
should be listed as one available in the pulldown.  You may need to close and
reopen the monitor config window

Set "Control Address" to "ip_address:port" where ip_address is the camera
IP.  Port is optional.  Please be mindful of NOTE above.

Set "Control Device" to be "login:password".  This will be appended to each http
call to the camera

Save the monitor.

=cut
Post Reply