1#!@PERL_EXECUTABLE@ -wT 2# 3# ========================================================================== 4# 5# ZoneMinder Experimental PTZ Tracking Script, $Date: 2009-06-08 10:11:56 +0100 (Mon, 08 Jun 2009) $, $Revision: 2908 $ 6# Copyright (C) 2001-2008 Philip Coombes 7# 8# This program is free software; you can redistribute it and/or 9# modify it under the terms of the GNU General Public License 10# as published by the Free Software Foundation; either version 2 11# of the License, or (at your option) any later version. 12# 13# This program is distributed in the hope that it will be useful, 14# but WITHOUT ANY WARRANTY; without even the implied warranty of 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16# GNU General Public License for more details. 17# 18# You should have received a copy of the GNU General Public License 19# along with this program; if not, write to the Free Software 20# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21# 22# ========================================================================== 23 24=head1 NAME 25 26zmtrack.pl - ZoneMinder Experimental PTZ Tracking Script 27 28=head1 SYNOPSIS 29 30 zmtrack.pl -m <monitor> 31 zmtrack.pl --monitor=<monitor> 32 33=head1 OPTIONS 34 35 -m<monitor>, --monitor=<monitor> - Id of the monitor to track 36 37=head1 DESCRIPTION 38 39This script is used to trigger and cancel alarms from external sources 40using an arbitrary text based format. 41 42=cut 43use strict; 44use bytes; 45 46# ========================================================================== 47# 48# User config 49# 50# ========================================================================== 51 52use constant SLEEP_TIME => 10000; # In microseconds 53 54# ========================================================================== 55# 56# Don't change anything from here on down 57# 58# ========================================================================== 59 60@EXTRA_PERL_LIB@ 61use ZoneMinder; 62use DBI; 63use POSIX; 64use autouse 'Data::Dumper'=>qw(Dumper); 65use Getopt::Long; 66use autouse 'Pod::Usage'=>qw(pod2usage); 67use Time::HiRes qw( usleep ); 68 69$| = 1; 70 71$ENV{PATH} = '/bin:/usr/bin:/usr/local/bin'; 72$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; 73delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; 74 75my $mid = 0; 76 77GetOptions( 'monitor=s'=>\$mid ) 78 or pod2usage(-exitstatus => -1); 79 80my ( $detaint_mid ) = $mid =~ /^(\d+)$/; 81$mid = $detaint_mid; 82 83logInit($mid?(id=>'zmtrack_m'.$mid):()); 84logSetSignal(); 85 86print( "Tracker daemon $mid (experimental) starting at " 87 .strftime( '%y/%m/%d %H:%M:%S', localtime() ) 88 ."\n" 89); 90 91my $dbh = zmDbConnect(); 92 93my $sql = 'SELECT C.*,M.* FROM Monitors as M 94 LEFT JOIN Controls as C on M.ControlId = C.Id 95 WHERE M.Id = ?' 96; 97my $sth = $dbh->prepare_cached( $sql ) 98 or Fatal("Can't prepare '$sql': ".$dbh->errstr()); 99 100my $res = $sth->execute( $mid ) 101 or Fatal("Can't execute '$sql': ".$sth->errstr()); 102my $monitor = $sth->fetchrow_hashref(); 103 104if ( !$monitor ) { 105 Fatal("Can't find monitor '$mid'"); 106} 107if ( !$monitor->{Controllable} ) { 108 Fatal("Monitor '$mid' is not controllable"); 109} 110if ( !$monitor->{TrackMotion} ) { 111 Fatal("Monitor '$mid' is not configured to track motion"); 112} 113 114if ( !$monitor->{CanMoveMap} ) { 115 if ( $monitor->{CanMoveRel} ) { 116 Warning("Monitor '$mid' cannot move in map mode, falling back to pseudo map mode"); 117 } else { 118 Fatal("Monitor '$mid' cannot move in map mode"); 119 } 120} 121 122exit(-1) if !zmMemVerify($monitor); 123 124sub Suspend { 125 my $monitor = shift; 126 zmMonitorSuspend($monitor); 127} 128 129sub Resume { 130 my $monitor = shift; 131 sleep($monitor->{TrackDelay}); 132 zmMonitorResume($monitor); 133} 134 135sub Track { 136 my $monitor = shift; 137 my ( $x, $y ) = @_; 138 my ( $detaint_x ) = $x =~ /^(\d+)$/; $x = $detaint_x; 139 my ( $detaint_y ) = $y =~ /^(\d+)$/; $y = $detaint_y; 140 141 my $ctrlCommand = $Config{ZM_PATH_BIN} 142 .'/zmcontrol.pl -i ' 143 .$monitor->{Id} 144 ; 145 $ctrlCommand .= ' --command=' 146 .( $monitor->{CanMoveMap} ? 'moveMap' 147 : 'movePseudoMap' 148 ) 149 ." --xcoord=$x --ycoord=$y" 150 ; 151 executeShellCommand($ctrlCommand); 152} 153 154sub Return { 155 my $monitor = shift; 156 157 my $ctrlCommand = $Config{ZM_PATH_BIN} 158 .'/zmcontrol.pl -i ' 159 .$monitor->{Id} 160 ; 161 if ( $monitor->{ReturnLocation} > 0 ) { 162 $ctrlCommand .= ' --command=presetGoto --preset=' 163 .$monitor->{ReturnLocation} 164 ; 165 } else { 166 $ctrlCommand .= ' --command=presetHome'; 167 } 168 executeShellCommand($ctrlCommand); 169} 170 171my $last_alarm = 0; 172if ( ($monitor->{ReturnLocation} >= 0) ) { 173 Suspend($monitor); 174 Return($monitor); 175 Resume($monitor); 176} 177 178my $alarmed = undef; 179while( 1 ) { 180 if ( zmIsAlarmed($monitor) ) { 181 my ( $alarm_x, $alarm_y ) = zmGetAlarmLocation($monitor); 182 if ( $alarm_x >= 0 && $alarm_y >= 0 ) { 183 Debug("Got alarm at $alarm_x, $alarm_y"); 184 Suspend($monitor); 185 Track($monitor, $alarm_x, $alarm_y); 186 Resume($monitor); 187 $last_alarm = time(); 188 $alarmed = !undef; 189 } 190 } else { 191 if ( logDebugging() && $alarmed ) { 192 Info('Left alarm state'); 193 $alarmed = undef; 194 } 195 if ( ($monitor->{ReturnLocation} >= 0) 196 && ($last_alarm > 0) 197 && ((time()-$last_alarm) > $monitor->{ReturnDelay}) 198 ) { 199 Debug("Returning to location ".$monitor->{ReturnLocation}); 200 Suspend($monitor); 201 Return($monitor); 202 Resume($monitor); 203 $last_alarm = 0; 204 } 205 } 206 usleep(SLEEP_TIME); 207} 208 2091; 210__END__ 211