diff --git a/scripts/zm.in b/scripts/zm.in index 33c32ac6c..b600cd983 100755 --- a/scripts/zm.in +++ b/scripts/zm.in @@ -16,12 +16,12 @@ LOCKFILE=/var/lock/subsys/zm loadconf() { - if [ -f $ZM_CONFIG ]; then - . $ZM_CONFIG - else - echo "ERROR: $ZM_CONFIG not found." - return 1 - fi + if [ -f $ZM_CONFIG ]; then + . $ZM_CONFIG + else + echo "ERROR: $ZM_CONFIG not found." + return 1 + fi } loadconf @@ -30,95 +30,95 @@ command="$ZM_PATH_BIN/zmpkg.pl" start() { # Commenting out as it is not needed. Leaving as a placeholder for future use. -# zmupdate || return $? - loadconf || return $? - #Make sure the directory for our PID folder exists or create one. - [ ! -d $pidfile ] \ - && mkdir -m 774 $pidfile \ - && chown $ZM_WEB_USER:$ZM_WEB_GROUP $pidfile - #Make sure the folder for the socks file exists or create one - GetPath="select Value from Config where Name='ZM_PATH_SOCKS'" +# zmupdate || return $? + loadconf || return $? + #Make sure the directory for our PID folder exists or create one. + [ ! -d $pidfile ] \ + && mkdir -m 774 $pidfile \ + && chown $ZM_WEB_USER:$ZM_WEB_GROUP $pidfile + #Make sure the folder for the socks file exists or create one + GetPath="select Value from Config where Name='ZM_PATH_SOCKS'" dbHost=`echo $ZM_DB_HOST | cut -d: -f1` dbPort=`echo $ZM_DB_HOST | cut -d: -s -f2` if [ "$dbPort" = "" ] 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 - 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 - [ ! -d $ZM_PATH_SOCK ] \ - && mkdir -m 774 $ZM_PATH_SOCK \ - && chown $ZM_WEB_USER:$ZM_WEB_GROUP $ZM_PATH_SOCK - echo -n $"Starting $prog: " - $command start - RETVAL=$? - [ $RETVAL = 0 ] && success || failure - echo - [ $RETVAL = 0 ] && touch $LOCKFILE - return $RETVAL + [ ! -d $ZM_PATH_SOCK ] \ + && mkdir -m 774 $ZM_PATH_SOCK \ + && chown $ZM_WEB_USER:$ZM_WEB_GROUP $ZM_PATH_SOCK + echo -n $"Starting $prog: " + $command start + RETVAL=$? + [ $RETVAL = 0 ] && success || failure + echo + [ $RETVAL = 0 ] && touch $LOCKFILE + return $RETVAL } stop() { - loadconf - echo -n $"Stopping $prog: " - $command stop - RETVAL=$? - [ $RETVAL = 0 ] && success || failure - echo - [ $RETVAL = 0 ] && rm -f $LOCKFILE + loadconf + echo -n $"Stopping $prog: " + $command stop + RETVAL=$? + [ $RETVAL = 0 ] && success || failure + echo + [ $RETVAL = 0 ] && rm -f $LOCKFILE } zmstatus() { - loadconf - result=`$command status` - if [ "$result" = "running" ]; then - echo "ZoneMinder is running" - $ZM_PATH_BIN/zmu -l - RETVAL=0 - else - echo "ZoneMinder is stopped" - RETVAL=1 - fi + loadconf + result=`$command status` + if [ "$result" = "running" ]; then + echo "ZoneMinder is running" + $ZM_PATH_BIN/zmu -l + RETVAL=0 + else + echo "ZoneMinder is stopped" + RETVAL=1 + fi } zmupdate() { - if [ -x $ZM_PATH_BIN/zmupdate.pl ]; then - $ZM_PATH_BIN/zmupdate.pl -f - fi + if [ -x $ZM_PATH_BIN/zmupdate.pl ]; then + $ZM_PATH_BIN/zmupdate.pl -f + fi } case "$1" in - 'start') - start - ;; - 'stop') - stop - ;; - 'restart') - stop - start - ;; - 'condrestart') - loadconf - result=`$ZM_PATH_BIN/zmdc.pl check` - if [ "$result" = "running" ]; then - $ZM_PATH_BIN/zmdc.pl shutdown > /dev/null - rm -f $LOCKFILE - start - fi - ;; - 'status') - status httpd - status mysqld - zmstatus - ;; - *) - echo "Usage: $0 { start | stop | restart | condrestart | status }" - RETVAL=1 - ;; + 'start') + start + ;; + 'stop') + stop + ;; + 'restart') + stop + start + ;; + 'condrestart') + loadconf + result=`$ZM_PATH_BIN/zmdc.pl check` + if [ "$result" = "running" ]; then + $ZM_PATH_BIN/zmdc.pl shutdown > /dev/null + rm -f $LOCKFILE + start + fi + ;; + 'status') + status httpd + status mysqld + zmstatus + ;; + *) + echo "Usage: $0 { start | stop | restart | condrestart | status }" + RETVAL=1 + ;; esac exit $RETVAL diff --git a/scripts/zmsystemctl.pl.in b/scripts/zmsystemctl.pl.in index 450fc2189..c825d891b 100644 --- a/scripts/zmsystemctl.pl.in +++ b/scripts/zmsystemctl.pl.in @@ -2,7 +2,7 @@ # # ========================================================================== # -# ZoneMinder Update Script, $Date$, $Revision$ +# ZoneMinder systemctl wrapper, $Date$, $Revision$ # Copyright (C) 2001-2008 Philip Coombes # # 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. # # ========================================================================== -# -# 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. -# + +=head1 NAME + +zmsystemctl.pl - ZoneMinder systemctl wrapper + +=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 strict; use bytes; +use autouse 'Pod::Usage'=>qw(pod2usage); @EXTRA_PERL_LIB@ use ZoneMinder::Logger qw(:all); my $command = $ARGV[0]; -if ( (scalar(@ARGV) == 1) && ($command =~ /^(start|stop|restart|version)$/ )) { - $command = $1; +if ( (scalar(@ARGV) == 1) + && ($command =~ /^(start|stop|restart|version)$/ ) +){ + $command = $1; } else { - die(" USAGE: zmsystemctl.pl \n"); + pod2usage(-exitstatus => -1); } my $path = qx(which systemctl); @@ -46,7 +60,7 @@ chomp($path); my $status = $? >> 8; 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" ); diff --git a/scripts/zmtrack.pl.in b/scripts/zmtrack.pl.in index f3a5a0e15..b1eec2d7e 100644 --- a/scripts/zmtrack.pl.in +++ b/scripts/zmtrack.pl.in @@ -20,10 +20,26 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script is used to trigger and cancel alarms from external sources -# using an arbitrary text based format -# + +=head1 NAME + +zmtrack.pl - ZoneMinder Experimental PTZ Tracking Script + +=head1 SYNOPSIS + + zmtrack.pl -m + zmtrack.pl --monitor= + +=head1 OPTIONS + + -m, --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 bytes; @@ -45,8 +61,9 @@ use constant SLEEP_TIME => 10000; # In microseconds use ZoneMinder; use DBI; use POSIX; -use Data::Dumper; +use autouse 'Data::Dumper'=>qw(Dumper); use Getopt::Long; +use autouse 'Pod::Usage'=>qw(pod2usage); use Time::HiRes qw( usleep ); $| = 1; @@ -57,20 +74,8 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; my $mid = 0; -sub Usage -{ - print( " - Usage: zmtrack.pl -m ,--monitor=] - Parameters are :- - -m, --monitor= - Id of the monitor to track - "); - exit( -1 ); -} - -if ( !GetOptions( 'monitor=s'=>\$mid ) ) -{ - Usage(); -} +GetOptions( 'monitor=s'=>\$mid ) + or pod2usage(-exitstatus => -1); logInit(); logSetSignal(); @@ -78,44 +83,52 @@ logSetSignal(); my ( $detaint_mid ) = $mid =~ /^(\d+)$/; $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 $sql = "select C.*,M.* from Monitors as M 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 $sql = "SELECT C.*,M.* FROM Monitors as M + 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(); if ( !$monitor ) { - print( "Can't find monitor '$mid'\n" ); - exit( -1 ); + print( "Can't find monitor '$mid'\n" ); + exit( -1 ); } if ( !$monitor->{Controllable} ) { - print( "Monitor '$mid' is not controllable\n" ); - exit( -1 ); + print( "Monitor '$mid' is not controllable\n" ); + exit( -1 ); } if ( !$monitor->{TrackMotion} ) { - print( "Monitor '$mid' is not configured to track motion\n" ); - exit( -1 ); + print( "Monitor '$mid' is not configured to track motion\n" ); + exit( -1 ); } if ( !$monitor->{CanMoveMap} ) { - print( "Monitor '$mid' cannot move in map mode" ); - if ( $monitor->{CanMoveRel} ) - { - print( ", falling back to pseudo map mode\n" ); - } - else - { - print( "\n" ); - exit( -1 ); - } + print( "Monitor '$mid' cannot move in map mode" ); + if ( $monitor->{CanMoveRel} ) + { + print( ", falling back to pseudo map mode\n" ); + } + else + { + print( "\n" ); + exit( -1 ); + } } Debug( "Found monitor for id '$monitor'\n" ); @@ -123,84 +136,100 @@ exit( -1 ) if ( !zmMemVerify( $monitor ) ); sub Suspend { - my $monitor = shift; - zmMonitorSuspend( $monitor ); + my $monitor = shift; + zmMonitorSuspend( $monitor ); } sub Resume { - my $monitor = shift; - sleep( $monitor->{TrackDelay} ); - zmMonitorResume( $monitor ); + my $monitor = shift; + sleep( $monitor->{TrackDelay} ); + zmMonitorResume( $monitor ); } sub Track { - my $monitor = shift; - my ( $x, $y ) = @_; - my ( $detaint_x ) = $x =~ /^(\d+)$/; $x = $detaint_x; - my ( $detaint_y ) = $y =~ /^(\d+)$/; $y = $detaint_y; + my $monitor = shift; + my ( $x, $y ) = @_; + my ( $detaint_x ) = $x =~ /^(\d+)$/; $x = $detaint_x; + my ( $detaint_y ) = $y =~ /^(\d+)$/; $y = $detaint_y; - my $ctrlCommand = $Config{ZM_PATH_BIN}."/zmcontrol.pl -i ".$monitor->{Id}; - $ctrlCommand .= " --command=".($monitor->{CanMoveMap}?"moveMap":"movePseudoMap")." --xcoord=$x --ycoord=$y"; - executeShellCommand( $ctrlCommand ); + my $ctrlCommand = $Config{ZM_PATH_BIN} + ."/zmcontrol.pl -i " + .$monitor->{Id} + ; + $ctrlCommand .= " --command=" + .( $monitor->{CanMoveMap} ? "moveMap" + : "movePseudoMap" + ) + ." --xcoord=$x --ycoord=$y" + ; + executeShellCommand( $ctrlCommand ); } sub Return { - my $monitor = shift; + my $monitor = shift; - my $ctrlCommand = $Config{ZM_PATH_BIN}."/zmcontrol.pl -i ".$monitor->{Id}; - if ( $monitor->{ReturnLocation} > 0 ) - { - $ctrlCommand .= " --command=presetGoto --preset=".$monitor->{ReturnLocation}; - } - else - { - $ctrlCommand .= " --command=presetHome"; - } - executeShellCommand( $ctrlCommand ); + my $ctrlCommand = $Config{ZM_PATH_BIN} + ."/zmcontrol.pl -i " + .$monitor->{Id} + ; + if ( $monitor->{ReturnLocation} > 0 ) + { + $ctrlCommand .= " --command=presetGoto --preset=" + .$monitor->{ReturnLocation} + ; + } + else + { + $ctrlCommand .= " --command=presetHome"; + } + executeShellCommand( $ctrlCommand ); } my $last_alarm = 0; if ( ($monitor->{ReturnLocation} >= 0) ) { - Suspend( $monitor ); - Return( $monitor ); - Resume( $monitor ); + Suspend( $monitor ); + Return( $monitor ); + Resume( $monitor ); } my $alarmed = undef; while( 1 ) { - if ( zmIsAlarmed( $monitor ) ) - { - my ( $alarm_x, $alarm_y ) = zmGetAlarmLocation( $monitor ); - if ( $alarm_x >= 0 && $alarm_y >= 0 ) - { - Debug( "Got alarm at $alarm_x, $alarm_y\n" ); - Suspend( $monitor ); - Track( $monitor, $alarm_x, $alarm_y ); - Resume( $monitor ); - $last_alarm = time(); - $alarmed = !undef; - } - } - else - { - if ( logDebugging() && $alarmed ) - { - print( "Left alarm state\n" ); - $alarmed = undef; - } - if ( ($monitor->{ReturnLocation} >= 0) && ($last_alarm > 0) && ((time()-$last_alarm) > $monitor->{ReturnDelay}) ) - { - Debug( "Returning to location ".$monitor->{ReturnLocation}."\n" ); - Suspend( $monitor ); - Return( $monitor ); - Resume( $monitor ); - $last_alarm = 0; - } - } - usleep( SLEEP_TIME ); + if ( zmIsAlarmed( $monitor ) ) + { + my ( $alarm_x, $alarm_y ) = zmGetAlarmLocation( $monitor ); + if ( $alarm_x >= 0 && $alarm_y >= 0 ) + { + Debug( "Got alarm at $alarm_x, $alarm_y\n" ); + Suspend( $monitor ); + Track( $monitor, $alarm_x, $alarm_y ); + Resume( $monitor ); + $last_alarm = time(); + $alarmed = !undef; + } + } + else + { + if ( logDebugging() && $alarmed ) + { + print( "Left alarm state\n" ); + $alarmed = undef; + } + if ( ($monitor->{ReturnLocation} >= 0) + && ($last_alarm > 0) + && ((time()-$last_alarm) > $monitor->{ReturnDelay}) + ) + { + Debug( "Returning to location ".$monitor->{ReturnLocation}."\n" ); + Suspend( $monitor ); + Return( $monitor ); + Resume( $monitor ); + $last_alarm = 0; + } + } + usleep( SLEEP_TIME ); } diff --git a/scripts/zmtrigger.pl.in b/scripts/zmtrigger.pl.in index 7dbca9898..e43b00bbb 100644 --- a/scripts/zmtrigger.pl.in +++ b/scripts/zmtrigger.pl.in @@ -20,11 +20,17 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script is used to trigger and cancel alarms from external connections -# using an arbitrary text based format -# -# ========================================================================== + +=head1 NAME + +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 bytes; @@ -52,8 +58,22 @@ use ZoneMinder::Trigger::Channel::Serial; use ZoneMinder::Trigger::Connection; my @connections; -push( @connections, 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=>"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=>"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 Socket; -use Data::Dumper; +use autouse 'Data::Dumper'=>qw(Dumper); use POSIX qw( EINTR ); use Time::HiRes qw( usleep ); @@ -85,8 +105,8 @@ my $dbh = zmDbConnect(); my $base_rin = ''; foreach my $connection ( @connections ) { - Info( "Opening connection '$connection->{name}'\n" ); - $connection->open(); + Info( "Opening connection '$connection->{name}'\n" ); + $connection->open(); } my @in_select_connections = grep { $_->input() && $_->selectable() } @connections; @@ -95,7 +115,7 @@ my @out_connections = grep { $_->output() } @connections; foreach my $connection ( @in_select_connections ) { - vec( $base_rin, $connection->fileno(), 1 ) = 1; + vec( $base_rin, $connection->fileno(), 1 ) = 1; } my %spawned_connections; @@ -111,332 +131,387 @@ my $timeout = SELECT_TIMEOUT; my %actions; while( 1 ) { - $rin = $base_rin; - # Add the file descriptors of any spawned connections - foreach my $fileno ( keys(%spawned_connections) ) - { - vec( $rin, $fileno, 1 ) = 1; - } + $rin = $base_rin; + # Add the file descriptors of any spawned connections + foreach my $fileno ( keys(%spawned_connections) ) + { + vec( $rin, $fileno, 1 ) = 1; + } - my $nfound = select( my $rout = $rin, undef, my $eout = $ein, $timeout ); - if ( $nfound > 0 ) - { - Debug( "Got input from $nfound connections\n" ); - foreach my $connection ( @in_select_connections ) - { - if ( vec( $rout, $connection->fileno(), 1 ) ) - { - Debug( "Got input from connection ".$connection->name()." (".$connection->fileno().")\n" ); - if ( $connection->spawns() ) - { - my $new_connection = $connection->accept(); - $spawned_connections{$new_connection->fileno()} = $new_connection; - Debug( "Added new spawned connection (".$new_connection->fileno()."), ".int(keys(%spawned_connections))." spawned connections\n" ); - } - else - { - 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 ) ) - { - Debug( "Got input from spawned connection ".$connection->name()." (".$connection->fileno().")\n" ); - my $messages = $connection->getMessages(); - if ( defined($messages) ) - { - foreach my $message ( @$messages ) - { - handleMessage( $connection, $message ); - } - } - else - { - 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: $!" ); - } - } + my $nfound = select( my $rout = $rin, undef, my $eout = $ein, $timeout ); + if ( $nfound > 0 ) + { + Debug( "Got input from $nfound connections\n" ); + foreach my $connection ( @in_select_connections ) + { + if ( vec( $rout, $connection->fileno(), 1 ) ) + { + Debug( "Got input from connection " + .$connection->name() + ." (" + .$connection->fileno() + .")\n" + ); + if ( $connection->spawns() ) + { + my $new_connection = $connection->accept(); + $spawned_connections{$new_connection->fileno()} = $new_connection; + Debug( "Added new spawned connection (" + .$new_connection->fileno() + ."), " + .int(keys(%spawned_connections)) + ." spawned connections\n" + ); + } + else + { + 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 ) ) + { + Debug( "Got input from spawned connection " + .$connection->name() + ." (" + .$connection->fileno() + .")\n" + ); + my $messages = $connection->getMessages(); + if ( defined($messages) ) + { + foreach my $message ( @$messages ) + { + handleMessage( $connection, $message ); + } + } + else + { + 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 - foreach my $connection ( @in_poll_connections ) - { - my $messages = $connection->getMessages(); - if ( defined($messages) ) - { - foreach my $message ( @$messages ) - { - handleMessage( $connection, $message ); - } - } - } + # Check polled connections + foreach my $connection ( @in_poll_connections ) + { + my $messages = $connection->getMessages(); + if ( defined($messages) ) + { + foreach my $message ( @$messages ) + { + handleMessage( $connection, $message ); + } + } + } - # Check for alarms that might have happened - my @out_messages; - foreach my $monitor ( values(%monitors) ) - { - my ( $state, $last_event ) = zmMemRead( $monitor, [ "shared_data:state", "shared_data:last_event" ] ); + # Check for alarms that might have happened + my @out_messages; + foreach my $monitor ( values(%monitors) ) + { + 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}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}\n" ); - if ( $state == STATE_ALARM || $state == STATE_ALERT ) # In alarm state - { - if ( !defined($monitor->{LastEvent}) || ($last_event != $monitor->{LastEvent}) ) # A new event - { - push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event ); - } - else # The same one as last time, so ignore it - { - # Do nothing - } - } - elsif ( ($state == STATE_IDLE && $monitor->{LastState} != STATE_IDLE) || ($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE) ) # Out of alarm state - { - push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); - } - elsif ( defined($monitor->{LastEvent}) && ($last_event != $monitor->{LastEvent}) ) # We've missed a whole event - { - push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event ); - push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); - } - $monitor->{LastState} = $state; - $monitor->{LastEvent} = $last_event; - } - 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 ); - } - } + #print( "$monitor->{Id}: S:$state, LE:$last_event\n" ); + #print( "$monitor->{Id}: mS:$monitor->{LastState}, mLE:$monitor->{LastEvent}\n" ); + if ( $state == STATE_ALARM + || $state == STATE_ALERT + ) # In alarm state + { + if ( !defined($monitor->{LastEvent}) + || ($last_event != $monitor->{LastEvent}) + ) # A new event + { + push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event ); + } + else # The same one as last time, so ignore it + { + # Do nothing + } + } + elsif ( ($state == STATE_IDLE + && $monitor->{LastState} != STATE_IDLE + ) + || ($state == STATE_TAPE + && $monitor->{LastState} != STATE_TAPE + ) + ) # Out of alarm state + { + push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); + } + elsif ( defined($monitor->{LastEvent}) + && ($last_event != $monitor->{LastEvent}) + ) # We've missed a whole event + { + push( @out_messages, $monitor->{Id}."|on|".time()."|".$last_event ); + push( @out_messages, $monitor->{Id}."|off|".time()."|".$last_event ); + } + $monitor->{LastState} = $state; + $monitor->{LastEvent} = $last_event; + } + 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)) ); - 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}} ) - { - my $connection = $action->{connection}; - my $message = $action->{message}; - Info( "Found action '$message'\n" ); - handleMessage( $connection, $message ); - } - delete( $actions{$action_time} ); - } + Debug( "Checking for timed actions\n" ) + if ( int(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}} ) + { + my $connection = $action->{connection}; + my $message = $action->{message}; + Info( "Found action '$message'\n" ); + handleMessage( $connection, $message ); + } + delete( $actions{$action_time} ); + } # Allow connections to do their own timed actions - foreach my $connection ( @connections ) - { - my $messages = $connection->timedActions(); - if ( defined($messages) ) - { - foreach my $message ( @$messages ) - { - handleMessage( $connection, $message ); - } - } - } - foreach my $connection ( values(%spawned_connections) ) - { - my $messages = $connection->timedActions(); - if ( defined($messages) ) - { - foreach my $message ( @$messages ) - { - handleMessage( $connection, $message ); - } - } - } + foreach my $connection ( @connections ) + { + my $messages = $connection->timedActions(); + if ( defined($messages) ) + { + foreach my $message ( @$messages ) + { + handleMessage( $connection, $message ); + } + } + } + foreach my $connection ( values(%spawned_connections) ) + { + my $messages = $connection->timedActions(); + if ( defined($messages) ) + { + foreach my $message ( @$messages ) + { + handleMessage( $connection, $message ); + } + } + } - # If necessary reload monitors - if ( (time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL ) - { - foreach my $monitor ( values(%monitors) ) + # If necessary reload monitors + if ( (time() - $monitor_reload_time) > MONITOR_RELOAD_INTERVAL ) + { + foreach my $monitor ( values(%monitors) ) { # Free up any used memory handle zmMemInvalidate( $monitor ); } - loadMonitors(); - } + loadMonitors(); + } } Info( "Trigger daemon exiting\n" ); exit; sub loadMonitors { - Debug( "Loading monitors\n" ); - $monitor_reload_time = time(); + Debug( "Loading monitors\n" ); + $monitor_reload_time = time(); - my %new_monitors = (); + my %new_monitors = (); - my $sql = "select * from Monitors where find_in_set( Function, 'Modect,Mocord,Nodect' )"; - 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() ); - while( my $monitor = $sth->fetchrow_hashref() ) - { - next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok + my $sql = "SELECT * FROM Monitors + WHERE find_in_set( Function, 'Modect,Mocord,Nodect' )" + ; + 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() ); + while( my $monitor = $sth->fetchrow_hashref() ) + { + next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok - if ( defined($monitors{$monitor->{Id}}->{LastState}) ) - { - $monitor->{LastState} = $monitors{$monitor->{Id}}->{LastState}; - } - else - { - $monitor->{LastState} = zmGetMonitorState( $monitor ); - } - if ( defined($monitors{$monitor->{Id}}->{LastEvent}) ) - { - $monitor->{LastEvent} = $monitors{$monitor->{Id}}->{LastEvent}; - } - else - { - $monitor->{LastEvent} = zmGetLastEvent( $monitor ); - } - $new_monitors{$monitor->{Id}} = $monitor; - } - %monitors = %new_monitors; + if ( defined($monitors{$monitor->{Id}}->{LastState}) ) + { + $monitor->{LastState} = $monitors{$monitor->{Id}}->{LastState}; + } + else + { + $monitor->{LastState} = zmGetMonitorState( $monitor ); + } + if ( defined($monitors{$monitor->{Id}}->{LastEvent}) ) + { + $monitor->{LastEvent} = $monitors{$monitor->{Id}}->{LastEvent}; + } + else + { + $monitor->{LastEvent} = zmGetLastEvent( $monitor ); + } + $new_monitors{$monitor->{Id}} = $monitor; + } + %monitors = %new_monitors; } sub handleMessage { - my $connection = shift; - my $message = shift; + my $connection = shift; + my $message = shift; - my ( $id, $action, $score, $cause, $text, $showtext ) = split( /\|/, $message ); - $score = 0 if ( !defined($score) ); - $cause = "" if ( !defined($cause) ); - $text = "" if ( !defined($text) ); + my ( $id, $action, $score, $cause, $text, $showtext ) + = split( /\|/, $message ); + $score = 0 if ( !defined($score) ); + $cause = "" if ( !defined($cause) ); + $text = "" if ( !defined($text) ); - my $monitor = $monitors{$id}; - if ( !$monitor ) - { - Warning( "Can't find monitor '$id' for message '$message'\n" ); - return; - } - Debug( "Found monitor for id '$id'\n" ); + my $monitor = $monitors{$id}; + if ( !$monitor ) + { + Warning( "Can't find monitor '$id' for message '$message'\n" ); + return; + } + Debug( "Found monitor for id '$id'\n" ); - next if ( !zmMemVerify( $monitor ) ); + next if ( !zmMemVerify( $monitor ) ); - Debug( "Handling action '$action'\n" ); - if ( $action =~ /^(enable|disable)(?:\+(\d+))?$/ ) - { - my $state = $1; - my $delay = $2; - if ( $state eq "enable" ) - { - zmMonitorEnable( $monitor ); - } - else - { - zmMonitorDisable( $monitor ); - } - # Force a reload - $monitor_reload_time = 0; - Info( "Set monitor to $state\n" ); - if ( $delay ) - { - my $action_time = time()+$delay; - my $action_text = $id."|".(($state eq "enable")?"disable":"enable"); - my $action_array = $actions{$action_time}; - if ( !$action_array ) - { - $action_array = $actions{$action_time} = []; - } - push( @$action_array, { connection=>$connection, message=>$action_text } ); - Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" ); - } - } - elsif ( $action =~ /^(on|off)(?:\+(\d+))?$/ ) - { - next if ( !$monitor->{Enabled} ); + Debug( "Handling action '$action'\n" ); + if ( $action =~ /^(enable|disable)(?:\+(\d+))?$/ ) + { + my $state = $1; + my $delay = $2; + if ( $state eq "enable" ) + { + zmMonitorEnable( $monitor ); + } + else + { + zmMonitorDisable( $monitor ); + } + # Force a reload + $monitor_reload_time = 0; + Info( "Set monitor to $state\n" ); + if ( $delay ) + { + my $action_time = time()+$delay; + my $action_text = $id."|".( ($state eq "enable") + ? "disable" + : "enable" + ) + ; + my $action_array = $actions{$action_time}; + if ( !$action_array ) + { + $action_array = $actions{$action_time} = []; + } + push( @$action_array, { connection=>$connection, + message=>$action_text + } + ); + 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 $delay = $2; - my $trigger_data; - if ( $trigger eq "on" ) - { - zmTriggerEventOn( $monitor, $score, $cause, $text ); - zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); - Info( "Trigger '$trigger' '$cause'\n" ); - } - elsif ( $trigger eq "off" ) - { + my $trigger = $1; + my $delay = $2; + my $trigger_data; + if ( $trigger eq "on" ) + { + zmTriggerEventOn( $monitor, $score, $cause, $text ); + zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); + Info( "Trigger '$trigger' '$cause'\n" ); + } + elsif ( $trigger eq "off" ) + { my $last_event = zmGetLastEvent( $monitor ); - zmTriggerEventOff( $monitor ); - zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); - Info( "Trigger '$trigger'\n" ); + zmTriggerEventOff( $monitor ); + zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); + Info( "Trigger '$trigger'\n" ); # Wait til it's finished - while( zmInAlarm( $monitor ) && ($last_event == zmGetLastEvent( $monitor )) ) + while( zmInAlarm( $monitor ) + && ($last_event == zmGetLastEvent( $monitor )) + ) { # Tenth of a second usleep( 100000 ); } - zmTriggerEventCancel( $monitor ); - } - else - { - Info( "Trigger '$trigger'\n" ); - zmTriggerEventCancel( $monitor ); - } - if ( $delay ) - { - my $action_time = time()+$delay; - #my $action_text = $id."|cancel|0|".$cause."|".$text; - my $action_text = $id."|cancel"; - my $action_array = $actions{$action_time}; - if ( !$action_array ) - { - $action_array = $actions{$action_time} = []; - } - push( @$action_array, { connection=>$connection, message=>$action_text } ); - Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" ); - } - } - elsif( $action eq "cancel" ) - { - zmTriggerEventCancel( $monitor ); - zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); - Info( "Cancelled event\n" ); - } - elsif( $action eq "show" ) - { - zmTriggerShowtext( $monitor, $showtext ); - Info( "Updated show text to '$showtext'\n" ); - } - else - { - Error( "Unrecognised action '$action' in message '$message'\n" ); - } + zmTriggerEventCancel( $monitor ); + } + else + { + Info( "Trigger '$trigger'\n" ); + zmTriggerEventCancel( $monitor ); + } + if ( $delay ) + { + my $action_time = time()+$delay; + #my $action_text = $id."|cancel|0|".$cause."|".$text; + my $action_text = $id."|cancel"; + my $action_array = $actions{$action_time}; + if ( !$action_array ) + { + $action_array = $actions{$action_time} = []; + } + push( @$action_array, { connection=>$connection, + message=>$action_text + } + ); + Debug( "Added timed event '$action_text', expires at $action_time (+$delay secs)\n" ); + } + } + elsif( $action eq "cancel" ) + { + zmTriggerEventCancel( $monitor ); + zmTriggerShowtext( $monitor, $showtext ) if defined($showtext); + Info( "Cancelled event\n" ); + } + elsif( $action eq "show" ) + { + zmTriggerShowtext( $monitor, $showtext ); + Info( "Updated show text to '$showtext'\n" ); + } + else + { + Error( "Unrecognised action '$action' in message '$message'\n" ); + } } # end sub handleMessage 1; diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in index 522f211ec..75ac52fa0 100644 --- a/scripts/zmupdate.pl.in +++ b/scripts/zmupdate.pl.in @@ -76,7 +76,7 @@ use POSIX; use DBI; use Getopt::Long; 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}); diff --git a/scripts/zmvideo.pl.in b/scripts/zmvideo.pl.in index 2b6765420..6a63502ee 100644 --- a/scripts/zmvideo.pl.in +++ b/scripts/zmvideo.pl.in @@ -20,10 +20,37 @@ # 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 -# or as email attachments. -# + +=head1 NAME + +zmvideo.pl - ZoneMinder Video Creation Script + +=head1 SYNOPSIS + + zmvideo.pl -e ,--event= [--format ] + [--rate=] + [--scale=] + [--fps=] + [--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= - What event to create the video for + -f, --format= - What format to create the video in, default is mpg. For ffmpeg only. + -r, --rate= - Relative rate, 1 = realtime, 2 = double speed, 0.5 = half speed etc. + -s, --scale= - Scale, 1 = normal, 2 = double size, 0.5 = half size etc. + -F, --fps= - Absolute frame rate, in frames per second + -S, --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 bytes; @@ -36,9 +63,10 @@ use bytes; @EXTRA_PERL_LIB@ use ZoneMinder; use DBI; -use Data::Dumper; +use autouse 'Data::Dumper'=>qw(Dumper); use POSIX qw(strftime); use Getopt::Long qw(:config no_ignore_case ); +use autouse 'Pod::Usage'=>qw(pod2usage); $| = 1; @@ -60,77 +88,66 @@ my $version = 0; my @formats = split( /\s+/, $Config{ZM_FFMPEG_FORMATS} ); for ( my $i = 0; $i < @formats; $i++ ) { - if ( $i =~ /^(.+)\*$/ ) - { - $format = $formats[$i] = $1; - } + if ( $i =~ /^(.+)\*$/ ) + { + $format = $formats[$i] = $1; + } } -sub Usage -{ - print( " -Usage: zmvideo.pl -e ,--event= [--format ] [--rate=] [--scale=] [--fps=] [--size=] [--overwrite] -Parameters are :- --e, --event= - What event to create the video for --f, --format= - What format to create the video in, default is mpg. For ffmpeg only. --r, --rate= - Relative rate , 1 = realtime, 2 = double speed , 0.5 = half speed etc --s, --scale= - Scale, 1 = normal, 2 = double size, 0.5 = half size etc --F, --fps= - Absolute frame rate, in frames per second --S, --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(); -} +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 +) or pod2usage(-exitstatus => -1); if ( $version ) { - print ZoneMinder::Base::ZM_VERSION . "\n"; - exit(0); + print ZoneMinder::Base::ZM_VERSION . "\n"; + exit(0); } if ( !$event_id || $event_id < 0 ) { - print( STDERR "Please give a valid event id\n" ); - Usage(); + print( STDERR "Please give a valid event id\n" ); + pod2usage(-exitstatus => -1); } if ( ! $Config{ZM_OPT_FFMPEG} ) { - print( STDERR "Mpeg encoding is not currently enabled\n" ); - exit(-1); + print( STDERR "Mpeg encoding is not currently enabled\n" ); + exit(-1); } if ( !$rate && !$fps ) { - $rate = 1; + $rate = 1; } if ( !$scale && !$size ) { - $scale = 1; + $scale = 1; } if ( $rate && ($rate < 0.25 || $rate > 100) ) { - print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" ); - Usage(); + print( STDERR "Rate is out of range, 0.25 >= rate <= 100\n" ); + pod2usage(-exitstatus => -1); } if ( $scale && ($scale < 0.25 || $scale > 4) ) { - print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" ); - Usage(); + print( STDERR "Scale is out of range, 0.25 >= scale <= 4\n" ); + pod2usage(-exitstatus => -1); } if ( $fps && ($fps > 30) ) { - print( STDERR "FPS is out of range, <= 30\n" ); - Usage(); + print( STDERR "FPS is out of range, <= 30\n" ); + pod2usage(-exitstatus => -1); } my ( $detaint_format ) = $format =~ /^(\w+)$/; @@ -148,9 +165,23 @@ $size = $detaint_size; my $dbh = zmDbConnect(); 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 $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 $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 $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(); $sth->finish(); my $event_path = getEventPath( $event ); @@ -160,42 +191,42 @@ chdir( $event_path ); my @file_parts; if ( $rate ) { - my $file_rate = $rate; - $file_rate =~ s/\./_/; - $file_rate =~ s/_00//; - $file_rate =~ s/(_\d+)0+$/$1/; - $file_rate = 'r'.$file_rate; - push( @file_parts, $file_rate ); + my $file_rate = $rate; + $file_rate =~ s/\./_/; + $file_rate =~ s/_00//; + $file_rate =~ s/(_\d+)0+$/$1/; + $file_rate = 'r'.$file_rate; + push( @file_parts, $file_rate ); } elsif ( $fps ) { - my $file_fps = $fps; - $file_fps =~ s/\./_/; - $file_fps =~ s/_00//; - $file_fps =~ s/(_\d+)0+$/$1/; - $file_fps = 'R'.$file_fps; - push( @file_parts, $file_fps ); + my $file_fps = $fps; + $file_fps =~ s/\./_/; + $file_fps =~ s/_00//; + $file_fps =~ s/(_\d+)0+$/$1/; + $file_fps = 'R'.$file_fps; + push( @file_parts, $file_fps ); } if ( $scale ) { - my $file_scale = $scale; - $file_scale =~ s/\./_/; - $file_scale =~ s/_00//; - $file_scale =~ s/(_\d+)0+$/$1/; - $file_scale = 's'.$file_scale; - push( @file_parts, $file_scale ); + my $file_scale = $scale; + $file_scale =~ s/\./_/; + $file_scale =~ s/_00//; + $file_scale =~ s/(_\d+)0+$/$1/; + $file_scale = 's'.$file_scale; + push( @file_parts, $file_scale ); } elsif ( $size ) { - my $file_size = 'S'.$size; - push( @file_parts, $file_size ); + my $file_size = 'S'.$size; + push( @file_parts, $file_size ); } my $video_file = "$video_name-".$file_parts[0]."-".$file_parts[1].".$format"; 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} ); if ( $rate ) @@ -228,22 +259,32 @@ if ( $overwrite || !-s $video_file ) $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" ); my $output = qx($command); my $status = $? >> 8; 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 ); } - - Info( "Finished $video_file\n" ); + + Info( "Finished $video_file\n" ); } 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 $video_file."\n" ); diff --git a/scripts/zmwatch.pl.in b/scripts/zmwatch.pl.in index bfa8b54bd..7d5193439 100644 --- a/scripts/zmwatch.pl.in +++ b/scripts/zmwatch.pl.in @@ -20,11 +20,22 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# 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 -# + +=head1 NAME + +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 bytes; @@ -46,7 +57,7 @@ use constant START_DELAY => 30; # To give everything else time to start use ZoneMinder; use POSIX; use DBI; -use Data::Dumper; +use autouse 'Data::Dumper'=>qw(Dumper); $| = 1; @@ -54,14 +65,6 @@ $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: zmwatch.pl -"); - exit( -1 ); -} - logInit(); logSetSignal(); @@ -72,38 +75,49 @@ sleep( START_DELAY ); my $dbh = zmDbConnect(); 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 ) { - my $now = time(); - my $res = $sth->execute() or Fatal( "Can't execute: ".$sth->errstr() ); - while( my $monitor = $sth->fetchrow_hashref() ) - { - if ( $monitor->{Function} ne 'None' ) - { + my $now = time(); + my $res = $sth->execute() + or Fatal( "Can't execute: ".$sth->errstr() ); + while( my $monitor = $sth->fetchrow_hashref() ) + { + if ( $monitor->{Function} ne 'None' ) + { my $restart = 0; - 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 - next if ( !$image_time ); # We can't get the last capture time so can't be sure it's died. + 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 + 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 $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" ); + 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; + 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; } - } - else - { - #Info( "Restarting capture daemon for ".$monitor->{Name}.", shared data not valid\n" ); + } + else + { + #Info( "Restarting capture daemon for ".$monitor->{Name}.", shared data not valid\n" ); #$restart = 1; - } + } if ( $restart ) { @@ -120,19 +134,28 @@ while( 1 ) } 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 my $image_time = zmGetLastReadTime( $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} + &&($monitor->{MaxFPS}>0) + &&($monitor->{MaxFPS}<1) + ) ? (3/$monitor->{MaxFPS}) + : $Config{ZM_WATCH_MAX_DELAY} + ; my $image_delay = $now-$image_time; Debug( "Monitor $monitor->{Id} last analysed $image_delay seconds ago, max is $max_image_delay\n" ); 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}; runCommand( $command ); } @@ -141,8 +164,8 @@ while( 1 ) } # Prevent open handles building up if we have connect to shared memory zmMemInvalidate( $monitor ); - } - sleep( $Config{ZM_WATCH_CHECK_INTERVAL} ); + } + sleep( $Config{ZM_WATCH_CHECK_INTERVAL} ); } Info( "Watchdog exiting\n" ); exit(); diff --git a/scripts/zmx10.pl.in b/scripts/zmx10.pl.in index add59034d..17d9546b2 100644 --- a/scripts/zmx10.pl.in +++ b/scripts/zmx10.pl.in @@ -20,10 +20,28 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ========================================================================== -# -# This script controls the monitoring of the X10 interface and the consequent -# management of the ZM daemons based on the receipt of X10 signals. -# + +=head1 NAME + +zmx10.pl - ZoneMinder X10 Control Script + +=head1 SYNOPSIS + + zmx10.pl -c ,--command= [-u ,--unit-code=] + +=head1 DESCRIPTION + +This script controls the monitoring of the X10 interface and the consequent +management of the ZM daemons based on the receipt of X10 signals. + +=head1 OPTIONS + + -c , --command= - Command to issue, one of 'on','off','dim','bright','status','shutdown' + -u , --unit-code= - Unit code to act on required for all commands + except 'status' (optional) and 'shutdown' + -v, --verison - Pirnts the currently installed version of ZoneMinder + +=cut use strict; use bytes; @@ -46,7 +64,8 @@ use ZoneMinder; use POSIX; use Socket; use Getopt::Long; -use Data::Dumper; +use autouse 'Pod::Usage'=>qw(pod2usage); +use autouse 'Data::Dumper'=>qw(Dumper); use constant SOCK_FILE => $Config{ZM_PATH_SOCKS}.'/zmx10.sock'; @@ -56,18 +75,6 @@ $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: zmx10.pl -c ,--command= [-u ,--unit-code=] -Parameters are :- --c , --command= - Command to issue, one of 'on','off','dim','bright','status','shutdown' --u , --unit-code= - Unit code to act on required for all commands except 'status' (optional) and 'shutdown' --v, --verison - Pirnts the currently installed version of ZoneMinder -"); - exit( -1 ); -} - logInit(); logSetSignal(); @@ -75,53 +82,59 @@ my $command; my $unit_code; my $version; -if ( !GetOptions( 'command=s'=>\$command, 'unit-code=i'=>\$unit_code, version=>\$version ) ) -{ - Usage(); -} +GetOptions( + 'command=s' =>\$command, + 'unit-code=i' =>\$unit_code, + 'version' =>\$version +) or pod2usage(-exitstatus => -1); + if ( $version ) { - print ZoneMinder::Base::ZM_VERSION; - exit(0); + print ZoneMinder::Base::ZM_VERSION; + exit(0); } die( "No command given" ) unless( $command ); -die( "No unit code given" ) unless( $unit_code || ($command =~ /(?:start|status|shutdown)/) ); +die( "No unit code given" ) + unless( $unit_code || ($command =~ /(?:start|status|shutdown)/) ); if ( $command eq "start" ) { - X10Server::runServer(); - exit(); + X10Server::runServer(); + exit(); } -socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); +socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) + or Fatal( "Can't open socket: $!" ); my $saddr = sockaddr_un( SOCK_FILE ); if ( !connect( CLIENT, $saddr ) ) { - # The server isn't there - print( "Unable to connect, starting server\n" ); - close( CLIENT ); + # The server isn't there + print( "Unable to connect, starting server\n" ); + close( CLIENT ); - if ( my $cpid = fork() ) - { - # Parent process just sleep and fall through - sleep( 2 ); + if ( my $cpid = fork() ) + { + # Parent process just sleep and fall through + sleep( 2 ); logReinit(); - socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); - connect( CLIENT, $saddr ) or Fatal( "Can't connect: $!" ); - } - elsif ( defined($cpid) ) - { - setpgrp(); + socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) + or Fatal( "Can't open socket: $!" ); + connect( CLIENT, $saddr ) + or Fatal( "Can't connect: $!" ); + } + elsif ( defined($cpid) ) + { + setpgrp(); logReinit(); - X10Server::runServer(); - } - else - { - Fatal( "Can't fork: $!" ); - } + X10Server::runServer(); + } + else + { + Fatal( "Can't fork: $!" ); + } } # The server is there, connect to it #print( "Writing commands\n" ); @@ -132,8 +145,8 @@ print( CLIENT $message ); shutdown( CLIENT, 1 ); while ( my $line = ) { - chomp( $line ); - print( "$line\n" ); + chomp( $line ); + print( "$line\n" ); } close( CLIENT ); #print( "Finished writing, bye\n" ); @@ -156,7 +169,7 @@ use POSIX; use DBI; use Socket; use X10::ActiveHome; -use Data::Dumper; +use autouse 'Data::Dumper'=>qw(Dumper); our $dbh; our $x10; @@ -167,515 +180,599 @@ our %pending_tasks; sub runServer { - Info( "X10 server starting\n" ); + Info( "X10 server starting\n" ); - socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) or Fatal( "Can't open socket: $!" ); - unlink( main::SOCK_FILE ); - my $saddr = sockaddr_un( main::SOCK_FILE ); - bind( SERVER, $saddr ) or Fatal( "Can't bind: $!" ); - listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" ); + socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) + or Fatal( "Can't open socket: $!" ); + unlink( main::SOCK_FILE ); + my $saddr = sockaddr_un( main::SOCK_FILE ); + bind( SERVER, $saddr ) or Fatal( "Can't bind: $!" ); + listen( SERVER, SOMAXCONN ) or Fatal( "Can't listen: $!" ); - $dbh = zmDbConnect(); + $dbh = zmDbConnect(); - $x10 = new X10::ActiveHome( port=>ZM_X10_DEVICE, house_code=>ZM_X10_HOUSE_CODE, debug=>0 ); + $x10 = new X10::ActiveHome( port=>ZM_X10_DEVICE, house_code=>ZM_X10_HOUSE_CODE, debug=>0 ); - loadTasks(); + loadTasks(); - $x10->register_listener( \&x10listen ); + $x10->register_listener( \&x10listen ); - my $rin = ''; - vec( $rin, fileno(SERVER),1) = 1; - vec( $rin, $x10->select_fds(),1) = 1; - my $timeout = 0.2; - #print( "F:".fileno(SERVER)."\n" ); - my $reload = undef; - my $reload_count = 0; - my $reload_limit = &ZM_X10_DB_RELOAD_INTERVAL / $timeout; - while( 1 ) - { - my $nfound = select( my $rout = $rin, undef, undef, $timeout ); - #print( "Off select, NF:$nfound, ER:$!\n" ); - #print( vec( $rout, fileno(SERVER),1)."\n" ); - #print( vec( $rout, $x10->select_fds(),1)."\n" ); - if ( $nfound > 0 ) - { - if ( vec( $rout, fileno(SERVER),1) ) - { - my $paddr = accept( CLIENT, SERVER ); - my $message = ; + my $rin = ''; + vec( $rin, fileno(SERVER),1) = 1; + vec( $rin, $x10->select_fds(),1) = 1; + my $timeout = 0.2; + #print( "F:".fileno(SERVER)."\n" ); + my $reload = undef; + my $reload_count = 0; + my $reload_limit = &ZM_X10_DB_RELOAD_INTERVAL / $timeout; + while( 1 ) + { + my $nfound = select( my $rout = $rin, undef, undef, $timeout ); + #print( "Off select, NF:$nfound, ER:$!\n" ); + #print( vec( $rout, fileno(SERVER),1)."\n" ); + #print( vec( $rout, $x10->select_fds(),1)."\n" ); + if ( $nfound > 0 ) + { + if ( vec( $rout, fileno(SERVER),1) ) + { + my $paddr = accept( CLIENT, SERVER ); + my $message = ; - my ( $command, $unit_code ) = split( /;/, $message ); + my ( $command, $unit_code ) = split( /;/, $message ); - my $device; - if ( defined($unit_code) ) - { - if ( $unit_code < 1 || $unit_code > 16 ) - { - dPrint( ZoneMinder::Logger::ERROR, "Invalid unit code '$unit_code'\n" ); - next; - } + my $device; + if ( defined($unit_code) ) + { + if ( $unit_code < 1 || $unit_code > 16 ) + { + dPrint( ZoneMinder::Logger::ERROR, "Invalid unit code '$unit_code'\n" ); + next; + } - $device = $device_hash{$unit_code}; - if ( !$device ) - { - $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), status=>'unknown' }; - } - } + $device = $device_hash{$unit_code}; + if ( !$device ) + { + $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), + status=>'unknown' + }; + } + } - my $result; - if ( $command eq 'on' ) - { - $result = $device->{appliance}->on(); - } - elsif ( $command eq 'off' ) - { - $result = $device->{appliance}->off(); - } - #elsif ( $command eq 'dim' ) - #{ - #$result = $device->{appliance}->dim(); - #} - #elsif ( $command eq 'bright' ) - #{ - #$result = $device->{appliance}->bright(); - #} - elsif ( $command eq 'status' ) - { - if ( $device ) - { - dPrint( ZoneMinder::Logger::DEBUG, $unit_code." ".$device->{status}."\n" ); - } - else - { - foreach my $unit_code ( sort( keys(%device_hash) ) ) - { - my $device = $device_hash{$unit_code}; - dPrint( ZoneMinder::Logger::DEBUG, $unit_code." ".$device->{status}."\n" ); - } - } - } - elsif ( $command eq 'shutdown' ) - { - last; - } - else - { - dPrint( ZoneMinder::Logger::ERROR, "Invalid command '$command'\n" ); - } - if ( defined($result) ) - { - if ( 1 || $result ) - { - $device->{status} = uc($command); - dPrint( ZoneMinder::Logger::DEBUG, $device->{appliance}->address()." $command, ok\n" ); - #x10listen( new X10::Event( sprintf("%s %s", $device->{appliance}->address, uc($command) ) ) ); - } - else - { - dPrint( ZoneMinder::Logger::ERROR, $device->{appliance}->address()." $command, failed\n" ); - } - } - close( CLIENT ); - } - elsif ( vec( $rout, $x10->select_fds(),1) ) - { - $x10->handle_input(); - } - else - { - Fatal( "Bogus descriptor" ); - } - } - elsif ( $nfound < 0 ) - { - if ( $! != EINTR ) - { - Fatal( "Can't select: $!" ); - } - } - else - { - #print( "Select timed out\n" ); - # Check for state changes - foreach my $monitor_id ( sort(keys(%monitor_hash) ) ) - { - my $monitor = $monitor_hash{$monitor_id}; - my $state = zmGetMonitorState( $monitor ); - if ( !defined($state) ) - { - $reload = !undef; - next; - } - if ( defined( $monitor->{LastState} ) ) - { - my $task_list; - if ( ($state == STATE_ALARM || $state == STATE_ALERT) && ($monitor->{LastState} == STATE_IDLE || $monitor->{LastState} == STATE_TAPE) ) # Gone into alarm state - { - Debug( "Applying ON_list for $monitor_id\n" ); - $task_list = $monitor->{"ON_list"}; - } - elsif ( ($state == STATE_IDLE && $monitor->{LastState} != STATE_IDLE) || ($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE) ) # Come out of alarm state - { - Debug( "Applying OFF_list for $monitor_id\n" ); - $task_list = $monitor->{"OFF_list"}; - } - if ( $task_list ) - { - foreach my $task ( @$task_list ) - { - processTask( $task ); - } - } - } - $monitor->{LastState} = $state; - } + my $result; + if ( $command eq 'on' ) + { + $result = $device->{appliance}->on(); + } + elsif ( $command eq 'off' ) + { + $result = $device->{appliance}->off(); + } + #elsif ( $command eq 'dim' ) + #{ + #$result = $device->{appliance}->dim(); + #} + #elsif ( $command eq 'bright' ) + #{ + #$result = $device->{appliance}->bright(); + #} + elsif ( $command eq 'status' ) + { + if ( $device ) + { + dPrint( ZoneMinder::Logger::DEBUG, $unit_code." ".$device->{status}."\n" ); + } + else + { + foreach my $unit_code ( sort( keys(%device_hash) ) ) + { + my $device = $device_hash{$unit_code}; + dPrint( ZoneMinder::Logger::DEBUG, $unit_code." ".$device->{status}."\n" ); + } + } + } + elsif ( $command eq 'shutdown' ) + { + last; + } + else + { + dPrint( ZoneMinder::Logger::ERROR, "Invalid command '$command'\n" ); + } + if ( defined($result) ) + { + if ( 1 || $result ) + { + $device->{status} = uc($command); + dPrint( ZoneMinder::Logger::DEBUG, $device->{appliance}->address()." $command, ok\n" ); + #x10listen( new X10::Event( sprintf("%s %s", $device->{appliance}->address, uc($command) ) ) ); + } + else + { + dPrint( ZoneMinder::Logger::ERROR, $device->{appliance}->address()." $command, failed\n" ); + } + } + close( CLIENT ); + } + elsif ( vec( $rout, $x10->select_fds(),1) ) + { + $x10->handle_input(); + } + else + { + Fatal( "Bogus descriptor" ); + } + } + elsif ( $nfound < 0 ) + { + if ( $! != EINTR ) + { + Fatal( "Can't select: $!" ); + } + } + else + { + #print( "Select timed out\n" ); + # Check for state changes + foreach my $monitor_id ( sort(keys(%monitor_hash) ) ) + { + my $monitor = $monitor_hash{$monitor_id}; + my $state = zmGetMonitorState( $monitor ); + if ( !defined($state) ) + { + $reload = !undef; + next; + } + if ( defined( $monitor->{LastState} ) ) + { + my $task_list; + if ( ($state == STATE_ALARM || $state == STATE_ALERT) + && ($monitor->{LastState} == STATE_IDLE || $monitor->{LastState} == STATE_TAPE) + ) # Gone into alarm state + { + Debug( "Applying ON_list for $monitor_id\n" ); + $task_list = $monitor->{"ON_list"}; + } + elsif ( ($state == STATE_IDLE && $monitor->{LastState} != STATE_IDLE) + || ($state == STATE_TAPE && $monitor->{LastState} != STATE_TAPE) + ) # Come out of alarm state + { + Debug( "Applying OFF_list for $monitor_id\n" ); + $task_list = $monitor->{"OFF_list"}; + } + if ( $task_list ) + { + foreach my $task ( @$task_list ) + { + processTask( $task ); + } + } + } + $monitor->{LastState} = $state; + } - # Check for pending tasks - my $now = time(); - foreach my $activation_time ( sort(keys(%pending_tasks) ) ) - { - last if ( $activation_time > $now ); - my $pending_list = $pending_tasks{$activation_time}; - foreach my $task ( @$pending_list ) - { - processTask( $task ); - } - delete( $pending_tasks{$activation_time} ); - } - if ( $reload || ++$reload_count >= $reload_limit ) - { - loadTasks(); - $reload = undef; - $reload_count = 0; - } - } - } - Info( "X10 server exiting\n" ); - close( SERVER ); - exit(); + # Check for pending tasks + my $now = time(); + foreach my $activation_time ( sort(keys(%pending_tasks) ) ) + { + last if ( $activation_time > $now ); + my $pending_list = $pending_tasks{$activation_time}; + foreach my $task ( @$pending_list ) + { + processTask( $task ); + } + delete( $pending_tasks{$activation_time} ); + } + if ( $reload || ++$reload_count >= $reload_limit ) + { + loadTasks(); + $reload = undef; + $reload_count = 0; + } + } + } + Info( "X10 server exiting\n" ); + close( SERVER ); + exit(); } sub addToDeviceList { - my $unit_code = shift; - my $event = shift; - my $monitor = shift; - my $function = shift; - my $limit = shift; + my $unit_code = shift; + my $event = shift; + my $monitor = shift; + my $function = shift; + my $limit = shift; - Debug( "Adding to device list, uc:$unit_code, ev:$event, mo:".$monitor->{Id}.", fu:$function, li:$limit\n" ); - my $device = $device_hash{$unit_code}; - if ( !$device ) - { - $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), status=>'unknown' }; - } + Debug( "Adding to device list, uc:$unit_code, ev:$event, mo:" + .$monitor->{Id}.", fu:$function, li:$limit\n" + ); + my $device = $device_hash{$unit_code}; + if ( !$device ) + { + $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), + status=>'unknown' + }; + } - my $task = { type=>"device", monitor=>$monitor, address=>$device->{appliance}->address(), function=>$function }; - if ( $limit ) - { - $task->{limit} = $limit - } + my $task = { type=>"device", + monitor=>$monitor, + address=>$device->{appliance}->address(), + function=>$function + }; + if ( $limit ) + { + $task->{limit} = $limit + } - my $task_list = $device->{$event."_list"}; - if ( !$task_list ) - { - $task_list = $device->{$event."_list"} = []; - } - push( @$task_list, $task ); + my $task_list = $device->{$event."_list"}; + if ( !$task_list ) + { + $task_list = $device->{$event."_list"} = []; + } + push( @$task_list, $task ); } sub addToMonitorList { - my $monitor = shift; - my $event = shift; - my $unit_code = shift; - my $function = shift; - my $limit = shift; + my $monitor = shift; + my $event = shift; + my $unit_code = shift; + my $function = shift; + my $limit = shift; - Debug( "Adding to monitor list, uc:$unit_code, ev:$event, mo:".$monitor->{Id}.", fu:$function, li:$limit\n" ); - my $device = $device_hash{$unit_code}; - if ( !$device ) - { - $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), status=>'unknown' }; - } + Debug( "Adding to monitor list, uc:$unit_code, ev:$event, mo:".$monitor->{Id} + .", fu:$function, li:$limit\n" + ); + my $device = $device_hash{$unit_code}; + if ( !$device ) + { + $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), + status=>'unknown' + }; + } - my $task = { type=>"monitor", device=>$device, id=>$monitor->{Id}, function=>$function }; - if ( $limit ) - { - $task->{limit} = $limit; - } + my $task = { type=>"monitor", + device=>$device, + id=>$monitor->{Id}, + function=>$function + }; + if ( $limit ) + { + $task->{limit} = $limit; + } - my $task_list = $monitor->{$event."_list"}; - if ( !$task_list ) - { - $task_list = $monitor->{$event."_list"} = []; - } - push( @$task_list, $task ); + my $task_list = $monitor->{$event."_list"}; + if ( !$task_list ) + { + $task_list = $monitor->{$event."_list"} = []; + } + push( @$task_list, $task ); } sub loadTasks { - %monitor_hash = (); + %monitor_hash = (); - Debug( "Loading tasks\n" ); - # Clear out all old device task lists - foreach my $unit_code ( sort( keys(%device_hash) ) ) - { - my $device = $device_hash{$unit_code}; - $device->{ON_list} = []; - $device->{OFF_list} = []; - } + Debug( "Loading tasks\n" ); + # Clear out all old device task lists + foreach my $unit_code ( sort( keys(%device_hash) ) ) + { + my $device = $device_hash{$unit_code}; + $device->{ON_list} = []; + $device->{OFF_list} = []; + } - my $sql = "select M.*,T.* from Monitors as M inner join TriggersX10 as T on (M.Id = T.MonitorId) where find_in_set( M.Function, 'Modect,Record,Mocord,Nodect' ) and M.Enabled = 1 and find_in_set( 'X10', M.Triggers )"; - 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() ); - while( my $monitor = $sth->fetchrow_hashref() ) - { - next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok + my $sql = "SELECT M.*,T.* from Monitors as M + INNER JOIN TriggersX10 as T on (M.Id = T.MonitorId) + WHERE find_in_set( M.Function, 'Modect,Record,Mocord,Nodect' ) + AND M.Enabled = 1 + AND find_IN_set( 'X10', M.Triggers )" + ; + 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() ); + while( my $monitor = $sth->fetchrow_hashref() ) + { + next if ( !zmMemVerify( $monitor ) ); # Check shared memory ok - $monitor_hash{$monitor->{Id}} = $monitor; + $monitor_hash{$monitor->{Id}} = $monitor; - if ( $monitor->{Activation} ) - { - Debug( "$monitor->{Name} has active string '$monitor->{Activation}'\n" ); - foreach my $code_string ( split( /,/, $monitor->{Activation} ) ) - { - #Debug( "Code string: $code_string\n" ); - my ( $invert, $unit_code, $modifier, $limit ) = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); - $limit = 0 if ( !$limit ); - if ( $unit_code ) - { - if ( !$modifier || $modifier eq '+' ) - { - addToDeviceList( $unit_code, "ON", $monitor, !$invert?"start_active":"stop_active", $limit ); - } - if ( !$modifier || $modifier eq '-' ) - { - addToDeviceList( $unit_code, "OFF", $monitor, !$invert?"stop_active":"start_active", $limit ); - } - } - } - } - if ( $monitor->{AlarmInput} ) - { - Debug( "$monitor->{Name} has alarm input string '$monitor->{AlarmInput}'\n" ); - foreach my $code_string ( split( /,/, $monitor->{AlarmInput} ) ) - { - #Debug( "Code string: $code_string\n" ); - my ( $invert, $unit_code, $modifier, $limit ) = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); - $limit = 0 if ( !$limit ); - if ( $unit_code ) - { - if ( !$modifier || $modifier eq '+' ) - { - addToDeviceList( $unit_code, "ON", $monitor, !$invert?"start_alarm":"stop_alarm", $limit ); - } - if ( !$modifier || $modifier eq '-' ) - { - addToDeviceList( $unit_code, "OFF", $monitor, !$invert?"stop_alarm":"start_alarm", $limit ); - } - } - } - } - if ( $monitor->{AlarmOutput} ) - { - Debug( "$monitor->{Name} has alarm output string '$monitor->{AlarmOutput}'\n" ); - foreach my $code_string ( split( /,/, $monitor->{AlarmOutput} ) ) - { - #Debug( "Code string: $code_string\n" ); - my ( $invert, $unit_code, $modifier, $limit ) = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); - $limit = 0 if ( !$limit ); - if ( $unit_code ) - { - if ( !$modifier || $modifier eq '+' ) - { - addToMonitorList( $monitor, "ON", $unit_code, !$invert?"on":"off", $limit ); - } - if ( !$modifier || $modifier eq '-' ) - { - addToMonitorList( $monitor, "OFF", $unit_code, !$invert?"off":"on", $limit ); - } - } - } - } + if ( $monitor->{Activation} ) + { + Debug( "$monitor->{Name} has active string '$monitor->{Activation}'\n" ); + foreach my $code_string ( split( /,/, $monitor->{Activation} ) ) + { + #Debug( "Code string: $code_string\n" ); + my ( $invert, $unit_code, $modifier, $limit ) + = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); + $limit = 0 if ( !$limit ); + if ( $unit_code ) + { + if ( !$modifier || $modifier eq '+' ) + { + addToDeviceList( $unit_code, + "ON", + $monitor, + !$invert ? "start_active" + : "stop_active", + $limit + ); + } + if ( !$modifier || $modifier eq '-' ) + { + addToDeviceList( $unit_code, + "OFF", + $monitor, + !$invert ? "stop_active" + : "start_active", + $limit + ); + } + } + } + } + if ( $monitor->{AlarmInput} ) + { + Debug( "$monitor->{Name} has alarm input string '$monitor->{AlarmInput}'\n" ); + foreach my $code_string ( split( /,/, $monitor->{AlarmInput} ) ) + { + #Debug( "Code string: $code_string\n" ); + my ( $invert, $unit_code, $modifier, $limit ) + = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); + $limit = 0 if ( !$limit ); + if ( $unit_code ) + { + if ( !$modifier || $modifier eq '+' ) + { + addToDeviceList( $unit_code, + "ON", + $monitor, + !$invert ? "start_alarm" + : "stop_alarm", + $limit + ); + } + if ( !$modifier || $modifier eq '-' ) + { + addToDeviceList( $unit_code, + "OFF", + $monitor, + !$invert ? "stop_alarm" + : "start_alarm", + $limit + ); + } + } + } + } + if ( $monitor->{AlarmOutput} ) + { + Debug( "$monitor->{Name} has alarm output string '$monitor->{AlarmOutput}'\n" ); + foreach my $code_string ( split( /,/, $monitor->{AlarmOutput} ) ) + { + #Debug( "Code string: $code_string\n" ); + my ( $invert, $unit_code, $modifier, $limit ) + = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ ); + $limit = 0 if ( !$limit ); + if ( $unit_code ) + { + if ( !$modifier || $modifier eq '+' ) + { + addToMonitorList( $monitor, + "ON", + $unit_code, + !$invert ? "on" + : "off", + $limit + ); + } + if ( !$modifier || $modifier eq '-' ) + { + addToMonitorList( $monitor, + "OFF", + $unit_code, + !$invert ? "off" + : "on", + $limit + ); + } + } + } + } zmMemInvalidate( $monitor ); - } + } } sub addPendingTask { - my $task = shift; + my $task = shift; - # Check whether we are just extending a previous pending task - # and remove it if it's there - foreach my $activation_time ( sort(keys(%pending_tasks) ) ) - { - my $pending_list = $pending_tasks{$activation_time}; - my $new_pending_list = []; - foreach my $pending_task ( @$pending_list ) - { - if ( $task->{type} ne $pending_task->{type} ) - { - push( @$new_pending_list, $pending_task ) - } - elsif ( $task->{type} eq "device" ) - { - if (( $task->{monitor}->{Id} != $pending_task->{monitor}->{Id} ) - || ( $task->{function} ne $pending_task->{function} )) - { - push( @$new_pending_list, $pending_task ) - } - } - elsif ( $task->{type} eq "monitor" ) - { - if (( $task->{device}->{appliance}->unit_code() != $pending_task->{device}->{appliance}->unit_code() ) - || ( $task->{function} ne $pending_task->{function} )) - { - push( @$new_pending_list, $pending_task ) - } - } - } - if ( @$new_pending_list ) - { - $pending_tasks{$activation_time} = $new_pending_list; - } - else - { - delete( $pending_tasks{$activation_time} ); - } - } + # Check whether we are just extending a previous pending task + # and remove it if it's there + foreach my $activation_time ( sort(keys(%pending_tasks) ) ) + { + my $pending_list = $pending_tasks{$activation_time}; + my $new_pending_list = []; + foreach my $pending_task ( @$pending_list ) + { + if ( $task->{type} ne $pending_task->{type} ) + { + push( @$new_pending_list, $pending_task ) + } + elsif ( $task->{type} eq "device" ) + { + if (( $task->{monitor}->{Id} != $pending_task->{monitor}->{Id} ) + || ( $task->{function} ne $pending_task->{function} )) + { + push( @$new_pending_list, $pending_task ) + } + } + elsif ( $task->{type} eq "monitor" ) + { + if (( $task->{device}->{appliance}->unit_code() + != $pending_task->{device}->{appliance}->unit_code() + ) + || ( $task->{function} ne $pending_task->{function} ) + ) + { + push( @$new_pending_list, $pending_task ) + } + } + } + if ( @$new_pending_list ) + { + $pending_tasks{$activation_time} = $new_pending_list; + } + else + { + delete( $pending_tasks{$activation_time} ); + } + } - my $end_time = time() + $task->{limit}; - my $pending_list = $pending_tasks{$end_time}; - if ( !$pending_list ) - { - $pending_list = $pending_tasks{$end_time} = []; - } - my $pending_task; - if ( $task->{type} eq "device" ) - { - $pending_task = { type=>$task->{type}, monitor=>$task->{monitor}, function=>$task->{function} }; - $pending_task->{function} =~ s/start/stop/; - } - elsif ( $task->{type} eq "monitor" ) - { - $pending_task = { type=>$task->{type}, device=>$task->{device}, function=>$task->{function} }; - $pending_task->{function} =~ s/on/off/; - } - push( @$pending_list, $pending_task ); + my $end_time = time() + $task->{limit}; + my $pending_list = $pending_tasks{$end_time}; + if ( !$pending_list ) + { + $pending_list = $pending_tasks{$end_time} = []; + } + my $pending_task; + if ( $task->{type} eq "device" ) + { + $pending_task = { type=>$task->{type}, + monitor=>$task->{monitor}, + function=>$task->{function} + }; + $pending_task->{function} =~ s/start/stop/; + } + elsif ( $task->{type} eq "monitor" ) + { + $pending_task = { type=>$task->{type}, + device=>$task->{device}, + function=>$task->{function} + }; + $pending_task->{function} =~ s/on/off/; + } + push( @$pending_list, $pending_task ); } sub processTask { - my $task = shift; + my $task = shift; - if ( $task->{type} eq "device" ) - { - my ( $instruction, $class ) = ( $task->{function} =~ /^(.+)_(.+)$/ ); + if ( $task->{type} eq "device" ) + { + my ( $instruction, $class ) = ( $task->{function} =~ /^(.+)_(.+)$/ ); - if ( $class eq "active" ) - { - if ( $instruction eq "start" ) - { - zmMonitorEnable( $task->{monitor} ); - if ( $task->{limit} ) - { - addPendingTask( $task ); - } - } - elsif( $instruction eq "stop" ) - { - zmMonitorDisable( $task->{monitor} ); - } - } - elsif( $class eq "alarm" ) - { - if ( $instruction eq "start" ) - { - zmTriggerEventOn( $task->{monitor}, 0, main::CAUSE_STRING, $task->{address} ); - if ( $task->{limit} ) - { - addPendingTask( $task ); - } - } - elsif( $instruction eq "stop" ) - { - zmTriggerEventCancel( $task->{monitor} ); - } - } - } - elsif( $task->{type} eq "monitor" ) - { - if ( $task->{function} eq "on" ) - { - $task->{device}->{appliance}->on(); - if ( $task->{limit} ) - { - addPendingTask( $task ); - } - } - elsif ( $task->{function} eq "off" ) - { - $task->{device}->{appliance}->off(); - } - } + if ( $class eq "active" ) + { + if ( $instruction eq "start" ) + { + zmMonitorEnable( $task->{monitor} ); + if ( $task->{limit} ) + { + addPendingTask( $task ); + } + } + elsif( $instruction eq "stop" ) + { + zmMonitorDisable( $task->{monitor} ); + } + } + elsif( $class eq "alarm" ) + { + if ( $instruction eq "start" ) + { + zmTriggerEventOn( $task->{monitor}, + 0, + main::CAUSE_STRING, + $task->{address} + ); + if ( $task->{limit} ) + { + addPendingTask( $task ); + } + } + elsif( $instruction eq "stop" ) + { + zmTriggerEventCancel( $task->{monitor} ); + } + } + } + elsif( $task->{type} eq "monitor" ) + { + if ( $task->{function} eq "on" ) + { + $task->{device}->{appliance}->on(); + if ( $task->{limit} ) + { + addPendingTask( $task ); + } + } + elsif ( $task->{function} eq "off" ) + { + $task->{device}->{appliance}->off(); + } + } } sub dPrint { - my $dbg_level = shift; - if ( fileno(CLIENT) ) - { - print CLIENT @_ - } - if ( $dbg_level == ZoneMinder::Logger::DEBUG ) - { - Debug( @_ ); - } - elsif ( $dbg_level == ZoneMinder::Logger::INFO ) - { - Info( @_ ); - } - elsif ( $dbg_level == ZoneMinder::Logger::WARNING ) - { - Warning( @_ ); - } - elsif ( $dbg_level == ZoneMinder::Logger::ERROR ) - { - Error( @_ ); - } - elsif ( $dbg_level == ZoneMinder::Logger::FATAL ) - { - Fatal( @_ ); - } + my $dbg_level = shift; + if ( fileno(CLIENT) ) + { + print CLIENT @_ + } + if ( $dbg_level == ZoneMinder::Logger::DEBUG ) + { + Debug( @_ ); + } + elsif ( $dbg_level == ZoneMinder::Logger::INFO ) + { + Info( @_ ); + } + elsif ( $dbg_level == ZoneMinder::Logger::WARNING ) + { + Warning( @_ ); + } + elsif ( $dbg_level == ZoneMinder::Logger::ERROR ) + { + Error( @_ ); + } + elsif ( $dbg_level == ZoneMinder::Logger::FATAL ) + { + Fatal( @_ ); + } } sub x10listen { - foreach my $event ( @_ ) - { - #print( Data::Dumper( $_ )."\n" ); - if ( $event->house_code() eq ZM_X10_HOUSE_CODE ) - { - my $unit_code = $event->unit_code(); - my $device = $device_hash{$unit_code}; - if ( !$device ) - { - $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), status=>'unknown' }; - } - next if ( $event->func() !~ /(?:ON|OFF)/ ); - $device->{status} = $event->func(); - my $task_list = $device->{$event->func()."_list"}; - if ( $task_list ) - { - foreach my $task ( @$task_list ) - { - processTask( $task ); - } - } - } - Info( "Got event - ".$event->as_string()."\n" ); - } + foreach my $event ( @_ ) + { + #print( Data::Dumper( $_ )."\n" ); + if ( $event->house_code() eq ZM_X10_HOUSE_CODE ) + { + my $unit_code = $event->unit_code(); + my $device = $device_hash{$unit_code}; + if ( !$device ) + { + $device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), + status=>'unknown' + }; + } + next if ( $event->func() !~ /(?:ON|OFF)/ ); + $device->{status} = $event->func(); + my $task_list = $device->{$event->func()."_list"}; + if ( $task_list ) + { + foreach my $task ( @$task_list ) + { + processTask( $task ); + } + } + } + Info( "Got event - ".$event->as_string()."\n" ); + } } 1;