Script To Change State of Zones

If you've made a patch to quick fix a bug or to add a new feature not yet in the main tree then post it here so others can try it out.
Post Reply
lselinger
Posts: 35
Joined: Fri Oct 25, 2013 9:57 pm

Script To Change State of Zones

Post by lselinger »

I created a pretty simple script to dump zone names and allow me to cron changing zones to/from Active and Inactive. I ran into a situation where some seasonal lighting was making my zm go nuts and it really only crossed paths on a couple of zones. For now I've created a relatively simple script that I run from cron:

Code: Select all

#!/usr/bin/perl
#
# Script to change zone states to and from active/inactive. This script 
# could be added to cron to allow timed zone changes as oposed to changing
# run times for entire monitors.
# Author: Lonny Selinger Tue Nov 28 12:30:54 CST 2017
#                 lonny<dot>selinger<at>gmail<dot>com 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

use strict;
use warnings;
 
use DBI;
use Getopt::Long;


# The assumption is that zm is the standard DB name and that is hasn't
# been changed. If it has, change to your DB name in the following line

my $dsn = "DBI:mysql:zm";

# Set your own user name and password to your DB. 
# Also keep this in a locked down place wih limited access and chmod 700
# I was going to have user/pass as options however I think it's safer to hide
# the script rather than providing plain text passwords in a crontab.

my $username = 'CHANGEME;
my $password = 'CHANGEME';
my $type = undef; 


GetOptions ("report|r"  => \my $report,
                        "help|h"        => \my $help,
                        "state|s=s"     => \my $state,
                        "zone|z=s"      => \my $zone
);

# Busy logic the forward to subs. This certainly isn't lean ;-)

if ($help) { help(); }
if ($report) { report(); }
if (!$zone || !$state) { help(); } 

if ($state eq 'inactive' or $state eq 'active') {

        if ($state eq 'inactive') {
            $type = 'Inactive';
        } else {
            if ($state eq 'active') {
                $type = 'Active';
            }
        }
        my $dbh  = DBI->connect($dsn,$username,$password);
        print "Changing $zone to $state\n";

        my $sth = $dbh->prepare("UPDATE Zones SET Type='$type' WHERE Name='$zone'");
        $sth->execute();
        exit(0);
} else {
        help();
        exit(0);
}

# Basic dump/report section. I do no validation currently on Zone names
# in the main section that alters the DB. IOW you can misspell or supply
# Zone names that do not exist and I do not verify they are valid.
# I decided to throw in a quick dump of the Zone Name, ID, and Monitor ID
# to help whoever uses this to select the zone they want to alter.

sub report {
my $dbh  = DBI->connect($dsn,$username,$password);
my $sth = $dbh->prepare("SELECT Name,Id,MonitorId from Zones");
$sth->execute();
$sth->dump_results();
$sth->finish();
exit(0);
}

# Help section

sub help {
        print "\nUsage: $0 [--report/-r] [--help/-h] --state/-s --zone/-z\n\n";
        print "\tAt a minimum you'll need to specify a zone and the state\n"; 
        print "\tyou want it in\n\n";
        print "\t -z    Zone you would like to change the state of\n";
        print "\t -s    State you would like it in (active/inactive)\n";
        print "\t -r    Provide a simple dump of Zone names, Zone ID,\n";
        print "\t       and Monitor Id# to help identify the zone you want to affect.\n";
        print "\t -h    for this menu\n\n"; 
        exit(0);
} #EOF
Here's a couple of simple lines calling the script:

Code: Select all

59 17 * * * /usr/local/src/test/zone_ctrl.pl -z Driveway -s inactive 2>&1
01 21 * * * /usr/local/src/test/zone_ctrl.pl -z Driveway -s active 2>&1
59 17 * * * /usr/local/src/test/zone_ctrl.pl -z Yard -s inactive 2>&1
01 21 * * * /usr/local/src/test/zone_ctrl.pl -z Yard -s active 2>&1
Hadn't seen much around this in terms of anyone else creating a function specifically to toggle zone states ... for the same reason I'm assuming there wasn't much of a need for others either :P either way ...
alabamatoy
Posts: 349
Joined: Sun Jun 05, 2016 2:53 pm

Re: Script To Change State of Zones

Post by alabamatoy »

Thanks for posting this. I think this will be perfect to integrate with home automation (Openhab, or similar), so that a minute or so before turning on lights in a particular area I can turn off motion detection in that same ZM monitor, then turn it back on again shortly afterwards. This will avoid pointless non-alarms for lights turning on and off.
sagitt
Posts: 39
Joined: Mon Apr 30, 2012 1:13 pm

Re: Script To Change State of Zones

Post by sagitt »

hi, is possible do something like this for change the monitor status?

like to none, to modect, to nodect?
alabamatoy
Posts: 349
Joined: Sun Jun 05, 2016 2:53 pm

Re: Script To Change State of Zones

Post by alabamatoy »

sagitt wrote: Sun Jan 28, 2018 10:27 pm hi, is possible do something like this for change the monitor status?

like to none, to modect, to nodect?
See viewtopic.php?f=37&t=26903#p104101 the API can do this, and its a simple one liner in bash script using curl.
sagitt
Posts: 39
Joined: Mon Apr 30, 2012 1:13 pm

Re: Script To Change State of Zones

Post by sagitt »

Thanks!
I done this:

Code: Select all

#!/bin/sh
username="USER"
password="PASSWORD"
host="http://localhost:PORT/zm"
file="/etc/zm/cookie.txt"

case "$1" in
	'statusid')
		if [ -e $file ]; then
  			echo "WARNING: Cookie file: $file already exist... Using it!"
		else
   			echo "WARNING: Cookie file: $file does not exist... Creating it!"
			curl -d "username=$username&password=$password&action=login&view=console" -c $file $host/index.php
			sleep 1
			chmod 600 $file
			echo Cookie file: $file created.
		fi
		curl -b $file -XPOST $host/api/monitors/$2.json -d "Monitor[Function]=$3&Monitor[Enabled]=$4"
		echo Changed ID $2 ZoneMinder monitor status to $3 now.

	;;
	'makecookie')
		if [ -e $file ]; then
  			echo "WARNING: Cookie file: $file already exist... Overwriting it!"
		else
   			echo "WARNING: Cookie file: $file does not exist... Creating it!"
		fi
		curl -d "username=$username&password=$password&action=login&view=console" -c $file $host/index.php
		sleep 1
		chmod 600 $file
		echo Cookie file: $file created.
	;;
	'deletecookie')
		if [ -e $file ]; then
  			echo "WARNING: Cookie file: $file exist... Deleting it!"
			rm $file
			echo Cookie file: $file deleted.
		else
   			echo "WARNING: Cookie file: $file does not exist... Can't delete it!"
		fi
	;;
	'info')
		echo "Use statusid <ID> <None|Monitor|Modect|Record|Mocord|Nodect> <0|1> parameters to change monitor status or makecookie\deletecookie to manage cookie file manually"
	;;
	*)
		echo "Usage: $0 {statusid|makecookie|deletecookie|info}"
		exit 1
	;;
esac

exit 0
jamesmcbride
Posts: 5
Joined: Sun Feb 18, 2018 12:07 am

Re: Script To Change State of Zones

Post by jamesmcbride »

This script is brilliant! I've got it tied in to openhab to turn off certain zones when it gets dark and back on again when it is light.

Turning the zone on seems to work fine, but for some reason when the zone gets turned off, even though it shows as inactive in zoneminder, it seems to still be active.

If I use the zoneminder interface to go into zones set it to active again, then inactive, it works fine.

I should note that zoneminder and openhab are running on separate servers, so the script is running on my openhab server, with relevant mysql permissions to the zoneminder db.

Any thoughts would be great!
jamesmcbride
Posts: 5
Joined: Sun Feb 18, 2018 12:07 am

Re: Script To Change State of Zones

Post by jamesmcbride »

it looks like I might not be completely correct above - it just seems hit and miss as to whether it actually takes notice of the active / inactive setting. Strange
jamesmcbride
Posts: 5
Joined: Sun Feb 18, 2018 12:07 am

Re: Script To Change State of Zones

Post by jamesmcbride »

Ok, I think I've figured this out from some tracing.

It looks like when I update to inactive through the web interface, it also sets min/max alarmed pixels to 0 it runs:
<code>
UPDATE Zones SET Type = 'Inactive', MinAlarmPixels = '0', MaxAlarmPixels = '0' WHERE MonitorId='5' AND Id='17'
</code>
jamesmcbride
Posts: 5
Joined: Sun Feb 18, 2018 12:07 am

Re: Script To Change State of Zones

Post by jamesmcbride »

I think I've figured this out completely now, incase anyone else runs in the same problems.

It looks like the original script above will set the zone active / inactive, but doesn't seem to actually apply the change.

Looking in /usr/share/zoneminder/www/includes/actions.php, the function that updates the zone's, runs the SQL in the script above, but also calls "zmaControl( $mid, "restart" );" I believe this restarts the zoneminder analysis daemon.

You could do this by calling this directly, like this: zmdc.pl stop zma -m 5

But in my case, I'm running my home automation system (openhab) on a separate box, so would mean calling it over ssh, which all starts to get a bit complicated. So I started to look to see if there was an easier way of doing this - ideally by just calling the function in actions.php directly.

After doing some packet captures on the form data sent back from the "Zones" page, I think I have a working way of doing this:

Code: Select all

curl  -s http://192.168.180.11/zm/index.php -d "action=zone&mid=5&zid=17&newZone[Type]=Active"
curl  -s http://192.168.180.11/zm/index.php -d "action=zone&mid=5&zid=17&newZone[Type]=Inactive"
If you are using authentication, I think you might need to use a cookie file as well to stay authenticated - I run zoneminder behind a reverse proxy, so deal with authentication on there.

Translating this to openhab, I've not figured out how to get this to work with the http binding yet - I don't think it likes the [] in the post data. But I've managed to get it to work with a rule, which will do for now:

Code: Select all

rule DriveEntranceMotionActive
when Item DriveEntranceMotionActive changed 
then
	if(DriveEntranceMotionActive.state == ON )
		{
		sendHttpPostRequest("http://192.168.180.11/zm/index.php", "application/x-www-form-urlencoded", "action=zone&mid=5&zid=17&newZone[Type]=Active")
		}
	if(DriveEntranceMotionActive.state == OFF )
		{
		sendHttpPostRequest("http://192.168.180.11/zm/index.php", "application/x-www-form-urlencoded", "action=zone&mid=5&zid=17&newZone[Type]=Inactive")
		}
end
Post Reply