diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm index ae1259814..5f66dfe12 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Database.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Database.pm @@ -203,27 +203,13 @@ sub zmDbGetMonitor { return undef ; } - my $sql = 'SELECT * FROM Monitors WHERE Id = ?'; - my $sth = $dbh->prepare_cached($sql); - if ( !$sth ) { - Error("Can't prepare '$sql': ".$dbh->errstr()); - return undef; - } - my $res = $sth->execute($id); - if ( !$res ) { - Error("Can't execute '$sql': ".$sth->errstr()); - return undef; - } - my $monitor = $sth->fetchrow_hashref(); - $sth->finish(); - return $monitor; + return zmDbFetchOne('SELECT * FROM Monitors WHERE Id = ?', $id); } sub zmDbGetMonitorAndControl { zmDbConnect(); my $id = shift; - return undef if !defined($id); my $sql = 'SELECT C.*,M.*,C.Protocol @@ -231,19 +217,7 @@ sub zmDbGetMonitorAndControl { INNER JOIN Controls as C on (M.ControlId = C.Id) WHERE M.Id = ?' ; - my $sth = $dbh->prepare_cached($sql); - if ( !$sth ) { - Error("Can't prepare '$sql': ".$dbh->errstr()); - return undef; - } - my $res = $sth->execute( $id ); - if ( !$res ) { - Error("Can't execute '$sql': ".$sth->errstr()); - return undef; - } - my $monitor = $sth->fetchrow_hashref(); - $sth->finish(); - return $monitor; + return zmDbFetchOne($sql); } sub start_transaction { @@ -280,6 +254,24 @@ sub zmDbDo { return $rows; } +sub zmDbFetchOne { + my $sql = shift; + + my $sth = $dbh->prepare_cached($sql); + if (!$sth) { + Error("Can't prepare '$sql': ".$dbh->errstr()); + return undef; + } + my $res = $sth->execute(@_); + if (!$res) { + Error("Can't execute '$sql': ".$sth->errstr()); + return undef; + } + my $row = $sth->fetchrow_hashref(); + $sth->finish(); + return $row; +} + 1; __END__ @@ -302,6 +294,7 @@ zmDbGetMonitors zmDbGetMonitor zmDbGetMonitorAndControl zmDbDo +zmDbFetchOne =head1 AUTHOR diff --git a/scripts/zmonvif-trigger.pl.in b/scripts/zmonvif-trigger.pl.in index 942ee0af0..f1221b322 100644 --- a/scripts/zmonvif-trigger.pl.in +++ b/scripts/zmonvif-trigger.pl.in @@ -203,8 +203,7 @@ sub xs_duration { my %new_monitors = (); - # my $sql = "select * from Monitors where find_in_set( Function, 'Modect,Mocord,Nodect,ExtDect' )>0 and ConfigType='ONVIF'"; - my $sql = "SELECT * FROM Monitors WHERE ONVIF_URL != ''"; + my $sql = "SELECT * FROM Monitors WHERE Capturing != 'None' AND ONVIF_URL != ''"; 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() ) { diff --git a/scripts/zmpkg.pl.in b/scripts/zmpkg.pl.in index 3302b0019..ffa7e3e50 100644 --- a/scripts/zmpkg.pl.in +++ b/scripts/zmpkg.pl.in @@ -32,6 +32,8 @@ use bytes; @EXTRA_PERL_LIB@ use ZoneMinder; +use ZoneMinder::Monitor; +use ZoneMinder::State; use DBI; use POSIX; use Time::HiRes qw/gettimeofday/; @@ -57,26 +59,40 @@ my $dbh = zmDbConnect(); Debug("Command: $command"); if ( $command and ( $command !~ /^(?:start|stop|restart|status|logrot|version)$/ ) ) { # Check to see if it's a valid run state - my $sql = 'SELECT * FROM `States` WHERE `Name`=?'; - my $sth = $dbh->prepare_cached($sql) - or Fatal("Can't prepare '$sql': ".$dbh->errstr()); - my $res = $sth->execute($command) - or Fatal("Can't execute: ".$sth->errstr()); - if ( $state = $sth->fetchrow_hashref() ) { - #$state->{Name} = $command; + if ($state = ZoneMinder->find_one(Name=>$command)) { $state->{Definitions} = []; - foreach( split(',', $state->{Definition}) ) { - my ( $id, $function, $enabled ) = split(':', $_); - push( @{$state->{Definitions}}, - { Id=>$id, Function=>$function, Enabled=>$enabled } - ); - } + foreach (split(',', $state->{Definition})) { + my @state = split(':', $_); + my ($id, $capturing, $analysing, $recording); + if (@state == 3) { + ($id, my $function, my $enabled) = @state; + if (!$enabled) { + ($capturing, $analysing, $recording) = ('None','None','None'); + } elsif ($function eq 'None') { + ($capturing, $analysing, $recording) = ('None','None','None'); + } elsif ($function eq 'Monitor') { + ($capturing, $analysing, $recording) = ('Always','None','None'); + } elsif ($function eq 'Modect') { + ($capturing, $analysing, $recording) = ('Always','Always','OnMotion'); + } elsif ($function eq 'Mocord') { + ($capturing, $analysing, $recording) = ('Always','Always','OnMotion'); + } elsif ($function eq 'Record') { + ($capturing, $analysing, $recording) = ('Always','Always','Always'); + } else { + Error("Unknown function $function, defaulting to Mocord"); + } + } elsif (@state == 4) { + ($id, $capturing, $analysing, $capturing) = @state; + } else { + Error("Unknown state in @state"); + } + push @{$state->{Definitions}}, {Id=>$id, Capturing=>$capturing, Analysing=>$analysing, Recording=>$recording}; + } # end foreach state definition $store_state = $command; # PP - Remember the name that was passed to search in DB $command = 'state'; } else { $command = undef; } - $sth->finish(); } # end if not one of the usual commands if ( !$command ) { @@ -87,8 +103,7 @@ if ( !$command ) { isActiveSanityCheck(); # Move to the right place -chdir($Config{ZM_PATH_WEB}) - or Fatal("Can't chdir to '$Config{ZM_PATH_WEB}': $!"); +chdir($Config{ZM_PATH_WEB}) or Fatal("Can't chdir to $Config{ZM_PATH_WEB}: $!"); my $dbg_id = ''; @@ -98,42 +113,33 @@ my $retval = 0; if ( $command eq 'state' ) { Info("Updating DB: $state->{Name}"); - my $sql = 'SELECT * FROM `Monitors`' . ($Config{ZM_SERVER_ID} ? ' WHERE `ServerId`=?' : '' ) .' ORDER BY `Id` ASC'; - my $sth = $dbh->prepare_cached($sql) - or Fatal("Can't prepare '$sql': ".$dbh->errstr()); - my $res = $sth->execute($Config{ZM_SERVER_ID} ? $Config{ZM_SERVER_ID}: ()) - or Fatal("Can't execute: ".$sth->errstr()); - while ( my $monitor = $sth->fetchrow_hashref() ) { + foreach my $monitor (ZoneMinder::Monitor->find( + ($Config{ZM_SERVER_ID} ? (ServerId=>$Config{ZM_SERVER_ID}) : () ), order=>'Id ASC') + ) { foreach my $definition ( @{$state->{Definitions}} ) { +# FIXME WHY a REGEXP if ( $monitor->{Id} =~ /^$definition->{Id}$/ ) { $monitor->{NewFunction} = $definition->{Function}; $monitor->{NewEnabled} = $definition->{Enabled}; last; } - } - next if ! exists $monitor->{NewFunction}; - $monitor->{NewFunction} = 'None' if !$monitor->{NewFunction}; - $monitor->{NewEnabled} = 0 if !$monitor->{NewEnabled}; - if ( $monitor->{Function} ne $monitor->{NewFunction} - || $monitor->{Enabled} ne $monitor->{NewEnabled} - ) { - my $sql = 'UPDATE `Monitors` SET `Function`=?, `Enabled`=? WHERE `Id`=?'; - my $sth = $dbh->prepare_cached($sql) - or Fatal("Can't prepare '$sql': ".$dbh->errstr()); - my $res = $sth->execute($monitor->{NewFunction}, $monitor->{NewEnabled}, $monitor->{Id}) - or Fatal("Can't execute: ".$sth->errstr()); - } # end if change of function or enablement + if ( + ($monitor->{Capturing} ne $definition->{Capturing}) + or + ($monitor->{Analysing} ne $definition->{Analysing}) + or + ($monitor->{Recording} ne $definition->{Recording}) + ) { + $monitor->save({ map { $_ => $definition{$_} } qw(Capturing Analysing Recording) }); + last; # definition + } # end if + } # end foreach definition } # end foreach monitor - $sth->finish(); # PP - Now mark a specific state as active resetStates(); Info("Marking $store_state as Enabled"); - $sql = 'UPDATE `States` SET `IsActive` = 1 WHERE `Name` = ?'; - $sth = $dbh->prepare_cached($sql) - or Fatal("Can't prepare '$sql': ".$dbh->errstr()); - $res = $sth->execute($store_state) - or Fatal("Can't execute: ".$sth->errstr()); + $state->save({IsActive=>1}); # PP - zero out other states isActive $command = 'restart'; @@ -199,63 +205,46 @@ if ( $command =~ /^(?:start|restart)$/ ) { runCommand('zmdc.pl startup'); my $Server = undef; - my $sql; - my @values; + my @monitors; if ( $Config{ZM_SERVER_ID} ) { require ZoneMinder::Server; Info("Multi-server configuration detected. Starting up services for server $Config{ZM_SERVER_ID}"); $Server = new ZoneMinder::Server($Config{ZM_SERVER_ID}); - $sql = 'SELECT * FROM `Monitors` WHERE `ServerId`=?'; - @values = ( $Config{ZM_SERVER_ID} ); + @monitors = ZoneMinder::Monitor->find(ServerId=>$Config{ZM_SERVER_ID}); } else { Info('Single server configuration detected. Starting up services.'); - $sql = 'SELECT * FROM `Monitors`'; + @monitors = ZoneMinder::Monitor->find(ServerId=>$Config{ZM_SERVER_ID}); } - { - my $sth = $dbh->prepare_cached($sql) - or Fatal("Can't prepare '$sql': ".$dbh->errstr()); - my $res = $sth->execute(@values) - or Fatal("Can't execute: ".$sth->errstr()); - while( my $monitor = $sth->fetchrow_hashref() ) { - if ( $monitor->{Function} ne 'None' && $monitor->{Type} ne 'WebSite' ) { - if ( $monitor->{Type} eq 'Local' ) { - runCommand("zmdc.pl start zmc -d $monitor->{Device}"); - } else { - runCommand("zmdc.pl start zmc -m $monitor->{Id}"); - } - if ( $Config{ZM_OPT_CONTROL} ) { - if ( $monitor->{Controllable} ) { - runCommand("zmdc.pl start zmcontrol.pl --id $monitor->{Id}"); - if ( $monitor->{TrackMotion} ) { - if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' ) { - runCommand("zmdc.pl start zmtrack.pl -m $monitor->{Id}"); - } else { - Warning('Monitor is set to track motion, but does not have motion detection enabled.'); - } # end if Has motion enabled - } # end if track motion - } # end if controllable - } # end if ZM_OPT_CONTROL - } # end if function is not none or Website - } # end foreach monitor - $sth->finish(); - } - - { - my $sql = 'SELECT `Id` FROM `Filters` WHERE `Background`=1'; - 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()); - if ( $sth->rows ) { - while( my $filter = $sth->fetchrow_hashref() ) { - # This is now started unconditionally - runCommand("zmdc.pl start zmfilter.pl --filter_id=$$filter{Id} --daemon"); + foreach my $monitor (@monitors) { + if ( $monitor->{Capturing} ne 'None' && $monitor->{Type} ne 'WebSite' ) { + if ( $monitor->{Type} eq 'Local' ) { + runCommand("zmdc.pl start zmc -d $monitor->{Device}"); + } else { + runCommand("zmdc.pl start zmc -m $monitor->{Id}"); } - } else { - runCommand('zmdc.pl start zmfilter.pl'); + if ( $Config{ZM_OPT_CONTROL} ) { + if ( $monitor->{Controllable} ) { + runCommand("zmdc.pl start zmcontrol.pl --id $monitor->{Id}"); + if ( $monitor->{TrackMotion} ) { + if ( $monitor->{Function} eq 'Modect' || $monitor->{Function} eq 'Mocord' ) { + runCommand("zmdc.pl start zmtrack.pl -m $monitor->{Id}"); + } else { + Warning('Monitor is set to track motion, but does not have motion detection enabled.'); + } # end if Has motion enabled + } # end if track motion + } # end if controllable + } # end if ZM_OPT_CONTROL + } # end if capturing is not none or Website + } # end foreach monitor + + my @filters = ZoneMinder::Filter->find(Background=>1); + if (@filters) { + foreach my $filter (@filters) { + runCommand("zmdc.pl start zmfilter.pl --filter_id=$$filter{Id} --daemon"); } - $sth->finish(); + } else { + runCommand('zmdc.pl start zmfilter.pl'); } if ( $Config{ZM_RUN_AUDIT} ) { @@ -283,8 +272,8 @@ if ( $command =~ /^(?:start|restart)$/ ) { runCommand('zmdc.pl start zmtelemetry.pl'); } if ($Config{ZM_OPT_USE_EVENTNOTIFICATION} ) { - if ( $Server and exists $$Server{'zmeventnotification'} and ! $$Server{'zmeventnotification'} ) { - Debug("Not running zmnotification.pl because it is turned off for this server."); + if ( $Server and exists $$Server{zmeventnotification} and ! $$Server{zmeventnotification} ) { + Debug('Not running zmnotification.pl because it is turned off for this server.'); } else { runCommand('zmdc.pl start zmeventnotification.pl'); } @@ -302,11 +291,11 @@ if ( $command =~ /^(?:start|restart)$/ ) { } } # end if command is start or restart -if ( $command eq 'status' ) { +if ($command eq 'status') { my $status = runCommand('zmdc.pl check'); print(STDOUT $status."\n"); -} elsif ( $command eq 'logrot' ) { +} elsif ($command eq 'logrot') { runCommand('zmdc.pl logrot'); } @@ -314,42 +303,31 @@ exit($retval); # PP - Make sure isActive is on and only one sub isActiveSanityCheck { - Info('Sanity checking States table...'); $dbh = zmDbConnect() if ! $dbh; # PP - First, make sure default exists and there is only one - my $sql = 'SELECT `Name` FROM `States` WHERE `Name`=?'; - my $sth = $dbh->prepare_cached($sql) - or Fatal("Can't prepare '$sql': ".$dbh->errstr()); - my $res = $sth->execute('default') - or Fatal("Can't execute: ".$sth->errstr()); - - if ( $sth->rows != 1 ) { + my @states = ZoneMinder::State->find(Name=>'default', order=>'Id ASC'); # PP - no row, or too many rows. Either case is an error - Info('Fixing States table - either no default state or duplicate default states'); - if ( $sth->rows ) { - $dbh->do('DELETE FROM `States` WHERE `Name`=\'default\'') or Fatal("Can't execute: ".$dbh->errstr()); - } - $dbh->do('INSERT INTO `States` (`Name`,`Definition`,`IsActive`) VALUES (\'default\',\'\',\'1\');') - or Fatal("Can't execute: ".$dbh->errstr()); + + my $default_state; + while (@states > 1) { + my $state = shift @states; + $state->delete(); + } + if (!@states) { + $default_state = new ZoneMinder::State(); + $default_state->save({Name=>'default', Definition=>'', IsActive=>1}); + } else { + $default_state = shift @states; } - $sth->finish(); -# PP - Now make sure no two states have IsActive=1 - $sql = 'SELECT `Name` FROM `States` WHERE `IsActive`=1'; - $sth = $dbh->prepare_cached($sql) - or Fatal("Can't prepare '$sql': ".$dbh->errstr()); - $res = $sth->execute() - or Fatal("Can't execute: ".$sth->errstr()); - - if ( $sth->rows != 1 ) { + @states = ZoneMinder::State->find(IsActive=>1); + if (@states != 1) { Info('Fixing States table so only one run state is active'); resetStates(); - $dbh->do('UPDATE `States` SET `IsActive`=1 WHERE `Name`=\'default\'') - or Fatal("Can't execute: ".$dbh->errstr()); + $default_state->save({IsActive=>1}); } - $sth->finish(); } # end sub isActiveSanityCheck # PP - zeroes out isActive for all states diff --git a/scripts/zmtelemetry.pl.in b/scripts/zmtelemetry.pl.in index c164df7e4..120c4b944 100644 --- a/scripts/zmtelemetry.pl.in +++ b/scripts/zmtelemetry.pl.in @@ -263,7 +263,7 @@ sub countQuery { sub getMonitorRef { my $dbh = shift; - my $sql = 'SELECT `Id`,`Name`,`Type`,`Function`,`Width`,`Height`,`Colours`,`MaxFPS`,`AlarmMaxFPS`, + my $sql = 'SELECT `Id`,`Name`,`Type`,`Capturing`,`Analysing`,`Recording`,`Width`,`Height`,`Colours`,`MaxFPS`,`AlarmMaxFPS`, (SELECT Name FROM Manufacturers WHERE Manufacturers.Id = ManufacturerId), (SELECT Name FROM Models WHERE Models.Id = ModelId) FROM `Monitors`'; diff --git a/scripts/zmtrigger.pl.in b/scripts/zmtrigger.pl.in index 94f59e001..cc9152fb2 100644 --- a/scripts/zmtrigger.pl.in +++ b/scripts/zmtrigger.pl.in @@ -302,9 +302,9 @@ while (!$zm_terminate) { } elsif (@needsReload) { foreach my $monitor (@needsReload) { $monitor = $monitors{$monitor->Id()} = ZoneMinder::Monitor->find_one(Id=>$monitor->Id()); - if ( $$monitor{Function} eq 'None' ) { + if ($$monitor{Capturing} eq 'None') { delete $monitors{$monitor->Id()}; - } elsif ( $Config{ZM_SERVER_ID} and ($$monitor{ServerId} != $Config{ZM_SERVER_ID})) { + } elsif ($Config{ZM_SERVER_ID} and ($$monitor{ServerId} != $Config{ZM_SERVER_ID})) { delete $monitors{$monitor->Id()}; } else { if ($monitor->connect()) { @@ -312,7 +312,7 @@ while (!$zm_terminate) { $monitor->{LastEvent} = zmGetLastEvent($monitor); } } - } + } # end foreach @needsREload @needsReload = (); } @@ -326,11 +326,10 @@ sub loadMonitors { $monitor_reload_time = time(); %monitors = (); - foreach my $monitor ( ZoneMinder::Monitor->find( - Function=>['Modect','Mocord','Nodect','Record'], + 'Capturing !=' => 'None', ($Config{ZM_SERVER_ID} ? (ServerId=>$Config{ZM_SERVER_ID}) : ()), - )) { + )) { if ($monitor->connect()) { # This will re-init shared memory $monitor->{LastState} = zmGetMonitorState($monitor); $monitor->{LastEvent} = zmGetLastEvent($monitor); diff --git a/scripts/zmwatch.pl.in b/scripts/zmwatch.pl.in index 1c4adfd0b..a6cbb6f8c 100644 --- a/scripts/zmwatch.pl.in +++ b/scripts/zmwatch.pl.in @@ -90,7 +90,7 @@ while (!$zm_terminate) { } foreach my $monitor (ZoneMinder::Monitor->find($Config{ZM_SERVER_ID} ? (ServerId=>$Config{ZM_SERVER_ID}) : ())) { - next if $monitor->{Function} eq 'None'; + next if $monitor->{Capturing} eq 'None' ; next if $monitor->{Type} eq 'WebSite'; next if $monitor->{Capturing} eq 'Ondemand'; my $now = time(); @@ -128,8 +128,8 @@ while (!$zm_terminate) { &&($monitor->{MaxFPS}>0) &&($monitor->{MaxFPS}<1) ) ? (3/$monitor->{MaxFPS}) - : $Config{ZM_WATCH_MAX_DELAY} - ; + : $Config{ZM_WATCH_MAX_DELAY}; + my $image_delay = $now - $capture_time; Debug("Monitor $monitor->{Id} last captured $image_delay seconds ago, max is $max_image_delay"); if ($image_delay > $max_image_delay) { @@ -140,7 +140,7 @@ while (!$zm_terminate) { next; } - if ($monitor->{Function} ne 'Monitor') { + if ($monitor->{Analysing} ne 'None') { # Now check analysis thread # Check we have got an image recently my $image_time = zmGetLastReadTime($monitor); @@ -168,9 +168,7 @@ while (!$zm_terminate) { next; } } - } # end if check analysis daemon - } # end foreach monitor sleep($Config{ZM_WATCH_CHECK_INTERVAL}); diff --git a/scripts/zmx10.pl.in b/scripts/zmx10.pl.in index de1f74929..bad8e3656 100644 --- a/scripts/zmx10.pl.in +++ b/scripts/zmx10.pl.in @@ -416,8 +416,7 @@ sub loadTasks { 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 + WHERE M.Capturing != \'None\' AND find_IN_set(\'X10\', M.Triggers)'; my $sth = $dbh->prepare_cached( $sql ) or Fatal("Can't prepare '$sql': ".$dbh->errstr());