ZM Perl Interface Issue

Forum for questions and support relating to the 1.28.x releases only.
User avatar
knight-of-ni
Posts: 2219
Joined: Thu Oct 18, 2007 1:55 pm
Location: Shiloh, IL

Re: ZM Perl Interface Issue

Post by knight-of-ni » Thu Feb 04, 2016 3:30 pm

You probably meant zmMemInvalidate
Visit my blog for ZoneMinder related projects using the Raspberry Pi, Orange Pi, Odroid, and the ESP8266
All of these can be found at https://zoneminder.blogspot.com/

User avatar
asker
Posts: 1049
Joined: Sun Mar 01, 2015 12:12 pm

Re: ZM Perl Interface Issue

Post by asker » Thu Feb 04, 2016 4:16 pm

I did a bit of experimentation (and took a hint from zmwatch.pl)
a) You detect your handle is invalid when zmMemRead fails (tip of the hat to zmwatch)
b) if above fails, you invalidate your current handle and do zmMemVerify. On looking at the code for zmMemRead, it already calls zmMemVerify, so I guess that part is redundant

I've tested this only slightly - but works to re-attach if you start/stop ZM as a whole, or kill and re-start a single zmc.

Code: Select all

#!/usr/bin/perl
use ZoneMinder;
use DBI;

my @monitors = ();
my $dbh = zmDbConnect();

loadMonitors();

my $iter=1;

for (;;)
{
        foreach $mon (@monitors)
        {
                
                my $mr = zmMemRead($mon, "shared_data:valid");
                print ("Iteration:$iter Checking Monitor ".$mon->{Id}." MemReadResult:$mr Name:".$mon->{Name}." MMap address:".$mon->{MMapAddr}."\n");
                if ($mr!="1")
                {
                        zmMemInvalidate($mon);
                        my $mv =zmMemVerify($mon);
                        print ("Reloading memory for ".$mon->{Id}.", status of verify is:$mv\n");
                }
        }
        print ("==================================\n"); 
        sleep(1);
        $iter++;
}

sub loadMonitors()
{
        @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() )
        {
                push @monitors, $monitor;
        }
}
--
My collection of ZoneMinder learnings:
https://wiki.zoneminder.com/Various_ZM_thoughts

User avatar
knight-of-ni
Posts: 2219
Joined: Thu Oct 18, 2007 1:55 pm
Location: Shiloh, IL

Re: ZM Perl Interface Issue

Post by knight-of-ni » Thu Feb 04, 2016 4:30 pm

Very nice. We can probably incorporate that into zmtrigger, since it is suspected to have the same issue as the op's script.
Probably replace this block of code:
https://github.com/ZoneMinder/ZoneMinde ... pl.in#L414

If this works as intended, then there would be no need to edit zmdc.pl or functions.php at all, right?
You could configure the third party script to start via init/systemd and it would just work all the time. Updating the version of zoneminder would not overwrite changes in this case.
Visit my blog for ZoneMinder related projects using the Raspberry Pi, Orange Pi, Odroid, and the ESP8266
All of these can be found at https://zoneminder.blogspot.com/

User avatar
asker
Posts: 1049
Joined: Sun Mar 01, 2015 12:12 pm

Re: ZM Perl Interface Issue

Post by asker » Thu Feb 04, 2016 5:16 pm

Right, I should plough this into zmeventserver as soon as I get time to test it more. As it stands today, zmeventserver also likely misses events between the reload_monitor interval if a zmc crashes in between (but not if zm restarts thanks to zmdc).

With respect to not changing zmdc.pl, I guess that is correct - since systemd allows us to restart services if it goes down and also allows the process to wait for zm service to start first (just in case there is a dependency)

Edited: Added note:
The line numbers you refer to would still be needed - it wouldn't replace those lines, as they take care of loading new monitor definitions (deletions/additions)
--
My collection of ZoneMinder learnings:
https://wiki.zoneminder.com/Various_ZM_thoughts

waynieack
Posts: 6
Joined: Thu May 24, 2012 11:24 pm

Re: ZM Perl Interface Issue

Post by waynieack » Sat Feb 06, 2016 4:34 am

Yes! This is great! I just got a few free mins and put that code in my script and it works perfectly so far. I am able to restart zoneminder and the script recovers without having to restart it. So all I need now is to just have monit monitor the script as I normally do and I don't have to modify the ZM code! I'm going to let it run for a while logging to make sure nothing strange happens, but it looks really good so far.

This was the last piece to the puzzle for this project for me! Thanks everyone for your help!

Not sure if any of you guys use Hikvision cameras, but they have pretty good motion features and its a huge resource saver to offload to the cameras. I like this camera so much I'm going to replace all my crap Foscam camera with them.

Also if any one has any pointers on my code feel free to comment. This was my first threaded script and I'm clearly not a developer, I just do this in my spare time for fun.

-Wayne

User avatar
asker
Posts: 1049
Joined: Sun Mar 01, 2015 12:12 pm

Re: ZM Perl Interface Issue

Post by asker » Sat Feb 06, 2016 12:45 pm

I'm glad it worked for you, but I don't see the changes in your code at https://github.com/waynieack/HikvisionZ ... nstream.pl --> have you uploaded it? Specifically, my theory (based on limited testing is)

1. if zmMemRead for mon $x fails for shared_data:valid, you need to invalidate that handle by calling zmMemInvalidate($x)
2. When zmc for that monitor restarts, zmMemRead of step 1 will eventually work after the memory is reestablished (zmMemRead calls zmMemVerify so you don't need to explicitly call)

The important points: a) Check with zmMemRead on shared_data:valid b) Very important to Invalidate otherwise your error will never recover

Is this what you have done?
--
My collection of ZoneMinder learnings:
https://wiki.zoneminder.com/Various_ZM_thoughts

waynieack
Posts: 6
Joined: Thu May 24, 2012 11:24 pm

Re: ZM Perl Interface Issue

Post by waynieack » Mon Feb 08, 2016 4:14 pm

I made a sub to check the memory and I added a loop to keep checking it until its valid in case ZM was stopped for an extended amount of time. With my script I am seeing some strange behaviors when I stop ZM, trigger a motion event (the validatemem sub loops until ZM starts again), then start ZM again. I may just set a flag when zmMemVerify fails after zmMemInvalidate and skip activating/disactivating the alarm until the memory is valid again instead of looping in the validatemem sub, that should keep everything in order.

I run the validatemem sub at line 241 in the disablezmalarm sub and line 149 in the activatezmalarm sub.

Code: Select all

sub validatemem {
   my $ip = $_[0];
   my $mr = zmMemRead($monitors->{$ip}->{'HASH'}, "shared_data:valid");
   print ("Checking Monitor ".$monitors->{$ip}->{'HASH'}->{Id}." MemReadResult:$mr Name:".$monitors->{$ip}->{'HASH'}->{Name}." MMap address:".$monitors->{$ip}->{'HASH'}->{MMapAddr}."\n");
         while ($mr!="1") {
                 zmMemInvalidate($monitors->{$ip}->{'HASH'});
                 my $mv =zmMemVerify($monitors->{$ip}->{'HASH'});
                if (!defined($mv)) {
                    print ("Cant verify memory for ".$monitors->{$ip}->{'HASH'}->{Id}.", zoneminder may be stopped\n");
                    $mr = 0; sleep 3;
                } else {
                    print ("Reloading memory for ".$monitors->{$ip}->{'HASH'}->{Id}.", status of verify is:$mv\n");
                    $mr = zmMemRead($monitors->{$ip}->{'HASH'}, "shared_data:valid");
                }
         }
}

Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests