Merge pull request #815 from onlyjob/PBP
last batch of POD and readability conversions for *.pl scripts
This commit is contained in:
commit
e69fee1c94
148
scripts/zm.in
148
scripts/zm.in
|
@ -16,12 +16,12 @@ LOCKFILE=/var/lock/subsys/zm
|
||||||
|
|
||||||
loadconf()
|
loadconf()
|
||||||
{
|
{
|
||||||
if [ -f $ZM_CONFIG ]; then
|
if [ -f $ZM_CONFIG ]; then
|
||||||
. $ZM_CONFIG
|
. $ZM_CONFIG
|
||||||
else
|
else
|
||||||
echo "ERROR: $ZM_CONFIG not found."
|
echo "ERROR: $ZM_CONFIG not found."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
loadconf
|
loadconf
|
||||||
|
@ -30,95 +30,95 @@ command="$ZM_PATH_BIN/zmpkg.pl"
|
||||||
start()
|
start()
|
||||||
{
|
{
|
||||||
# Commenting out as it is not needed. Leaving as a placeholder for future use.
|
# Commenting out as it is not needed. Leaving as a placeholder for future use.
|
||||||
# zmupdate || return $?
|
# zmupdate || return $?
|
||||||
loadconf || return $?
|
loadconf || return $?
|
||||||
#Make sure the directory for our PID folder exists or create one.
|
#Make sure the directory for our PID folder exists or create one.
|
||||||
[ ! -d $pidfile ] \
|
[ ! -d $pidfile ] \
|
||||||
&& mkdir -m 774 $pidfile \
|
&& mkdir -m 774 $pidfile \
|
||||||
&& chown $ZM_WEB_USER:$ZM_WEB_GROUP $pidfile
|
&& chown $ZM_WEB_USER:$ZM_WEB_GROUP $pidfile
|
||||||
#Make sure the folder for the socks file exists or create one
|
#Make sure the folder for the socks file exists or create one
|
||||||
GetPath="select Value from Config where Name='ZM_PATH_SOCKS'"
|
GetPath="select Value from Config where Name='ZM_PATH_SOCKS'"
|
||||||
dbHost=`echo $ZM_DB_HOST | cut -d: -f1`
|
dbHost=`echo $ZM_DB_HOST | cut -d: -f1`
|
||||||
dbPort=`echo $ZM_DB_HOST | cut -d: -s -f2`
|
dbPort=`echo $ZM_DB_HOST | cut -d: -s -f2`
|
||||||
if [ "$dbPort" = "" ]
|
if [ "$dbPort" = "" ]
|
||||||
then
|
then
|
||||||
ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$ZM_DB_HOST -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'`
|
ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$ZM_DB_HOST -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'`
|
||||||
else
|
else
|
||||||
ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$dbHost -P$dbPort -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'`
|
ZM_PATH_SOCK=`echo $GetPath | mysql -B -h$dbHost -P$dbPort -u$ZM_DB_USER -p$ZM_DB_PASS $ZM_DB_NAME | grep -v '^Value'`
|
||||||
fi
|
fi
|
||||||
[ ! -d $ZM_PATH_SOCK ] \
|
[ ! -d $ZM_PATH_SOCK ] \
|
||||||
&& mkdir -m 774 $ZM_PATH_SOCK \
|
&& mkdir -m 774 $ZM_PATH_SOCK \
|
||||||
&& chown $ZM_WEB_USER:$ZM_WEB_GROUP $ZM_PATH_SOCK
|
&& chown $ZM_WEB_USER:$ZM_WEB_GROUP $ZM_PATH_SOCK
|
||||||
echo -n $"Starting $prog: "
|
echo -n $"Starting $prog: "
|
||||||
$command start
|
$command start
|
||||||
RETVAL=$?
|
RETVAL=$?
|
||||||
[ $RETVAL = 0 ] && success || failure
|
[ $RETVAL = 0 ] && success || failure
|
||||||
echo
|
echo
|
||||||
[ $RETVAL = 0 ] && touch $LOCKFILE
|
[ $RETVAL = 0 ] && touch $LOCKFILE
|
||||||
return $RETVAL
|
return $RETVAL
|
||||||
}
|
}
|
||||||
|
|
||||||
stop()
|
stop()
|
||||||
{
|
{
|
||||||
loadconf
|
loadconf
|
||||||
echo -n $"Stopping $prog: "
|
echo -n $"Stopping $prog: "
|
||||||
$command stop
|
$command stop
|
||||||
RETVAL=$?
|
RETVAL=$?
|
||||||
[ $RETVAL = 0 ] && success || failure
|
[ $RETVAL = 0 ] && success || failure
|
||||||
echo
|
echo
|
||||||
[ $RETVAL = 0 ] && rm -f $LOCKFILE
|
[ $RETVAL = 0 ] && rm -f $LOCKFILE
|
||||||
}
|
}
|
||||||
|
|
||||||
zmstatus()
|
zmstatus()
|
||||||
{
|
{
|
||||||
loadconf
|
loadconf
|
||||||
result=`$command status`
|
result=`$command status`
|
||||||
if [ "$result" = "running" ]; then
|
if [ "$result" = "running" ]; then
|
||||||
echo "ZoneMinder is running"
|
echo "ZoneMinder is running"
|
||||||
$ZM_PATH_BIN/zmu -l
|
$ZM_PATH_BIN/zmu -l
|
||||||
RETVAL=0
|
RETVAL=0
|
||||||
else
|
else
|
||||||
echo "ZoneMinder is stopped"
|
echo "ZoneMinder is stopped"
|
||||||
RETVAL=1
|
RETVAL=1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
zmupdate()
|
zmupdate()
|
||||||
{
|
{
|
||||||
if [ -x $ZM_PATH_BIN/zmupdate.pl ]; then
|
if [ -x $ZM_PATH_BIN/zmupdate.pl ]; then
|
||||||
$ZM_PATH_BIN/zmupdate.pl -f
|
$ZM_PATH_BIN/zmupdate.pl -f
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
'start')
|
'start')
|
||||||
start
|
start
|
||||||
;;
|
;;
|
||||||
'stop')
|
'stop')
|
||||||
stop
|
stop
|
||||||
;;
|
;;
|
||||||
'restart')
|
'restart')
|
||||||
stop
|
stop
|
||||||
start
|
start
|
||||||
;;
|
;;
|
||||||
'condrestart')
|
'condrestart')
|
||||||
loadconf
|
loadconf
|
||||||
result=`$ZM_PATH_BIN/zmdc.pl check`
|
result=`$ZM_PATH_BIN/zmdc.pl check`
|
||||||
if [ "$result" = "running" ]; then
|
if [ "$result" = "running" ]; then
|
||||||
$ZM_PATH_BIN/zmdc.pl shutdown > /dev/null
|
$ZM_PATH_BIN/zmdc.pl shutdown > /dev/null
|
||||||
rm -f $LOCKFILE
|
rm -f $LOCKFILE
|
||||||
start
|
start
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
'status')
|
'status')
|
||||||
status httpd
|
status httpd
|
||||||
status mysqld
|
status mysqld
|
||||||
zmstatus
|
zmstatus
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 { start | stop | restart | condrestart | status }"
|
echo "Usage: $0 { start | stop | restart | condrestart | status }"
|
||||||
RETVAL=1
|
RETVAL=1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
exit $RETVAL
|
exit $RETVAL
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
#
|
||||||
# ZoneMinder Update Script, $Date$, $Revision$
|
# ZoneMinder systemctl wrapper, $Date$, $Revision$
|
||||||
# Copyright (C) 2001-2008 Philip Coombes
|
# Copyright (C) 2001-2008 Philip Coombes
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
|
@ -20,25 +20,39 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
|
||||||
# This is a wrapper script that allows zoneminder to start and stop itself
|
=head1 NAME
|
||||||
# in a manner that keeps it in-sync with systemd. This script is intended
|
|
||||||
# to be called internally by zoneminder and may not give the desired results
|
zmsystemctl.pl - ZoneMinder systemctl wrapper
|
||||||
# if run from the command line.
|
|
||||||
#
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
zmsystemctl.pl {start|stop|restart|version}
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
This is a wrapper script that allows zoneminder to start and stop itself
|
||||||
|
in a manner that keeps it in-sync with systemd. This script is intended
|
||||||
|
to be called internally by zoneminder and may not give the desired results
|
||||||
|
if run from the command line.
|
||||||
|
|
||||||
|
=cut
|
||||||
use warnings;
|
use warnings;
|
||||||
use strict;
|
use strict;
|
||||||
use bytes;
|
use bytes;
|
||||||
|
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||||
|
|
||||||
@EXTRA_PERL_LIB@
|
@EXTRA_PERL_LIB@
|
||||||
use ZoneMinder::Logger qw(:all);
|
use ZoneMinder::Logger qw(:all);
|
||||||
|
|
||||||
my $command = $ARGV[0];
|
my $command = $ARGV[0];
|
||||||
|
|
||||||
if ( (scalar(@ARGV) == 1) && ($command =~ /^(start|stop|restart|version)$/ )) {
|
if ( (scalar(@ARGV) == 1)
|
||||||
$command = $1;
|
&& ($command =~ /^(start|stop|restart|version)$/ )
|
||||||
|
){
|
||||||
|
$command = $1;
|
||||||
} else {
|
} else {
|
||||||
die(" USAGE: zmsystemctl.pl <start|stop|restart|version>\n");
|
pod2usage(-exitstatus => -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
my $path = qx(which systemctl);
|
my $path = qx(which systemctl);
|
||||||
|
@ -46,7 +60,7 @@ chomp($path);
|
||||||
|
|
||||||
my $status = $? >> 8;
|
my $status = $? >> 8;
|
||||||
if ( !$path || $status ) {
|
if ( !$path || $status ) {
|
||||||
Fatal( "Unable to determine systemctl executable. Is systemd in use?" );
|
Fatal( "Unable to determine systemctl executable. Is systemd in use?" );
|
||||||
}
|
}
|
||||||
|
|
||||||
Info( "Redirecting command through systemctl\n" );
|
Info( "Redirecting command through systemctl\n" );
|
||||||
|
|
|
@ -20,10 +20,26 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
|
||||||
# This script is used to trigger and cancel alarms from external sources
|
=head1 NAME
|
||||||
# using an arbitrary text based format
|
|
||||||
#
|
zmtrack.pl - ZoneMinder Experimental PTZ Tracking Script
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
zmtrack.pl -m <monitor>
|
||||||
|
zmtrack.pl --monitor=<monitor>
|
||||||
|
|
||||||
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
-m<monitor>, --monitor=<monitor> - Id of the monitor to track
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
This script is used to trigger and cancel alarms from external sources
|
||||||
|
using an arbitrary text based format.
|
||||||
|
|
||||||
|
=cut
|
||||||
use strict;
|
use strict;
|
||||||
use bytes;
|
use bytes;
|
||||||
|
|
||||||
|
@ -45,8 +61,9 @@ use constant SLEEP_TIME => 10000; # In microseconds
|
||||||
use ZoneMinder;
|
use ZoneMinder;
|
||||||
use DBI;
|
use DBI;
|
||||||
use POSIX;
|
use POSIX;
|
||||||
use Data::Dumper;
|
use autouse 'Data::Dumper'=>qw(Dumper);
|
||||||
use Getopt::Long;
|
use Getopt::Long;
|
||||||
|
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||||
use Time::HiRes qw( usleep );
|
use Time::HiRes qw( usleep );
|
||||||
|
|
||||||
$| = 1;
|
$| = 1;
|
||||||
|
@ -57,20 +74,8 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
||||||
|
|
||||||
my $mid = 0;
|
my $mid = 0;
|
||||||
|
|
||||||
sub Usage
|
GetOptions( 'monitor=s'=>\$mid )
|
||||||
{
|
or pod2usage(-exitstatus => -1);
|
||||||
print( "
|
|
||||||
Usage: zmtrack.pl -m <monitor>,--monitor=<monitor>]
|
|
||||||
Parameters are :-
|
|
||||||
-m<monitor>, --monitor=<monitor> - Id of the monitor to track
|
|
||||||
");
|
|
||||||
exit( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !GetOptions( 'monitor=s'=>\$mid ) )
|
|
||||||
{
|
|
||||||
Usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
logInit();
|
logInit();
|
||||||
logSetSignal();
|
logSetSignal();
|
||||||
|
@ -78,44 +83,52 @@ logSetSignal();
|
||||||
my ( $detaint_mid ) = $mid =~ /^(\d+)$/;
|
my ( $detaint_mid ) = $mid =~ /^(\d+)$/;
|
||||||
$mid = $detaint_mid;
|
$mid = $detaint_mid;
|
||||||
|
|
||||||
print( "Tracker daemon $mid (experimental) starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
|
print( "Tracker daemon $mid (experimental) starting at "
|
||||||
|
.strftime( '%y/%m/%d %H:%M:%S', localtime() )
|
||||||
|
."\n"
|
||||||
|
);
|
||||||
|
|
||||||
my $dbh = zmDbConnect();
|
my $dbh = zmDbConnect();
|
||||||
|
|
||||||
my $sql = "select C.*,M.* from Monitors as M left join Controls as C on M.ControlId = C.Id where M.Id = ?";
|
my $sql = "SELECT C.*,M.* FROM Monitors as M
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
LEFT JOIN Controls as C on M.ControlId = C.Id
|
||||||
|
WHERE M.Id = ?"
|
||||||
|
;
|
||||||
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
|
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||||
|
|
||||||
my $res = $sth->execute( $mid ) or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
my $res = $sth->execute( $mid )
|
||||||
|
or Fatal( "Can't execute '$sql': ".$sth->errstr() );
|
||||||
my $monitor = $sth->fetchrow_hashref();
|
my $monitor = $sth->fetchrow_hashref();
|
||||||
|
|
||||||
if ( !$monitor )
|
if ( !$monitor )
|
||||||
{
|
{
|
||||||
print( "Can't find monitor '$mid'\n" );
|
print( "Can't find monitor '$mid'\n" );
|
||||||
exit( -1 );
|
exit( -1 );
|
||||||
}
|
}
|
||||||
if ( !$monitor->{Controllable} )
|
if ( !$monitor->{Controllable} )
|
||||||
{
|
{
|
||||||
print( "Monitor '$mid' is not controllable\n" );
|
print( "Monitor '$mid' is not controllable\n" );
|
||||||
exit( -1 );
|
exit( -1 );
|
||||||
}
|
}
|
||||||
if ( !$monitor->{TrackMotion} )
|
if ( !$monitor->{TrackMotion} )
|
||||||
{
|
{
|
||||||
print( "Monitor '$mid' is not configured to track motion\n" );
|
print( "Monitor '$mid' is not configured to track motion\n" );
|
||||||
exit( -1 );
|
exit( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !$monitor->{CanMoveMap} )
|
if ( !$monitor->{CanMoveMap} )
|
||||||
{
|
{
|
||||||
print( "Monitor '$mid' cannot move in map mode" );
|
print( "Monitor '$mid' cannot move in map mode" );
|
||||||
if ( $monitor->{CanMoveRel} )
|
if ( $monitor->{CanMoveRel} )
|
||||||
{
|
{
|
||||||
print( ", falling back to pseudo map mode\n" );
|
print( ", falling back to pseudo map mode\n" );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
print( "\n" );
|
print( "\n" );
|
||||||
exit( -1 );
|
exit( -1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug( "Found monitor for id '$monitor'\n" );
|
Debug( "Found monitor for id '$monitor'\n" );
|
||||||
|
@ -123,84 +136,100 @@ exit( -1 ) if ( !zmMemVerify( $monitor ) );
|
||||||
|
|
||||||
sub Suspend
|
sub Suspend
|
||||||
{
|
{
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
zmMonitorSuspend( $monitor );
|
zmMonitorSuspend( $monitor );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub Resume
|
sub Resume
|
||||||
{
|
{
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
sleep( $monitor->{TrackDelay} );
|
sleep( $monitor->{TrackDelay} );
|
||||||
zmMonitorResume( $monitor );
|
zmMonitorResume( $monitor );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub Track
|
sub Track
|
||||||
{
|
{
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
my ( $x, $y ) = @_;
|
my ( $x, $y ) = @_;
|
||||||
my ( $detaint_x ) = $x =~ /^(\d+)$/; $x = $detaint_x;
|
my ( $detaint_x ) = $x =~ /^(\d+)$/; $x = $detaint_x;
|
||||||
my ( $detaint_y ) = $y =~ /^(\d+)$/; $y = $detaint_y;
|
my ( $detaint_y ) = $y =~ /^(\d+)$/; $y = $detaint_y;
|
||||||
|
|
||||||
my $ctrlCommand = $Config{ZM_PATH_BIN}."/zmcontrol.pl -i ".$monitor->{Id};
|
my $ctrlCommand = $Config{ZM_PATH_BIN}
|
||||||
$ctrlCommand .= " --command=".($monitor->{CanMoveMap}?"moveMap":"movePseudoMap")." --xcoord=$x --ycoord=$y";
|
."/zmcontrol.pl -i "
|
||||||
executeShellCommand( $ctrlCommand );
|
.$monitor->{Id}
|
||||||
|
;
|
||||||
|
$ctrlCommand .= " --command="
|
||||||
|
.( $monitor->{CanMoveMap} ? "moveMap"
|
||||||
|
: "movePseudoMap"
|
||||||
|
)
|
||||||
|
." --xcoord=$x --ycoord=$y"
|
||||||
|
;
|
||||||
|
executeShellCommand( $ctrlCommand );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub Return
|
sub Return
|
||||||
{
|
{
|
||||||
my $monitor = shift;
|
my $monitor = shift;
|
||||||
|
|
||||||
my $ctrlCommand = $Config{ZM_PATH_BIN}."/zmcontrol.pl -i ".$monitor->{Id};
|
my $ctrlCommand = $Config{ZM_PATH_BIN}
|
||||||
if ( $monitor->{ReturnLocation} > 0 )
|
."/zmcontrol.pl -i "
|
||||||
{
|
.$monitor->{Id}
|
||||||
$ctrlCommand .= " --command=presetGoto --preset=".$monitor->{ReturnLocation};
|
;
|
||||||
}
|
if ( $monitor->{ReturnLocation} > 0 )
|
||||||
else
|
{
|
||||||
{
|
$ctrlCommand .= " --command=presetGoto --preset="
|
||||||
$ctrlCommand .= " --command=presetHome";
|
.$monitor->{ReturnLocation}
|
||||||
}
|
;
|
||||||
executeShellCommand( $ctrlCommand );
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$ctrlCommand .= " --command=presetHome";
|
||||||
|
}
|
||||||
|
executeShellCommand( $ctrlCommand );
|
||||||
}
|
}
|
||||||
|
|
||||||
my $last_alarm = 0;
|
my $last_alarm = 0;
|
||||||
if ( ($monitor->{ReturnLocation} >= 0) )
|
if ( ($monitor->{ReturnLocation} >= 0) )
|
||||||
{
|
{
|
||||||
Suspend( $monitor );
|
Suspend( $monitor );
|
||||||
Return( $monitor );
|
Return( $monitor );
|
||||||
Resume( $monitor );
|
Resume( $monitor );
|
||||||
}
|
}
|
||||||
|
|
||||||
my $alarmed = undef;
|
my $alarmed = undef;
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
if ( zmIsAlarmed( $monitor ) )
|
if ( zmIsAlarmed( $monitor ) )
|
||||||
{
|
{
|
||||||
my ( $alarm_x, $alarm_y ) = zmGetAlarmLocation( $monitor );
|
my ( $alarm_x, $alarm_y ) = zmGetAlarmLocation( $monitor );
|
||||||
if ( $alarm_x >= 0 && $alarm_y >= 0 )
|
if ( $alarm_x >= 0 && $alarm_y >= 0 )
|
||||||
{
|
{
|
||||||
Debug( "Got alarm at $alarm_x, $alarm_y\n" );
|
Debug( "Got alarm at $alarm_x, $alarm_y\n" );
|
||||||
Suspend( $monitor );
|
Suspend( $monitor );
|
||||||
Track( $monitor, $alarm_x, $alarm_y );
|
Track( $monitor, $alarm_x, $alarm_y );
|
||||||
Resume( $monitor );
|
Resume( $monitor );
|
||||||
$last_alarm = time();
|
$last_alarm = time();
|
||||||
$alarmed = !undef;
|
$alarmed = !undef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( logDebugging() && $alarmed )
|
if ( logDebugging() && $alarmed )
|
||||||
{
|
{
|
||||||
print( "Left alarm state\n" );
|
print( "Left alarm state\n" );
|
||||||
$alarmed = undef;
|
$alarmed = undef;
|
||||||
}
|
}
|
||||||
if ( ($monitor->{ReturnLocation} >= 0) && ($last_alarm > 0) && ((time()-$last_alarm) > $monitor->{ReturnDelay}) )
|
if ( ($monitor->{ReturnLocation} >= 0)
|
||||||
{
|
&& ($last_alarm > 0)
|
||||||
Debug( "Returning to location ".$monitor->{ReturnLocation}."\n" );
|
&& ((time()-$last_alarm) > $monitor->{ReturnDelay})
|
||||||
Suspend( $monitor );
|
)
|
||||||
Return( $monitor );
|
{
|
||||||
Resume( $monitor );
|
Debug( "Returning to location ".$monitor->{ReturnLocation}."\n" );
|
||||||
$last_alarm = 0;
|
Suspend( $monitor );
|
||||||
}
|
Return( $monitor );
|
||||||
}
|
Resume( $monitor );
|
||||||
usleep( SLEEP_TIME );
|
$last_alarm = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usleep( SLEEP_TIME );
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,17 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
|
||||||
# This script is used to trigger and cancel alarms from external connections
|
=head1 NAME
|
||||||
# using an arbitrary text based format
|
|
||||||
#
|
zmtrigger.pl - ZoneMinder External Trigger Script
|
||||||
# ==========================================================================
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
This script is used to trigger and cancel alarms from external connections
|
||||||
|
using an arbitrary text based format
|
||||||
|
|
||||||
|
=cut
|
||||||
use strict;
|
use strict;
|
||||||
use bytes;
|
use bytes;
|
||||||
|
|
||||||
|
@ -52,8 +58,22 @@ use ZoneMinder::Trigger::Channel::Serial;
|
||||||
use ZoneMinder::Trigger::Connection;
|
use ZoneMinder::Trigger::Connection;
|
||||||
|
|
||||||
my @connections;
|
my @connections;
|
||||||
push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan1", channel=>ZoneMinder::Trigger::Channel::Inet->new( port=>6802 ), mode=>"rw" ) );
|
push( @connections,
|
||||||
push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan2", channel=>ZoneMinder::Trigger::Channel::Unix->new( path=>$Config{ZM_PATH_SOCKS}.'/zmtrigger.sock' ), mode=>"rw" ) );
|
ZoneMinder::Trigger::Connection->new(
|
||||||
|
name=>"Chan1",
|
||||||
|
channel=>ZoneMinder::Trigger::Channel::Inet->new( port=>6802 ),
|
||||||
|
mode=>"rw"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
push( @connections,
|
||||||
|
ZoneMinder::Trigger::Connection->new(
|
||||||
|
name=>"Chan2",
|
||||||
|
channel=>ZoneMinder::Trigger::Channel::Unix->new(
|
||||||
|
path=>$Config{ZM_PATH_SOCKS}.'/zmtrigger.sock'
|
||||||
|
),
|
||||||
|
mode=>"rw"
|
||||||
|
)
|
||||||
|
);
|
||||||
#push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan3", channel=>ZoneMinder::Trigger::Channel::File->new( path=>'/tmp/zmtrigger.out' ), mode=>"w" ) );
|
#push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan3", channel=>ZoneMinder::Trigger::Channel::File->new( path=>'/tmp/zmtrigger.out' ), mode=>"w" ) );
|
||||||
#push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan4", channel=>ZoneMinder::Trigger::Channel::Serial->new( path=>'/dev/ttyS0' ), mode=>"rw" ) );
|
#push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan4", channel=>ZoneMinder::Trigger::Channel::Serial->new( path=>'/dev/ttyS0' ), mode=>"rw" ) );
|
||||||
|
|
||||||
|
@ -65,7 +85,7 @@ push( @connections, ZoneMinder::Trigger::Connection->new( name=>"Chan2", channel
|
||||||
|
|
||||||
use DBI;
|
use DBI;
|
||||||
#use Socket;
|
#use Socket;
|
||||||
use Data::Dumper;
|
use autouse 'Data::Dumper'=>qw(Dumper);
|
||||||
use POSIX qw( EINTR );
|
use POSIX qw( EINTR );
|
||||||
use Time::HiRes qw( usleep );
|
use Time::HiRes qw( usleep );
|
||||||
|
|
||||||
|
@ -85,8 +105,8 @@ my $dbh = zmDbConnect();
|
||||||
my $base_rin = '';
|
my $base_rin = '';
|
||||||
foreach my $connection ( @connections )
|
foreach my $connection ( @connections )
|
||||||
{
|
{
|
||||||
Info( "Opening connection '$connection->{name}'\n" );
|
Info( "Opening connection '$connection->{name}'\n" );
|
||||||
$connection->open();
|
$connection->open();
|
||||||
}
|
}
|
||||||
|
|
||||||
my @in_select_connections = grep { $_->input() && $_->selectable() } @connections;
|
my @in_select_connections = grep { $_->input() && $_->selectable() } @connections;
|
||||||
|
@ -95,7 +115,7 @@ my @out_connections = grep { $_->output() } @connections;
|
||||||
|
|
||||||
foreach my $connection ( @in_select_connections )
|
foreach my $connection ( @in_select_connections )
|
||||||
{
|
{
|
||||||
vec( $base_rin, $connection->fileno(), 1 ) = 1;
|
vec( $base_rin, $connection->fileno(), 1 ) = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
my %spawned_connections;
|
my %spawned_connections;
|
||||||
|
@ -111,332 +131,387 @@ my $timeout = SELECT_TIMEOUT;
|
||||||
my %actions;
|
my %actions;
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
$rin = $base_rin;
|
$rin = $base_rin;
|
||||||
# Add the file descriptors of any spawned connections
|
# Add the file descriptors of any spawned connections
|
||||||
foreach my $fileno ( keys(%spawned_connections) )
|
foreach my $fileno ( keys(%spawned_connections) )
|
||||||
{
|
{
|
||||||
vec( $rin, $fileno, 1 ) = 1;
|
vec( $rin, $fileno, 1 ) = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $nfound = select( my $rout = $rin, undef, my $eout = $ein, $timeout );
|
my $nfound = select( my $rout = $rin, undef, my $eout = $ein, $timeout );
|
||||||
if ( $nfound > 0 )
|
if ( $nfound > 0 )
|
||||||
{
|
{
|
||||||
Debug( "Got input from $nfound connections\n" );
|
Debug( "Got input from $nfound connections\n" );
|
||||||
foreach my $connection ( @in_select_connections )
|
foreach my $connection ( @in_select_connections )
|
||||||
{
|
{
|
||||||
if ( vec( $rout, $connection->fileno(), 1 ) )
|
if ( vec( $rout, $connection->fileno(), 1 ) )
|
||||||
{
|
{
|
||||||
Debug( "Got input from connection ".$connection->name()." (".$connection->fileno().")\n" );
|
Debug( "Got input from connection "
|
||||||
if ( $connection->spawns() )
|
.$connection->name()
|
||||||
{
|
." ("
|
||||||
my $new_connection = $connection->accept();
|
.$connection->fileno()
|
||||||
$spawned_connections{$new_connection->fileno()} = $new_connection;
|
.")\n"
|
||||||
Debug( "Added new spawned connection (".$new_connection->fileno()."), ".int(keys(%spawned_connections))." spawned connections\n" );
|
);
|
||||||
}
|
if ( $connection->spawns() )
|
||||||
else
|
{
|
||||||
{
|
my $new_connection = $connection->accept();
|
||||||
my $messages = $connection->getMessages();
|
$spawned_connections{$new_connection->fileno()} = $new_connection;
|
||||||
if ( defined($messages) )
|
Debug( "Added new spawned connection ("
|
||||||
{
|
.$new_connection->fileno()
|
||||||
foreach my $message ( @$messages )
|
."), "
|
||||||
{
|
.int(keys(%spawned_connections))
|
||||||
handleMessage( $connection, $message );
|
." spawned connections\n"
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
}
|
{
|
||||||
}
|
my $messages = $connection->getMessages();
|
||||||
foreach my $connection ( values(%spawned_connections) )
|
if ( defined($messages) )
|
||||||
{
|
{
|
||||||
if ( vec( $rout, $connection->fileno(), 1 ) )
|
foreach my $message ( @$messages )
|
||||||
{
|
{
|
||||||
Debug( "Got input from spawned connection ".$connection->name()." (".$connection->fileno().")\n" );
|
handleMessage( $connection, $message );
|
||||||
my $messages = $connection->getMessages();
|
}
|
||||||
if ( defined($messages) )
|
}
|
||||||
{
|
}
|
||||||
foreach my $message ( @$messages )
|
}
|
||||||
{
|
}
|
||||||
handleMessage( $connection, $message );
|
foreach my $connection ( values(%spawned_connections) )
|
||||||
}
|
{
|
||||||
}
|
if ( vec( $rout, $connection->fileno(), 1 ) )
|
||||||
else
|
{
|
||||||
{
|
Debug( "Got input from spawned connection "
|
||||||
delete( $spawned_connections{$connection->fileno()} );
|
.$connection->name()
|
||||||
Debug( "Removed spawned connection (".$connection->fileno()."), ".int(keys(%spawned_connections))." spawned connections\n" );
|
." ("
|
||||||
$connection->close();
|
.$connection->fileno()
|
||||||
}
|
.")\n"
|
||||||
}
|
);
|
||||||
}
|
my $messages = $connection->getMessages();
|
||||||
}
|
if ( defined($messages) )
|
||||||
elsif ( $nfound < 0 )
|
{
|
||||||
{
|
foreach my $message ( @$messages )
|
||||||
if ( $! == EINTR )
|
{
|
||||||
{
|
handleMessage( $connection, $message );
|
||||||
# Do nothing
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Fatal( "Can't select: $!" );
|
delete( $spawned_connections{$connection->fileno()} );
|
||||||
}
|
Debug( "Removed spawned connection ("
|
||||||
}
|
.$connection->fileno()
|
||||||
|
."), "
|
||||||
|
.int(keys(%spawned_connections))
|
||||||
|
." spawned connections\n"
|
||||||
|
);
|
||||||
|
$connection->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elsif ( $nfound < 0 )
|
||||||
|
{
|
||||||
|
if ( $! == EINTR )
|
||||||
|
{
|
||||||
|
# Do nothing
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Fatal( "Can't select: $!" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Check polled connections
|
# Check polled connections
|
||||||
foreach my $connection ( @in_poll_connections )
|
foreach my $connection ( @in_poll_connections )
|
||||||
{
|
{
|
||||||
my $messages = $connection->getMessages();
|
my $messages = $connection->getMessages();
|
||||||
if ( defined($messages) )
|
if ( defined($messages) )
|
||||||
{
|
{
|
||||||
foreach my $message ( @$messages )
|
foreach my $message ( @$messages )
|
||||||
{
|
{
|
||||||
handleMessage( $connection, $message );
|
handleMessage( $connection, $message );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check for alarms that might have happened
|
# Check for alarms that might have happened
|
||||||
my @out_messages;
|
my @out_messages;
|
||||||
foreach my $monitor ( values(%monitors) )
|
foreach my $monitor ( values(%monitors) )
|
||||||
{
|
{
|
||||||
my ( $state, $last_event ) = zmMemRead( $monitor, [ "shared_data:state", "shared_data:last_event" ] );
|
my ( $state, $last_event )
|
||||||
|
= zmMemRead( $monitor,
|
||||||
|
[ "shared_data:state",
|
||||||
|
"shared_data:last_event"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
#print( "$monitor->{Id}: S:$state, LE:$last_event\n" );
|
#print( "$monitor->{Id}: S:$state, LE:$last_event\n" );
|
||||||
#print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}\n" );
|
#print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}\n" );
|
||||||
if ( $state == STATE_ALARM || $state == STATE_ALERT ) # In alarm state
|
if ( $state == STATE_ALARM
|
||||||
{
|
|| $state == STATE_ALERT
|
||||||
if ( !defined($monitor->{LastEvent}) || ($last_event != $monitor->{LastEvent}) ) # A new event
|
) # In alarm state
|
||||||
{
|
{
|
||||||
push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event );
|
if ( !defined($monitor->{LastEvent})
|
||||||
}
|
|| ($last_event != $monitor->{LastEvent})
|
||||||
else # The same one as last time, so ignore it
|
) # A new event
|
||||||
{
|
{
|
||||||
# Do nothing
|
push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event );
|
||||||
}
|
}
|
||||||
}
|
else # The same one as last time, so ignore it
|
||||||
elsif ( ($state == STATE_IDLE && $monitor->{LastState} != STATE_IDLE) || ($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE) ) # Out of alarm state
|
{
|
||||||
{
|
# Do nothing
|
||||||
push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event );
|
}
|
||||||
}
|
}
|
||||||
elsif ( defined($monitor->{LastEvent}) && ($last_event != $monitor->{LastEvent}) ) # We've missed a whole event
|
elsif ( ($state == STATE_IDLE
|
||||||
{
|
&& $monitor->{LastState} != STATE_IDLE
|
||||||
push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event );
|
)
|
||||||
push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event );
|
|| ($state == STATE_TAPE
|
||||||
}
|
&& $monitor->{LastState} != STATE_TAPE
|
||||||
$monitor->{LastState} = $state;
|
)
|
||||||
$monitor->{LastEvent} = $last_event;
|
) # Out of alarm state
|
||||||
}
|
{
|
||||||
foreach my $connection ( @out_connections )
|
push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event );
|
||||||
{
|
}
|
||||||
if ( $connection->canWrite() )
|
elsif ( defined($monitor->{LastEvent})
|
||||||
{
|
&& ($last_event != $monitor->{LastEvent})
|
||||||
$connection->putMessages( \@out_messages );
|
) # We've missed a whole event
|
||||||
}
|
{
|
||||||
}
|
push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event );
|
||||||
foreach my $connection ( values(%spawned_connections) )
|
push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event );
|
||||||
{
|
}
|
||||||
if ( $connection->canWrite() )
|
$monitor->{LastState} = $state;
|
||||||
{
|
$monitor->{LastEvent} = $last_event;
|
||||||
$connection->putMessages( \@out_messages );
|
}
|
||||||
}
|
foreach my $connection ( @out_connections )
|
||||||
}
|
{
|
||||||
|
if ( $connection->canWrite() )
|
||||||
|
{
|
||||||
|
$connection->putMessages( \@out_messages );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach my $connection ( values(%spawned_connections) )
|
||||||
|
{
|
||||||
|
if ( $connection->canWrite() )
|
||||||
|
{
|
||||||
|
$connection->putMessages( \@out_messages );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Debug( "Checking for timed actions\n" ) if ( int(keys(%actions)) );
|
Debug( "Checking for timed actions\n" )
|
||||||
my $now = time();
|
if ( int(keys(%actions)) );
|
||||||
foreach my $action_time ( sort( grep { $_ < $now } keys( %actions ) ) )
|
my $now = time();
|
||||||
{
|
foreach my $action_time ( sort( grep { $_ < $now } keys( %actions ) ) )
|
||||||
Info( "Found actions expiring at $action_time\n" );
|
{
|
||||||
foreach my $action ( @{$actions{$action_time}} )
|
Info( "Found actions expiring at $action_time\n" );
|
||||||
{
|
foreach my $action ( @{$actions{$action_time}} )
|
||||||
my $connection = $action->{connection};
|
{
|
||||||
my $message = $action->{message};
|
my $connection = $action->{connection};
|
||||||
Info( "Found action '$message'\n" );
|
my $message = $action->{message};
|
||||||
handleMessage( $connection, $message );
|
Info( "Found action '$message'\n" );
|
||||||
}
|
handleMessage( $connection, $message );
|
||||||
delete( $actions{$action_time} );
|
}
|
||||||
}
|
delete( $actions{$action_time} );
|
||||||
|
}
|
||||||
|
|
||||||
# Allow connections to do their own timed actions
|
# Allow connections to do their own timed actions
|
||||||
foreach my $connection ( @connections )
|
foreach my $connection ( @connections )
|
||||||
{
|
{
|
||||||
my $messages = $connection->timedActions();
|
my $messages = $connection->timedActions();
|
||||||
if ( defined($messages) )
|
if ( defined($messages) )
|
||||||
{
|
{
|
||||||
foreach my $message ( @$messages )
|
foreach my $message ( @$messages )
|
||||||
{
|
{
|
||||||
handleMessage( $connection, $message );
|
handleMessage( $connection, $message );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach my $connection ( values(%spawned_connections) )
|
foreach my $connection ( values(%spawned_connections) )
|
||||||
{
|
{
|
||||||
my $messages = $connection->timedActions();
|
my $messages = $connection->timedActions();
|
||||||
if ( defined($messages) )
|
if ( defined($messages) )
|
||||||
{
|
{
|
||||||
foreach my $message ( @$messages )
|
foreach my $message ( @$messages )
|
||||||
{
|
{
|
||||||
handleMessage( $connection, $message );
|
handleMessage( $connection, $message );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# If necessary reload monitors
|
# If necessary reload monitors
|
||||||
if ( (time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL )
|
if ( (time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL )
|
||||||
{
|
{
|
||||||
foreach my $monitor ( values(%monitors) )
|
foreach my $monitor ( values(%monitors) )
|
||||||
{
|
{
|
||||||
# Free up any used memory handle
|
# Free up any used memory handle
|
||||||
zmMemInvalidate( $monitor );
|
zmMemInvalidate( $monitor );
|
||||||
}
|
}
|
||||||
loadMonitors();
|
loadMonitors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Info( "Trigger daemon exiting\n" );
|
Info( "Trigger daemon exiting\n" );
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
sub loadMonitors
|
sub loadMonitors
|
||||||
{
|
{
|
||||||
Debug( "Loading monitors\n" );
|
Debug( "Loading monitors\n" );
|
||||||
$monitor_reload_time = time();
|
$monitor_reload_time = time();
|
||||||
|
|
||||||
my %new_monitors = ();
|
my %new_monitors = ();
|
||||||
|
|
||||||
my $sql = "select * from Monitors where find_in_set( Function, 'Modect,Mocord,Nodect' )";
|
my $sql = "SELECT * FROM Monitors
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
WHERE find_in_set( Function, 'Modect,Mocord,Nodect' )"
|
||||||
my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() );
|
;
|
||||||
while( my $monitor = $sth->fetchrow_hashref() )
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
{
|
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||||
next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok
|
my $res = $sth->execute()
|
||||||
|
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||||
|
while( my $monitor = $sth->fetchrow_hashref() )
|
||||||
|
{
|
||||||
|
next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok
|
||||||
|
|
||||||
if ( defined($monitors{$monitor->{Id}}->{LastState}) )
|
if ( defined($monitors{$monitor->{Id}}->{LastState}) )
|
||||||
{
|
{
|
||||||
$monitor->{LastState} = $monitors{$monitor->{Id}}->{LastState};
|
$monitor->{LastState} = $monitors{$monitor->{Id}}->{LastState};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$monitor->{LastState} = zmGetMonitorState( $monitor );
|
$monitor->{LastState} = zmGetMonitorState( $monitor );
|
||||||
}
|
}
|
||||||
if ( defined($monitors{$monitor->{Id}}->{LastEvent}) )
|
if ( defined($monitors{$monitor->{Id}}->{LastEvent}) )
|
||||||
{
|
{
|
||||||
$monitor->{LastEvent} = $monitors{$monitor->{Id}}->{LastEvent};
|
$monitor->{LastEvent} = $monitors{$monitor->{Id}}->{LastEvent};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$monitor->{LastEvent} = zmGetLastEvent( $monitor );
|
$monitor->{LastEvent} = zmGetLastEvent( $monitor );
|
||||||
}
|
}
|
||||||
$new_monitors{$monitor->{Id}} = $monitor;
|
$new_monitors{$monitor->{Id}} = $monitor;
|
||||||
}
|
}
|
||||||
%monitors = %new_monitors;
|
%monitors = %new_monitors;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub handleMessage
|
sub handleMessage
|
||||||
{
|
{
|
||||||
my $connection = shift;
|
my $connection = shift;
|
||||||
my $message = shift;
|
my $message = shift;
|
||||||
|
|
||||||
my ( $id, $action, $score, $cause, $text, $showtext ) = split( /\|/, $message );
|
my ( $id, $action, $score, $cause, $text, $showtext )
|
||||||
$score = 0 if ( !defined($score) );
|
= split( /\|/, $message );
|
||||||
$cause = "" if ( !defined($cause) );
|
$score = 0 if ( !defined($score) );
|
||||||
$text = "" if ( !defined($text) );
|
$cause = "" if ( !defined($cause) );
|
||||||
|
$text = "" if ( !defined($text) );
|
||||||
|
|
||||||
my $monitor = $monitors{$id};
|
my $monitor = $monitors{$id};
|
||||||
if ( !$monitor )
|
if ( !$monitor )
|
||||||
{
|
{
|
||||||
Warning( "Can't find monitor '$id' for message '$message'\n" );
|
Warning( "Can't find monitor '$id' for message '$message'\n" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Debug( "Found monitor for id '$id'\n" );
|
Debug( "Found monitor for id '$id'\n" );
|
||||||
|
|
||||||
next if ( !zmMemVerify( $monitor ) );
|
next if ( !zmMemVerify( $monitor ) );
|
||||||
|
|
||||||
Debug( "Handling action '$action'\n" );
|
Debug( "Handling action '$action'\n" );
|
||||||
if ( $action =~ /^(enable|disable)(?:\+(\d+))?$/ )
|
if ( $action =~ /^(enable|disable)(?:\+(\d+))?$/ )
|
||||||
{
|
{
|
||||||
my $state = $1;
|
my $state = $1;
|
||||||
my $delay = $2;
|
my $delay = $2;
|
||||||
if ( $state eq "enable" )
|
if ( $state eq "enable" )
|
||||||
{
|
{
|
||||||
zmMonitorEnable( $monitor );
|
zmMonitorEnable( $monitor );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
zmMonitorDisable( $monitor );
|
zmMonitorDisable( $monitor );
|
||||||
}
|
}
|
||||||
# Force a reload
|
# Force a reload
|
||||||
$monitor_reload_time = 0;
|
$monitor_reload_time = 0;
|
||||||
Info( "Set monitor to $state\n" );
|
Info( "Set monitor to $state\n" );
|
||||||
if ( $delay )
|
if ( $delay )
|
||||||
{
|
{
|
||||||
my $action_time = time()+$delay;
|
my $action_time = time()+$delay;
|
||||||
my $action_text = $id."|".(($state eq "enable")?"disable":"enable");
|
my $action_text = $id."|".( ($state eq "enable")
|
||||||
my $action_array = $actions{$action_time};
|
? "disable"
|
||||||
if ( !$action_array )
|
: "enable"
|
||||||
{
|
)
|
||||||
$action_array = $actions{$action_time} = [];
|
;
|
||||||
}
|
my $action_array = $actions{$action_time};
|
||||||
push( @$action_array, { connection=>$connection, message=>$action_text } );
|
if ( !$action_array )
|
||||||
Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" );
|
{
|
||||||
}
|
$action_array = $actions{$action_time} = [];
|
||||||
}
|
}
|
||||||
elsif ( $action =~ /^(on|off)(?:\+(\d+))?$/ )
|
push( @$action_array, { connection=>$connection,
|
||||||
{
|
message=>$action_text
|
||||||
next if ( !$monitor->{Enabled} );
|
}
|
||||||
|
);
|
||||||
|
Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elsif ( $action =~ /^(on|off)(?:\+(\d+))?$/ )
|
||||||
|
{
|
||||||
|
next if ( !$monitor->{Enabled} );
|
||||||
|
|
||||||
my $trigger = $1;
|
my $trigger = $1;
|
||||||
my $delay = $2;
|
my $delay = $2;
|
||||||
my $trigger_data;
|
my $trigger_data;
|
||||||
if ( $trigger eq "on" )
|
if ( $trigger eq "on" )
|
||||||
{
|
{
|
||||||
zmTriggerEventOn( $monitor, $score, $cause, $text );
|
zmTriggerEventOn( $monitor, $score, $cause, $text );
|
||||||
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
|
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
|
||||||
Info( "Trigger '$trigger' '$cause'\n" );
|
Info( "Trigger '$trigger' '$cause'\n" );
|
||||||
}
|
}
|
||||||
elsif ( $trigger eq "off" )
|
elsif ( $trigger eq "off" )
|
||||||
{
|
{
|
||||||
my $last_event = zmGetLastEvent( $monitor );
|
my $last_event = zmGetLastEvent( $monitor );
|
||||||
zmTriggerEventOff( $monitor );
|
zmTriggerEventOff( $monitor );
|
||||||
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
|
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
|
||||||
Info( "Trigger '$trigger'\n" );
|
Info( "Trigger '$trigger'\n" );
|
||||||
# Wait til it's finished
|
# Wait til it's finished
|
||||||
while( zmInAlarm( $monitor ) && ($last_event == zmGetLastEvent( $monitor )) )
|
while( zmInAlarm( $monitor )
|
||||||
|
&& ($last_event == zmGetLastEvent( $monitor ))
|
||||||
|
)
|
||||||
{
|
{
|
||||||
# Tenth of a second
|
# Tenth of a second
|
||||||
usleep( 100000 );
|
usleep( 100000 );
|
||||||
}
|
}
|
||||||
zmTriggerEventCancel( $monitor );
|
zmTriggerEventCancel( $monitor );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Info( "Trigger '$trigger'\n" );
|
Info( "Trigger '$trigger'\n" );
|
||||||
zmTriggerEventCancel( $monitor );
|
zmTriggerEventCancel( $monitor );
|
||||||
}
|
}
|
||||||
if ( $delay )
|
if ( $delay )
|
||||||
{
|
{
|
||||||
my $action_time = time()+$delay;
|
my $action_time = time()+$delay;
|
||||||
#my $action_text = $id."|cancel|0|".$cause."|".$text;
|
#my $action_text = $id."|cancel|0|".$cause."|".$text;
|
||||||
my $action_text = $id."|cancel";
|
my $action_text = $id."|cancel";
|
||||||
my $action_array = $actions{$action_time};
|
my $action_array = $actions{$action_time};
|
||||||
if ( !$action_array )
|
if ( !$action_array )
|
||||||
{
|
{
|
||||||
$action_array = $actions{$action_time} = [];
|
$action_array = $actions{$action_time} = [];
|
||||||
}
|
}
|
||||||
push( @$action_array, { connection=>$connection, message=>$action_text } );
|
push( @$action_array, { connection=>$connection,
|
||||||
Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" );
|
message=>$action_text
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
elsif( $action eq "cancel" )
|
Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" );
|
||||||
{
|
}
|
||||||
zmTriggerEventCancel( $monitor );
|
}
|
||||||
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
|
elsif( $action eq "cancel" )
|
||||||
Info( "Cancelled event\n" );
|
{
|
||||||
}
|
zmTriggerEventCancel( $monitor );
|
||||||
elsif( $action eq "show" )
|
zmTriggerShowtext( $monitor, $showtext ) if defined($showtext);
|
||||||
{
|
Info( "Cancelled event\n" );
|
||||||
zmTriggerShowtext( $monitor, $showtext );
|
}
|
||||||
Info( "Updated show text to '$showtext'\n" );
|
elsif( $action eq "show" )
|
||||||
}
|
{
|
||||||
else
|
zmTriggerShowtext( $monitor, $showtext );
|
||||||
{
|
Info( "Updated show text to '$showtext'\n" );
|
||||||
Error( "Unrecognised action '$action' in message '$message'\n" );
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
Error( "Unrecognised action '$action' in message '$message'\n" );
|
||||||
|
}
|
||||||
} # end sub handleMessage
|
} # end sub handleMessage
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -76,7 +76,7 @@ use POSIX;
|
||||||
use DBI;
|
use DBI;
|
||||||
use Getopt::Long;
|
use Getopt::Long;
|
||||||
use autouse 'Pod::Usage'=>qw(pod2usage);
|
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||||
use Data::Dumper;
|
use autouse 'Data::Dumper'=>qw(Dumper);
|
||||||
|
|
||||||
use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS});
|
use constant EVENT_PATH => ($Config{ZM_DIR_EVENTS}=~m|/|)?$Config{ZM_DIR_EVENTS}:($Config{ZM_PATH_WEB}.'/'.$Config{ZM_DIR_EVENTS});
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,37 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
|
||||||
# This script is used to create MPEG videos of events for the web pages
|
=head1 NAME
|
||||||
# or as email attachments.
|
|
||||||
#
|
zmvideo.pl - ZoneMinder Video Creation Script
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
zmvideo.pl -e <event_id>,--event=<event_id> [--format <format>]
|
||||||
|
[--rate=<rate>]
|
||||||
|
[--scale=<scale>]
|
||||||
|
[--fps=<fps>]
|
||||||
|
[--size=<size>]
|
||||||
|
[--overwrite]
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
This script is used to create MPEG videos of events for the web pages
|
||||||
|
or as email attachments.
|
||||||
|
|
||||||
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
-e<event_id>, --event=<event_id> - What event to create the video for
|
||||||
|
-f<format>, --format=<format> - What format to create the video in, default is mpg. For ffmpeg only.
|
||||||
|
-r<rate>, --rate=<rate> - Relative rate, 1 = realtime, 2 = double speed, 0.5 = half speed etc.
|
||||||
|
-s<scale>, --scale=<scale> - Scale, 1 = normal, 2 = double size, 0.5 = half size etc.
|
||||||
|
-F<fps>, --fps=<fps> - Absolute frame rate, in frames per second
|
||||||
|
-S<size>, --size=<size> - Absolute video size, WxH or other specification supported by ffmpeg
|
||||||
|
-o, --overwrite - Whether to overwrite an existing file, off by default.
|
||||||
|
-v, --version - Outputs the currently installed version of ZoneMinder
|
||||||
|
|
||||||
|
=cut
|
||||||
use strict;
|
use strict;
|
||||||
use bytes;
|
use bytes;
|
||||||
|
|
||||||
|
@ -36,9 +63,10 @@ use bytes;
|
||||||
@EXTRA_PERL_LIB@
|
@EXTRA_PERL_LIB@
|
||||||
use ZoneMinder;
|
use ZoneMinder;
|
||||||
use DBI;
|
use DBI;
|
||||||
use Data::Dumper;
|
use autouse 'Data::Dumper'=>qw(Dumper);
|
||||||
use POSIX qw(strftime);
|
use POSIX qw(strftime);
|
||||||
use Getopt::Long qw(:config no_ignore_case );
|
use Getopt::Long qw(:config no_ignore_case );
|
||||||
|
use autouse 'Pod::Usage'=>qw(pod2usage);
|
||||||
|
|
||||||
$| = 1;
|
$| = 1;
|
||||||
|
|
||||||
|
@ -60,77 +88,66 @@ my $version = 0;
|
||||||
my @formats = split( /\s+/, $Config{ZM_FFMPEG_FORMATS} );
|
my @formats = split( /\s+/, $Config{ZM_FFMPEG_FORMATS} );
|
||||||
for ( my $i = 0; $i < @formats; $i++ )
|
for ( my $i = 0; $i < @formats; $i++ )
|
||||||
{
|
{
|
||||||
if ( $i =~ /^(.+)\*$/ )
|
if ( $i =~ /^(.+)\*$/ )
|
||||||
{
|
{
|
||||||
$format = $formats[$i] = $1;
|
$format = $formats[$i] = $1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub Usage
|
GetOptions(
|
||||||
{
|
'event=i' =>\$event_id,
|
||||||
print( "
|
'format|f=s' =>\$format,
|
||||||
Usage: zmvideo.pl -e <event_id>,--event=<event_id> [--format <format>] [--rate=<rate>] [--scale=<scale>] [--fps=<fps>] [--size=<size>] [--overwrite]
|
'rate|r=f' =>\$rate,
|
||||||
Parameters are :-
|
'scale|s=f' =>\$scale,
|
||||||
-e<event_id>, --event=<event_id> - What event to create the video for
|
'fps|F=f' =>\$fps,
|
||||||
-f<format>, --format=<format> - What format to create the video in, default is mpg. For ffmpeg only.
|
'size|S=s' =>\$size,
|
||||||
-r<rate>, --rate=<rate> - Relative rate , 1 = realtime, 2 = double speed , 0.5 = half speed etc
|
'overwrite' =>\$overwrite,
|
||||||
-s<scale>, --scale=<scale> - Scale, 1 = normal, 2 = double size, 0.5 = half size etc
|
'version' =>\$version
|
||||||
-F<fps>, --fps=<fps> - Absolute frame rate, in frames per second
|
) or pod2usage(-exitstatus => -1);
|
||||||
-S<size>, --size=<size> - Absolute video size, WxH or other specification supported by ffmpeg
|
|
||||||
-o, --overwrite - Whether to overwrite an existing file, off by default.
|
|
||||||
-v, --version - Outputs the currently installed version of ZoneMinder
|
|
||||||
");
|
|
||||||
exit( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !GetOptions( 'event=i'=>\$event_id, 'format|f=s'=>\$format, 'rate|r=f'=>\$rate, 'scale|s=f'=>\$scale, 'fps|F=f'=>\$fps, 'size|S=s'=>\$size, 'overwrite'=>\$overwrite, version=>\$version ) )
|
|
||||||
{
|
|
||||||
Usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $version ) {
|
if ( $version ) {
|
||||||
print ZoneMinder::Base::ZM_VERSION . "\n";
|
print ZoneMinder::Base::ZM_VERSION . "\n";
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !$event_id || $event_id < 0 )
|
if ( !$event_id || $event_id < 0 )
|
||||||
{
|
{
|
||||||
print( STDERR "Please give a valid event id\n" );
|
print( STDERR "Please give a valid event id\n" );
|
||||||
Usage();
|
pod2usage(-exitstatus => -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! $Config{ZM_OPT_FFMPEG} )
|
if ( ! $Config{ZM_OPT_FFMPEG} )
|
||||||
{
|
{
|
||||||
print( STDERR "Mpeg encoding is not currently enabled\n" );
|
print( STDERR "Mpeg encoding is not currently enabled\n" );
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !$rate && !$fps )
|
if ( !$rate && !$fps )
|
||||||
{
|
{
|
||||||
$rate = 1;
|
$rate = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !$scale && !$size )
|
if ( !$scale && !$size )
|
||||||
{
|
{
|
||||||
$scale = 1;
|
$scale = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $rate && ($rate < 0.25 || $rate > 100) )
|
if ( $rate && ($rate < 0.25 || $rate > 100) )
|
||||||
{
|
{
|
||||||
print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" );
|
print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" );
|
||||||
Usage();
|
pod2usage(-exitstatus => -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $scale && ($scale < 0.25 || $scale > 4) )
|
if ( $scale && ($scale < 0.25 || $scale > 4) )
|
||||||
{
|
{
|
||||||
print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" );
|
print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" );
|
||||||
Usage();
|
pod2usage(-exitstatus => -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $fps && ($fps > 30) )
|
if ( $fps && ($fps > 30) )
|
||||||
{
|
{
|
||||||
print( STDERR "FPS is out of range, <= 30\n" );
|
print( STDERR "FPS is out of range, <= 30\n" );
|
||||||
Usage();
|
pod2usage(-exitstatus => -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
my ( $detaint_format ) = $format =~ /^(\w+)$/;
|
my ( $detaint_format ) = $format =~ /^(\w+)$/;
|
||||||
|
@ -148,9 +165,23 @@ $size = $detaint_size;
|
||||||
my $dbh = zmDbConnect();
|
my $dbh = zmDbConnect();
|
||||||
|
|
||||||
my @filters;
|
my @filters;
|
||||||
my $sql = "select max(F.Delta)-min(F.Delta) as FullLength, E.*, unix_timestamp(E.StartTime) as Time, M.Name as MonitorName, M.Width as MonitorWidth, M.Height as MonitorHeight, M.Palette from Frames as F inner join Events as E on F.EventId = E.Id inner join Monitors as M on E.MonitorId = M.Id where EventId = '$event_id' group by F.EventId";
|
my $sql = " SELECT max(F.Delta)-min(F.Delta) as FullLength,
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
E.*,
|
||||||
my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() );
|
unix_timestamp(E.StartTime) as Time,
|
||||||
|
M.Name as MonitorName,
|
||||||
|
M.Width as MonitorWidth,
|
||||||
|
M.Height as MonitorHeight,
|
||||||
|
M.Palette
|
||||||
|
FROM Frames as F
|
||||||
|
INNER JOIN Events as E on F.EventId = E.Id
|
||||||
|
INNER JOIN Monitors as M on E.MonitorId = M.Id
|
||||||
|
WHERE EventId = '$event_id'
|
||||||
|
GROUP BY F.EventId"
|
||||||
|
;
|
||||||
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
|
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||||
|
my $res = $sth->execute()
|
||||||
|
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||||
my $event = $sth->fetchrow_hashref();
|
my $event = $sth->fetchrow_hashref();
|
||||||
$sth->finish();
|
$sth->finish();
|
||||||
my $event_path = getEventPath( $event );
|
my $event_path = getEventPath( $event );
|
||||||
|
@ -160,42 +191,42 @@ chdir( $event_path );
|
||||||
my @file_parts;
|
my @file_parts;
|
||||||
if ( $rate )
|
if ( $rate )
|
||||||
{
|
{
|
||||||
my $file_rate = $rate;
|
my $file_rate = $rate;
|
||||||
$file_rate =~ s/\./_/;
|
$file_rate =~ s/\./_/;
|
||||||
$file_rate =~ s/_00//;
|
$file_rate =~ s/_00//;
|
||||||
$file_rate =~ s/(_\d+)0+$/$1/;
|
$file_rate =~ s/(_\d+)0+$/$1/;
|
||||||
$file_rate = 'r'.$file_rate;
|
$file_rate = 'r'.$file_rate;
|
||||||
push( @file_parts, $file_rate );
|
push( @file_parts, $file_rate );
|
||||||
}
|
}
|
||||||
elsif ( $fps )
|
elsif ( $fps )
|
||||||
{
|
{
|
||||||
my $file_fps = $fps;
|
my $file_fps = $fps;
|
||||||
$file_fps =~ s/\./_/;
|
$file_fps =~ s/\./_/;
|
||||||
$file_fps =~ s/_00//;
|
$file_fps =~ s/_00//;
|
||||||
$file_fps =~ s/(_\d+)0+$/$1/;
|
$file_fps =~ s/(_\d+)0+$/$1/;
|
||||||
$file_fps = 'R'.$file_fps;
|
$file_fps = 'R'.$file_fps;
|
||||||
push( @file_parts, $file_fps );
|
push( @file_parts, $file_fps );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $scale )
|
if ( $scale )
|
||||||
{
|
{
|
||||||
my $file_scale = $scale;
|
my $file_scale = $scale;
|
||||||
$file_scale =~ s/\./_/;
|
$file_scale =~ s/\./_/;
|
||||||
$file_scale =~ s/_00//;
|
$file_scale =~ s/_00//;
|
||||||
$file_scale =~ s/(_\d+)0+$/$1/;
|
$file_scale =~ s/(_\d+)0+$/$1/;
|
||||||
$file_scale = 's'.$file_scale;
|
$file_scale = 's'.$file_scale;
|
||||||
push( @file_parts, $file_scale );
|
push( @file_parts, $file_scale );
|
||||||
}
|
}
|
||||||
elsif ( $size )
|
elsif ( $size )
|
||||||
{
|
{
|
||||||
my $file_size = 'S'.$size;
|
my $file_size = 'S'.$size;
|
||||||
push( @file_parts, $file_size );
|
push( @file_parts, $file_size );
|
||||||
}
|
}
|
||||||
my $video_file = "$video_name-".$file_parts[0]."-".$file_parts[1].".$format";
|
my $video_file = "$video_name-".$file_parts[0]."-".$file_parts[1].".$format";
|
||||||
|
|
||||||
if ( $overwrite || !-s $video_file )
|
if ( $overwrite || !-s $video_file )
|
||||||
{
|
{
|
||||||
Info( "Creating video file $video_file for event $event->{Id}\n" );
|
Info( "Creating video file $video_file for event $event->{Id}\n" );
|
||||||
|
|
||||||
my $frame_rate = sprintf( "%.2f", $event->{Frames}/$event->{FullLength} );
|
my $frame_rate = sprintf( "%.2f", $event->{Frames}/$event->{FullLength} );
|
||||||
if ( $rate )
|
if ( $rate )
|
||||||
|
@ -228,22 +259,32 @@ if ( $overwrite || !-s $video_file )
|
||||||
$video_size = $size;
|
$video_size = $size;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $command = $Config{ZM_PATH_FFMPEG}." -y -r $frame_rate ".$Config{ZM_FFMPEG_INPUT_OPTIONS}." -i %0".$Config{ZM_EVENT_IMAGE_DIGITS}."d-capture.jpg -s $video_size ".$Config{ZM_FFMPEG_OUTPUT_OPTIONS}." '$video_file' > ffmpeg.log 2>&1";
|
my $command = $Config{ZM_PATH_FFMPEG}
|
||||||
|
." -y -r $frame_rate "
|
||||||
|
.$Config{ZM_FFMPEG_INPUT_OPTIONS}
|
||||||
|
." -i %0"
|
||||||
|
.$Config{ZM_EVENT_IMAGE_DIGITS}
|
||||||
|
."d-capture.jpg -s $video_size "
|
||||||
|
.$Config{ZM_FFMPEG_OUTPUT_OPTIONS}
|
||||||
|
." '$video_file' > ffmpeg.log 2>&1"
|
||||||
|
;
|
||||||
Debug( $command."\n" );
|
Debug( $command."\n" );
|
||||||
my $output = qx($command);
|
my $output = qx($command);
|
||||||
|
|
||||||
my $status = $? >> 8;
|
my $status = $? >> 8;
|
||||||
if ( $status )
|
if ( $status )
|
||||||
{
|
{
|
||||||
Error( "Unable to generate video, check ".$event_path."/ffmpeg.log for details" );
|
Error( "Unable to generate video, check "
|
||||||
|
.$event_path."/ffmpeg.log for details"
|
||||||
|
);
|
||||||
exit( -1 );
|
exit( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
Info( "Finished $video_file\n" );
|
Info( "Finished $video_file\n" );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Info( "Video file $video_file already exists for event $event->{Id}\n" );
|
Info( "Video file $video_file already exists for event $event->{Id}\n" );
|
||||||
}
|
}
|
||||||
#print( STDOUT $event->{MonitorId}.'/'.$event->{Id}.'/'.$video_file."\n" );
|
#print( STDOUT $event->{MonitorId}.'/'.$event->{Id}.'/'.$video_file."\n" );
|
||||||
print( STDOUT $video_file."\n" );
|
print( STDOUT $video_file."\n" );
|
||||||
|
|
|
@ -20,11 +20,22 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
#
|
|
||||||
# This does some basic setup for ZoneMinder to run and then periodically
|
=head1 NAME
|
||||||
# checks the fps output of the active daemons to check they haven't
|
|
||||||
# locked up. If they have then they are killed and restarted
|
zmwatch.pl - ZoneMinder WatchDog Script
|
||||||
#
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
zmwatch.pl
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
This does some basic setup for ZoneMinder to run and then periodically
|
||||||
|
checks the fps output of the active daemons to check they haven't
|
||||||
|
locked up. If they have then they are killed and restarted
|
||||||
|
|
||||||
|
=cut
|
||||||
use strict;
|
use strict;
|
||||||
use bytes;
|
use bytes;
|
||||||
|
|
||||||
|
@ -46,7 +57,7 @@ use constant START_DELAY => 30; # To give everything else time to start
|
||||||
use ZoneMinder;
|
use ZoneMinder;
|
||||||
use POSIX;
|
use POSIX;
|
||||||
use DBI;
|
use DBI;
|
||||||
use Data::Dumper;
|
use autouse 'Data::Dumper'=>qw(Dumper);
|
||||||
|
|
||||||
$| = 1;
|
$| = 1;
|
||||||
|
|
||||||
|
@ -54,14 +65,6 @@ $ENV{PATH} = '/bin:/usr/bin';
|
||||||
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
|
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
|
||||||
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
||||||
|
|
||||||
sub Usage
|
|
||||||
{
|
|
||||||
print( "
|
|
||||||
Usage: zmwatch.pl
|
|
||||||
");
|
|
||||||
exit( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
logInit();
|
logInit();
|
||||||
logSetSignal();
|
logSetSignal();
|
||||||
|
|
||||||
|
@ -72,38 +75,49 @@ sleep( START_DELAY );
|
||||||
my $dbh = zmDbConnect();
|
my $dbh = zmDbConnect();
|
||||||
|
|
||||||
my $sql = "select * from Monitors";
|
my $sql = "select * from Monitors";
|
||||||
my $sth = $dbh->prepare_cached( $sql ) or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
my $sth = $dbh->prepare_cached( $sql )
|
||||||
|
or Fatal( "Can't prepare '$sql': ".$dbh->errstr() );
|
||||||
|
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
my $now = time();
|
my $now = time();
|
||||||
my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() );
|
my $res = $sth->execute()
|
||||||
while( my $monitor = $sth->fetchrow_hashref() )
|
or Fatal( "Can't execute: ".$sth->errstr() );
|
||||||
{
|
while( my $monitor = $sth->fetchrow_hashref() )
|
||||||
if ( $monitor->{Function} ne 'None' )
|
{
|
||||||
{
|
if ( $monitor->{Function} ne 'None' )
|
||||||
|
{
|
||||||
my $restart = 0;
|
my $restart = 0;
|
||||||
if ( zmMemVerify( $monitor ) && zmMemRead( $monitor, "shared_data:valid" ) )
|
if ( zmMemVerify( $monitor )
|
||||||
{
|
&& zmMemRead( $monitor, "shared_data:valid" )
|
||||||
# Check we have got an image recently
|
)
|
||||||
my $image_time = zmGetLastWriteTime( $monitor );
|
{
|
||||||
next if ( !defined($image_time) ); # Can't read from shared data
|
# Check we have got an image recently
|
||||||
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died.
|
my $image_time = zmGetLastWriteTime( $monitor );
|
||||||
|
next if ( !defined($image_time) ); # Can't read from shared data
|
||||||
|
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died.
|
||||||
|
|
||||||
my $max_image_delay = ($monitor->{MaxFPS}&&($monitor->{MaxFPS}>0)&&($monitor->{MaxFPS}<1))?(3/$monitor->{MaxFPS}):$Config{ZM_WATCH_MAX_DELAY};
|
my $max_image_delay = ( $monitor->{MaxFPS}
|
||||||
my $image_delay = $now-$image_time;
|
&&($monitor->{MaxFPS}>0)
|
||||||
Debug( "Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay\n" );
|
&&($monitor->{MaxFPS}<1)
|
||||||
if ( $image_delay > $max_image_delay )
|
) ? (3/$monitor->{MaxFPS})
|
||||||
{
|
: $Config{ZM_WATCH_MAX_DELAY}
|
||||||
Info( "Restarting capture daemon for ".$monitor->{Name}.", time since last capture $image_delay seconds ($now-$image_time)\n" );
|
;
|
||||||
|
my $image_delay = $now-$image_time;
|
||||||
|
Debug( "Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay\n" );
|
||||||
|
if ( $image_delay > $max_image_delay )
|
||||||
|
{
|
||||||
|
Info( "Restarting capture daemon for "
|
||||||
|
.$monitor->{Name}.", time since last capture $image_delay seconds ($now-$image_time)\n"
|
||||||
|
);
|
||||||
$restart = 1;
|
$restart = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#Info( "Restarting capture daemon for ".$monitor->{Name}.", shared data not valid\n" );
|
#Info( "Restarting capture daemon for ".$monitor->{Name}.", shared data not valid\n" );
|
||||||
#$restart = 1;
|
#$restart = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $restart )
|
if ( $restart )
|
||||||
{
|
{
|
||||||
|
@ -120,19 +134,28 @@ while( 1 )
|
||||||
}
|
}
|
||||||
elsif ( $monitor->{Function} ne 'Monitor' )
|
elsif ( $monitor->{Function} ne 'Monitor' )
|
||||||
{
|
{
|
||||||
if ( zmMemVerify( $monitor ) && zmMemRead( $monitor, "shared_data:valid" ) )
|
if ( zmMemVerify( $monitor )
|
||||||
|
&& zmMemRead( $monitor, "shared_data:valid" )
|
||||||
|
)
|
||||||
{
|
{
|
||||||
# Check we have got an image recently
|
# Check we have got an image recently
|
||||||
my $image_time = zmGetLastReadTime( $monitor );
|
my $image_time = zmGetLastReadTime( $monitor );
|
||||||
next if ( !defined($image_time) ); # Can't read from shared data
|
next if ( !defined($image_time) ); # Can't read from shared data
|
||||||
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died.
|
next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died.
|
||||||
|
|
||||||
my $max_image_delay = ($monitor->{MaxFPS}&&($monitor->{MaxFPS}>0)&&($monitor->{MaxFPS}<1))?(3/$monitor->{MaxFPS}):$Config{ZM_WATCH_MAX_DELAY};
|
my $max_image_delay = ( $monitor->{MaxFPS}
|
||||||
|
&&($monitor->{MaxFPS}>0)
|
||||||
|
&&($monitor->{MaxFPS}<1)
|
||||||
|
) ? (3/$monitor->{MaxFPS})
|
||||||
|
: $Config{ZM_WATCH_MAX_DELAY}
|
||||||
|
;
|
||||||
my $image_delay = $now-$image_time;
|
my $image_delay = $now-$image_time;
|
||||||
Debug( "Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay\n" );
|
Debug( "Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay\n" );
|
||||||
if ( $image_delay > $max_image_delay )
|
if ( $image_delay > $max_image_delay )
|
||||||
{
|
{
|
||||||
Info( "Restarting analysis daemon for ".$monitor->{Name}.", time since last analysis $image_delay seconds ($now-$image_time)\n" );
|
Info( "Restarting analysis daemon for "
|
||||||
|
.$monitor->{Name}.", time since last analysis $image_delay seconds ($now-$image_time)\n"
|
||||||
|
);
|
||||||
my $command = "zmdc.pl restart zma -m ".$monitor->{Id};
|
my $command = "zmdc.pl restart zma -m ".$monitor->{Id};
|
||||||
runCommand( $command );
|
runCommand( $command );
|
||||||
}
|
}
|
||||||
|
@ -141,8 +164,8 @@ while( 1 )
|
||||||
}
|
}
|
||||||
# Prevent open handles building up if we have connect to shared memory
|
# Prevent open handles building up if we have connect to shared memory
|
||||||
zmMemInvalidate( $monitor );
|
zmMemInvalidate( $monitor );
|
||||||
}
|
}
|
||||||
sleep( $Config{ZM_WATCH_CHECK_INTERVAL} );
|
sleep( $Config{ZM_WATCH_CHECK_INTERVAL} );
|
||||||
}
|
}
|
||||||
Info( "Watchdog exiting\n" );
|
Info( "Watchdog exiting\n" );
|
||||||
exit();
|
exit();
|
||||||
|
|
1105
scripts/zmx10.pl.in
1105
scripts/zmx10.pl.in
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue