Foscam FI8918W control script for ZoneMinder

Based on origional article by Howard at Durdle.com

Updated for Fedora 19

The Foscam cameras have pan, tilt and the ability to set and move to preset locations.

The Foscam control script for ZoneMinder which I found on the ZoneMinder wiki was a good starting point, 

To install the Foscam control script: find where the control scripts are installed on your distro. In mine I found the files in:

  /usr/lib/perl5/site_perl/5.8.8/ZoneMinder/Control/

or CentOS

  /usr/share/perl5/ZoneMinder/Control/PanasonicIP.pm

or Fedora 19

  /usr/share/perl5/vendor_perl/ZoneMinder/Control/PanasonicIP.pm

If you’re not sure where to look, run the command:

  locate PanasonicIP.pm

or

  find / -name PanasonicIP.pm -print

This will return the location of one of the existing control scripts.

Once you’ve found them, create a new file called FoscamFI8918W.pm and paste the code below into it. The username and password are passed via the Control Device field. See below.

You’ll need to add the control script to the ZoneMinder interface and attach it to your camera. First make sure that ZoneMinder is configured to support controllable cameras. Open Options from the main console and click OPT_CONTROL in the System tab.

Now back on the main console click the 'Add New Monitor' button to add a new monitor camera.

Select the Control tab, and click Edit next to Control Type. Click the Add New Control button, then enter the following settings.

Click the 'Add New Control' button and ender the camera details.

main

move

pan

presets

Back on the main console add a new monitor and enter all the monitor tabs as shown

general

source

buffers

Now save the new monitor, then go back and edit the newly created monitor and on the control tab you should be able to pick the Foscam camera.

Now to get the camera to show in the drop down list is a trick. You must create a new monitor with all the data except the control tab, save the camera and then when you edit the camera again you will see the drop down list for the Control Type expanded (this is a zoneminder bug). You should now see the Foscam FI8918W script in the list. Select it, and enter the IP address of the camera in the Control Address box. Make sure Controllable is ticked, then click Save.

Now if you view the camera you’ll have a Control option near the top. Click it to reveal the Pan/Tilt controls, along with the presets:
 

That’s it. Enjoy your controllable cameras!

Download the FoscamFI8918W.pm script. Rename to .pm.

The script now uses Sleep and Wake to turn the IR off and on and passes the username and password via the Control Device parameter. You’ll need to enable those options on the Main tab of the Control like so:

And put your username and password query string in the Control Device field:
 

Getting ZoneMinder working with my Foscam 8918W IP camera

http://192.168.1.19:85/videostream.asf?user=admin&pwd=pass

Turn off the blinking green LED:

http://192.168.1.19:85/set_misc.cgi?led_mode=2?user=admin&pwd=pass

Other Commands

http://[ipcam]/get_misc.cgi ->Returns all the current values for the functions.

http://[ipcam]/get_log.cgi -> Displays the visits log

http://[ipcam]/get_params.cgi ->Returns the complete configuration of the camera.

 

# ==========================================================================
#
# ZoneMinder Foscam FI8918W IP 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 use with Foscam FI8918W IP Camera by Dave Harris
# Modified Feb 2011 by Howard Durdle (http://durdl.es/x) to:
#      fix horizontal panning, add presets and IR on/off
#      use Control Device field to pass username and password
#
# 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 Foscam FI8918W IP camera control
# protocol
#
package ZoneMinder::Control::FoscamFI8918W;
 
use 5.006;
use strict;
use warnings;
 
require ZoneMinder::Base;
require ZoneMinder::Control;
 
our @ISA = qw(ZoneMinder::Control);
 
our $VERSION = $ZoneMinder::Base::VERSION;
 
# ==========================================================================
#
# Foscam FI8918W IP Control Protocol
#
# ==========================================================================
 
use ZoneMinder::Debug 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($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" );
}
our $stop_command;
 
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" );
 
	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 reset
{
	my $self = shift;
	Debug( "Camera Reset" );
	my $cmd = "reboot.cgi?";
	$self->sendCmd( $cmd );
}
 
#Up Arrow
sub moveConUp
{
	my $self = shift;
	$stop_command = "1";
	Debug( "Move Up" );
	my $cmd = "decoder_control.cgi?command=0&";
	$self->sendCmd( $cmd );
}
 
#Down Arrow
sub moveConDown
{
	my $self = shift;
	$stop_command = "1";
	Debug( "Move Down" );
	my $cmd = "decoder_control.cgi?command=2&";
	$self->sendCmd( $cmd );
}
 
#Left Arrow
sub moveConLeft
{
	my $self = shift;
	$stop_command = "1";
	Debug( "Move Left" );
	my $cmd = "decoder_control.cgi?command=6&";
	$self->sendCmd( $cmd );
}
 
#Right Arrow
sub moveConRight
{
	my $self = shift;
	$stop_command = "1";
	Debug( "Move Right" );
	my $cmd = "decoder_control.cgi?command=4&";
	$self->sendCmd( $cmd );
}
 
#Diagonally Up Right Arrow
sub moveConUpRight
{
	my $self = shift;
	$stop_command = "1";
	Debug( "Move Diagonally Up Right" );
	my $cmd = "decoder_control.cgi?command=90&";
	$self->sendCmd( $cmd );
}
 
#Diagonally Down Right Arrow
sub moveConDownRight
{
	my $self = shift;
	$stop_command = "1";
	Debug( "Move Diagonally Down Right" );
	my $cmd = "decoder_control.cgi?command=92&";
	$self->sendCmd( $cmd );
}
 
#Diagonally Up Left Arrow
sub moveConUpLeft
{
	my $self = shift;
	$stop_command = "1";
	Debug( "Move Diagonally Up Left" );
	my $cmd = "decoder_control.cgi?command=91&";
	$self->sendCmd( $cmd );
}
 
#Diagonally Down Left Arrow
sub moveConDownLeft
{
	my $self = shift;
	$stop_command = "1";
	Debug( "Move Diagonally Down Left" );
	my $cmd = "decoder_control.cgi?command=93&";
	$self->sendCmd( $cmd );
}
 
#Stop
sub moveStop
{
	my $self = shift;
	Debug( "Move Stop" );
	my $cmd = "decoder_control.cgi?command=1&";
	$self->sendCmd( $cmd );
}
 
#Move Camera to Home Position
sub presetHome
{
	my $self = shift;
	Debug( "Home Preset" );
	my $cmd = "decoder_control.cgi?command=25&";
	$self->sendCmd( $cmd );
}
 
#Set preset
sub presetSet
{
    my $self = shift;
    my $params = shift;
    my $preset = $self->getParam( $params, 'preset' );
	my $presetCmd = 30 + ($preset*2);
    Debug( "Set Preset $preset with cmd $presetCmd" );
    my $cmd = "decoder_control.cgi?command=$presetCmd&";
    $self->sendCmd( $cmd );
}
 
#Goto preset
sub presetGoto
{
    my $self = shift;
    my $params = shift;
    $stop_command = "1";
    my $preset = $self->getParam( $params, 'preset' );
    my $presetCmd = 31 + ($preset*2);
    Debug( "Goto Preset $preset with cmd $presetCmd" );
    my $cmd = "decoder_control.cgi?command=$presetCmd&";
    $self->sendCmd( $cmd );
}
 
#Turn IR on
sub wake
{
	my $self = shift;
	Debug( "Wake - IR on" );
	my $cmd = "decoder_control.cgi?command=95&";
	$self->sendCmd( $cmd );
}
 
#Turn IR off
sub sleep
{
	my $self = shift;
	Debug( "Sleep - IR off" );
	my $cmd = "decoder_control.cgi?command=94&";
	$self->sendCmd( $cmd );
}
 
1;