Here is the code. Sorry folks, I don't really have a place to host this that is open to the world and I'm not much of a fan of the public hosting sites. If anyone has the spare bandwidth to host this in a file format that can be publicly accessible, please feel free to host.
#!/usr/bin/perl -wT
#
#
# ==========================================================================
#
# ZoneMinder Sony SNC-RN50 Control Script, $Date: 2006/04/18 08:53:15 $, $Revision: .3 $
# Copyright (C) 2006 Glenn Neufeld
#
# Adapted From:
#
# ZoneMinder VISCA Control Script, $Date: 2005/07/14 08:53:15 $, $Revision: 1.6 $
# Copyright (C) 2003, 2004, 2005 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.
#
# ==========================================================================
use strict;
#use Switch;
# ==========================================================================
#
# These are the elements you need to edit to suit your installation
#
# ==========================================================================
use constant DBG_ID => "zmctrl-sncrz50"; # Tag that appears in debug to identify source
use constant DBG_LEVEL => 0; # 0 is errors, warnings and info only, > 0 for debug
# ==========================================================================
use ZoneMinder;
use Getopt::Long;
use LWP::UserAgent;
$| = 1;
$ENV{PATH} = '/bin:/usr/bin';
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
sub Usage
{
print( "
Usage: zmcontrol-SNC-RN50.pl <various>
");
exit( -1 );
}
zmDbgInit( DBG_ID, level=>DBG_LEVEL );
# Values that need to be initialized with a value of 0
my ($currentPan, $currentTilt, $currentSpeed, $speed, $step,
$xcoord, $ycoord, $panspeed, $tiltspeed, $panstep,
$tiltstep, $preset ) = 0;
my $arg_string = join( " ", @ARGV );
# Uncomment for error log debug
#print STDERR "ARGS = $arg_string\n";
# Initialize the remaining variables
my ($device, $command, $height, $width);
# ==============================================================
# Must be set statically at this time
my $address = "user:pass\@somedomain.com:80";
# ==============================================================
# Massive array of http commands and possible args:
my %cameraCommands = (
'move_map' => '$evalString = "/command/ptzf.cgi?AreaZoom=$xcoord,$ycoord,0,0,jpeg"',
'move_abs_up' => '$evalString = "/command/ptzf.cgi?Move=up,0"',
'move_abs_down' => '$evalString = "/command/ptzf.cgi?Move=down,0"',
'move_abs_left' => '$evalString = "/command/ptzf.cgi?Move=left,0"',
'move_abs_right' => '$evalString = "/command/ptzf.cgi?Move=right,0"',
'move_abs_upleft' => '$evalString = "/command/ptzf.cgi?Move=up-left,0"',
'move_abs_upright' => '$evalString = "/command/ptzf.cgi?Move=up-right,0"',
'move_abs_downleft' => '$evalString = "/command/ptzf.cgi?Move=down-left,0"',
'move_abs_downright' => '$evalString = "/command/ptzf.cgi?Move=down-right,0"',
'move_stop' => '$evalString = "/command/ptzf.cgi?Move=stop,motor"',
'zoom_rel_tele' => '$evalString = "/command/ptzf.cgi?Move=tele,8"',
'zoom_rel_wide' => '$evalString = "/command/ptzf.cgi?Move=wide,8"',
'preset_home' => '$evalString = "/command/presetposition.cgi?HomePos=ptz-recall"',
);
if ( !GetOptions(
'device=s'=>\$device,
'address=i'=>\$address,
'command=s'=>\$command,
'speed=i'=>\$speed,
'step=i'=>\$step,
'xcoord=i'=>\$xcoord,
'ycoord=i'=>\$ycoord,
'height=i'=>\$height,
'width=i'=>\$width,
'panspeed=i'=>\$panspeed,
'tiltspeed=i'=>\$tiltspeed,
'panstep=i'=>\$panstep,
'tiltstep=i'=>\$tiltstep,
'preset=i'=>\$preset
)
)
{
Usage();
}
# In order to map the coordinates correctly,
# we need to map according to the camera's
# relative coordinates
$xcoord-=320;
$ycoord-=240;
srand( time() );
# Given a zm_command, execute it using http commo to the camera
sub doCommand
{
my $httpCommand;
#my $command = @_;
Debug ("doCommand => " . $command."\n");
$httpCommand = $cameraCommands{ $command };
#Debug("doCommand => " . $httpCommand . "\n" );
#print( $httpCommand . "\n" );
if ( $httpCommand )
{
my $result = "";
my $a = "";
my $evalString = "";
#eval($httpCommand);
# Uncomment for error log debug
#print STDERR "$evalString\n";
$httpCommand = "http://$address" . eval($httpCommand);
#$httpCommand =~ s/ //g;
my $ua = LWP::UserAgent->new;
$ua->agent( "ZoneMinder Control Agent/".ZM_VERSION );
Debug( $httpCommand );
# Uncomment for error log debug
#print STDERR "The full command = $httpCommand\n";
my $req = HTTP::Request->new( GET=>$httpCommand );
my $res = $ua->request($req);
print( $res->as_string );
if ( $res->is_success )
{
$result = !undef;
}
else
{
Error( "doCommand => Error check failed: '".$res->status_line()."'\n" );
}
# In order to use this camera, we need to issue a stop command
# after each command is sent. This mimics the Java applet
my $stop;
if ($httpCommand =~ /(.*)tele(.*)/ || $httpCommand =~ /(.*)wide(.*)/)
{
sleep 1;
$stop = "/command/ptzf.cgi?Move=stop,zoom";
}
else
{
$stop = "/command/ptzf.cgi?Move=stop,motor";
}
my $stopCommand = "http://$address" . $stop;
my $s_req = HTTP::Request->new( GET=>$stopCommand );
my $s_res = $ua->request($s_req);
print( $result."\n" );
}
else
{
{ Debug("Error, can't handle command $command\n")}
}
}
sub getCurrentPTZData
{
my $currentPos = "";
my $ua = LWP::UserAgent->new;
$ua->agent( "ZoneMinder Control Agent/".ZM_VERSION );
#my $req = HTTP::Request->new( GET=>"http://$address/command/ptzf.cgi?AbsolutePanTilt=5,5,5" );
#my $res = $ua->request($req);
#print($res->as_string);
my $req = HTTP::Request->new( GET=>"http://$address/command/inquiry.cgi?inq=ptzf" );
my $res = $ua->request($req);
#print($res->as_string);
if ( $res->is_success )
{
# print($res->as_string . "\n");
$currentPos = $res->content;
Debug( $currentPos );
$currentPos =~ s/AbsolutePanTilt\=// ;
$currentPos =~ s/\n// ;
$currentPos =~ s/\r// ;
Debug( $currentPos );
my @xy = split( /,/ , $currentPos);
Debug( @xy );
$currentPan = $xy[0];
$currentTilt = $xy[1];
#chop($currentTilt);
#Debug( "Read Current Cam Position As: (".$currentPan.",".$currentTilt.")..." );
#print( "Read Current Cam Position As: (".$xy[0].",".$xy[1].")\n");
#print( $xy[0] . "\n");
#print( $xy[1] . "\n");
#$result = !undef;
}
else
{
Error( "getPTZ... => Error check failed: '".$res->status_line()."'\n" );
}
}
# Usage here, too
if ( $command eq "" )
{
Usage();
}
Debug( "Passed => " . $arg_string . "\n" );
# Read the absolute pan and tilt and speed values from the camera
getCurrentPTZData;
A# If relative...
# Relative values idea of positive and negative are weird - figure them out.
# pan and tilt speed are send - disable them in camera control setup page?
# Also, diagonal movement is strange. Different with pan/tilt speeds available?
# Should I ignore the speeds entirely?
#$tiltstep = abs($tiltstep);
#$panstep = abs($panstep);
# If absolute...
# Check passed params and normalize or default them
if ( !$tiltstep ) { $tiltstep = $currentTilt };
if ( !$panstep ) { $panstep = $currentPan };
if ( !$tiltspeed ) { $tiltspeed = 10 };
if ( !$panspeed ) { $panspeed = 10 };
# Run it
doCommand( $command );
#########################################
# The following information is not used #
# by the Sony SNC-RN50 #
# with this script but are left in #
# for future development #
#########################################
#'reset' => '$evalString = "/adm/file.cgi?next_file=camera.htm&todo=save&h_v_mode=mpeg"',
# RESET/SLEEP sets MPEG mode to play nice with IE users of this Camera.
#'sleep' => '$evalString = "/adm/file.cgi?next_file=camera.htm&todo=save&h_v_mode=mpeg"',
# WAKE should put the camera into JPEG mode for ZM.
#'wake' => '$evalString = "/adm/file.cgi?next_file=camera.htm&todo=save&h_v_mode=jpeg"',
#'move_con_up' => '$evalString = "/command/ptzf.cgi?Move=up,$speed"',
#'move_con_down' => '$evalString = "/command/ptzf.cgi?Move=down,0"',
#'move_con_left' => '$evalString = "/command/ptzf.cgi?Move=left,0"',
#'move_con_right' => '$evalString = "/command/ptzf.cgi?Move=right,0"',
#'move_con_upleft' => '$evalString = "/command/ptzf.cgi?Move=up-left,0"',
#'move_con_upright' => '$evalString = "/command/ptzf.cgi?Move=up-right,0"',
#'move_con_downleft' => '$evalString = "/command/ptzf.cgi?Move=down-left,0"',
#'move_con_downright' => '$evalString = "/command/ptzf.cgi?Move=down-right,0"',
#'move_abs_upleft' => quotemeta("function($panstep, $tiltstep, $panspeed, $tiltspeed)"),
#'move_abs_upright' => quotemeta("function($panstep, $tiltstep, $panspeed, $tiltspeed)"),
#'move_abs_downleft' => quotemeta("function($panstep, $tiltstep, $panspeed, $tiltspeed)"),
#'move_abs_downright' => quotemeta("function($panstep, $tiltstep, $panspeed, $tiltspeed)"),
#'move_rel_up' => '$evalString = "/command/ptzf.cgi?RelativePanTilt=0,$tiltstep,$tiltspeed"',
#'move_rel_down' => '$evalString = "/command/ptzf.cgi?RelativePanTilt=0,-$tiltstep,$tiltspeed"',
#'move_rel_left' => '$evalString = "/command/ptzf.cgi?RelativePanTilt=-$panstep,0,$panspeed"',
#'move_rel_right' => '$evalString = "/command/ptzf.cgi?RelativePanTilt=$panstep,0,$panspeed"',
#'move_rel_upleft' => '$evalString = "/command/ptzf.cgi?RelativePanTilt=$panstep,$tiltstep,$tiltspeed"',
#'move_rel_upright' => '$evalString = "/command/ptzf.cgi?RelativePanTilt=$panstep,$tiltstep,$tiltspeed"',
#'move_rel_downleft' => '$evalString = "/command/ptzf.cgi?RelativePanTilt=$panstep,$tiltstep,$tiltspeed"',
#'move_rel_downright' => '$evalString = "/command/ptzf.cgi?RelativePanTilt=$panstep,$tiltstep,$tiltspeed"',
#'move_abs_up' => '$evalString = "/command/ptzf.cgi?AbsolutePanTilt=$currentPan,$tiltstep,$tiltspeed"',
#'move_abs_down' => '$evalString = "/command/ptzf.cgi?AbsolutePanTilt=$currentPan,$tiltstep,$tiltspeed"',
#'move_abs_left' => '$evalString = "/command/ptzf.cgi?AbsolutePanTilt=$panstep,$currentTilt,$panspeed"',
#'move_abs_right' => '$evalString = "/command/ptzf.cgi?AbsolutePanTilt=$panstep,$currentTilt,$panspeed"',
#up, down = tiltstep, tiltspeed
#right, left = panstep, panspeed
#'zoom_con_tele' => quotemeta("function($speed)"),
#'zoom_con_wide' => quotemeta("function($speed)"),
#'zoom_stop' => quotemeta("function()"),
#'zoom_abs_wide' => quotemeta("function($step)"),
#'zoom_abs_tele' => quotemeta("function($step)"),
#'focus_con_near' => quotemeta("function()"),
#'focus_con_far' => quotemeta("function()"),
#'focus_stop' => quotemeta("function()"),
#'focus_rel_near' => quotemeta("function($step)"),
#'focus_rel_far' => quotemeta("function($step)"),
#'focus_abs_near' => quotemeta("function($step)"),
#'focus_abs_far' => quotemeta("function($step)"),
#'focus_auto' => quotemeta("function()"),
#'focus_man' => quotemeta("function()"),
#'white_con_in' => quotemeta("function()"),
#'white_con_out' => quotemeta("function()"),
#'white_stop' => quotemeta("function()"),
#'white_rel_in' => quotemeta("function()"),
#'white_rel_out' => quotemeta("function()"),
#'white_auto' => quotemeta("function()"),
#'white_man' => quotemeta("function()"),
#'iris_con_open' => quotemeta("function()"),
#'iris_con_close' => quotemeta("function()"),
#'iris_stop' => quotemeta("function()"),
#'iris_rel_open' => quotemeta("function($step)"),
#'iris_rel_close' => quotemeta("function($step)"),
#'iris_auto' => quotemeta("function()"),
#'iris_man' => quotemeta("function()"),
#'preset_set' => quotemeta("function($preset)"),
#'preset_goto' => quotemeta("function($preset)")
#if ( !$tiltstep ) { if ( $tiltstep != 0 ) { $tiltstep = $currentTilt } };
#if ( !$panstep ) { if ( $panstep != 0 ) { $panstep = $currentPan } };
#if ( !$tiltspeed ) { if ( $tiltspeed != 0 ) { $tiltspeed = 5 } };
#if ( !$panspeed ) { if ( $panspeed != 0 ) { $panspeed = 5 } };
Zoneminder settings are as follows.
Follow the instructions in previous Sony Network camera instructions and make the camera remote and controllable. The remote camera should be set to jpeg mode.
General: Name->(name); Source Type->Remote; Function->Remote; Enabled; Maximum FPS-> 30.00
Source: Remote Host Name->(must match your camera schema); Remote Host Port->(must match your camera - default is 80); Remote Host Path->/mjpeg; Remote Image Colors->24bit; Capture Width->(must match camera - default is 640); Capture Height->(must match camera - default is 480); Orientation->Normal
Then, follow the edit link to create your control parameters.
Move: check the following: Can Move; Can Move Diagonally; Can Move Mapped; Can Move Absolute
Zoom: check the following: Can Zoom; Can Zoom Absolute; Can Zoom Relative.
Save it. Now from your main Monitor setting, select the new Control and check the "Controllable" box.
You should be able to leave the rest alone. The script takes into account the other variables. Naturally, you are welcome to make your own adjustments and I have left a substantial amount of code at the bottom of the script for future development is other folks feel so inclined.
And that should be all you need to get the camera functional. If you have any troubles, verify traffic connectivity using either debug parameter setting or apache2 error logs. Also, log into your camera's built in software and refresh the access logs to see what is being passed to the camera.
If I've forgotten anything, let me know.