2002-12-05 19:32:40 +08:00
|
|
|
#!/usr/bin/perl -wT
|
2002-12-10 21:17:16 +08:00
|
|
|
#
|
|
|
|
# ==========================================================================
|
|
|
|
#
|
|
|
|
# Zone Minder X10 Control Script, $Date$, $Revision$
|
2003-01-12 02:22:27 +08:00
|
|
|
# Copyright (C) 2003 Philip Coombes
|
2002-12-10 21:17:16 +08:00
|
|
|
#
|
|
|
|
# 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 2
|
|
|
|
# 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, write to the Free Software
|
|
|
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
#
|
2002-12-05 19:32:40 +08:00
|
|
|
# ==========================================================================
|
|
|
|
#
|
|
|
|
# This script controls the monitoring of the X10 interface and the consequent
|
|
|
|
# management of the ZM daemons based on the receipt of X10 signals.
|
|
|
|
#
|
|
|
|
|
2002-12-10 21:17:16 +08:00
|
|
|
# ==========================================================================
|
|
|
|
#
|
|
|
|
# These are the elements you need to edit to suit your installation
|
|
|
|
#
|
|
|
|
# ==========================================================================
|
2002-12-10 21:33:18 +08:00
|
|
|
|
2003-01-11 08:15:29 +08:00
|
|
|
use constant ZM_DB_SERVER => "<from zmconfig>";
|
|
|
|
use constant ZM_DB_NAME => "<from zmconfig>";
|
|
|
|
use constant ZM_DB_USERA => "<from zmconfig>";
|
|
|
|
use constant ZM_DB_PASSA => "<from zmconfig>";
|
|
|
|
use constant ZM_DIR_EVENTS => "<from zmconfig>";
|
|
|
|
use constant ZM_PATH_LOGS => "<from zmconfig>";
|
|
|
|
use constant ZM_X10_DB_RELOAD_INTERVAL => 60;
|
|
|
|
use constant ZM_X10_DEVICE => '/dev/ttyS1';
|
|
|
|
use constant ZM_X10_HOUSE_CODE => 'K';
|
|
|
|
use constant ZM_SHM_KEY => 0x7a6d2000;
|
|
|
|
|
2002-12-05 19:32:40 +08:00
|
|
|
use constant X10_SOCK_FILE => '/tmp/zmx10.sock';
|
2003-01-11 08:15:29 +08:00
|
|
|
use constant X10_LOG_FILE => ZM_PATH_LOGS.'/zmx10.log';
|
2002-12-15 22:09:53 +08:00
|
|
|
use constant COMMAND_PATH => '@prefix@/bin/';
|
2003-01-07 20:26:34 +08:00
|
|
|
use constant VERBOSE => 0; # Whether to output more verbose debug
|
2002-12-05 19:32:40 +08:00
|
|
|
|
|
|
|
# ==========================================================================
|
|
|
|
#
|
|
|
|
# Don't change anything below here
|
|
|
|
#
|
|
|
|
# ==========================================================================
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use POSIX;
|
|
|
|
use Socket;
|
|
|
|
use Getopt::Long;
|
|
|
|
use Data::Dumper;
|
|
|
|
|
|
|
|
$| = 1;
|
|
|
|
|
2003-01-07 19:32:37 +08:00
|
|
|
$ENV{PATH} = '/bin:/usr/bin';
|
|
|
|
$ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL};
|
|
|
|
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
|
|
|
|
|
2002-12-05 19:32:40 +08:00
|
|
|
sub Usage
|
|
|
|
{
|
|
|
|
print( "
|
|
|
|
Usage: zmx10.pl -c <command>,--command=<command> [-u <unit code>,--unit-code=<unit code>]
|
|
|
|
Parameters are :-
|
2002-12-24 19:53:41 +08:00
|
|
|
-c <command>, --command=<command> - Command to issue, one of 'on','off','dim','bright','status','shutdown'
|
|
|
|
-u <unit code>, --unit-code=<unit code> - Unit code to act on required for all commands except 'status' (optional) and 'shutdown'
|
2002-12-05 19:32:40 +08:00
|
|
|
");
|
|
|
|
exit( -1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
my $command;
|
|
|
|
my $unit_code;
|
|
|
|
|
|
|
|
if ( !GetOptions( 'command=s'=>\$command, 'unit-code=i'=>\$unit_code ) )
|
|
|
|
{
|
|
|
|
Usage();
|
|
|
|
}
|
|
|
|
|
|
|
|
die( "No command given" ) unless( $command );
|
2002-12-15 22:09:53 +08:00
|
|
|
die( "No unit code given" ) unless( $unit_code || ($command =~ /(?:start|status|shutdown)/) );
|
|
|
|
|
|
|
|
if ( $command eq "start" )
|
|
|
|
{
|
|
|
|
X10Server::runServer();
|
|
|
|
exit();
|
|
|
|
}
|
2002-12-05 19:32:40 +08:00
|
|
|
|
|
|
|
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or die( "Can't open socket: $!" );
|
|
|
|
|
|
|
|
my $saddr = sockaddr_un( X10_SOCK_FILE );
|
|
|
|
|
|
|
|
if ( !connect( CLIENT, $saddr ) )
|
|
|
|
{
|
|
|
|
# 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 );
|
|
|
|
socket( CLIENT, PF_UNIX, SOCK_STREAM, 0 ) or die( "Can't open socket: $!" );
|
|
|
|
connect( CLIENT, $saddr ) or die( "Can't connect: $!" );
|
|
|
|
}
|
|
|
|
elsif ( defined($cpid) )
|
|
|
|
{
|
|
|
|
setpgrp();
|
|
|
|
|
2002-12-15 22:09:53 +08:00
|
|
|
X10Server::runServer();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
die( "Can't fork: $!" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# The server is there, connect to it
|
|
|
|
#print( "Writing commands\n" );
|
|
|
|
CLIENT->autoflush();
|
|
|
|
my $message = "$command";
|
|
|
|
$message .= ";$unit_code" if ( $unit_code );
|
|
|
|
print( CLIENT $message );
|
|
|
|
shutdown( CLIENT, 1 );
|
|
|
|
while ( my $line = <CLIENT> )
|
|
|
|
{
|
|
|
|
chomp( $line );
|
|
|
|
print( "$line\n" );
|
|
|
|
}
|
|
|
|
close( CLIENT );
|
|
|
|
#print( "Finished writing, bye\n" );
|
|
|
|
exit;
|
|
|
|
|
|
|
|
#
|
|
|
|
# ==========================================================================
|
|
|
|
#
|
|
|
|
# This is the X10 Server package
|
|
|
|
#
|
|
|
|
# ==========================================================================
|
|
|
|
#
|
|
|
|
package X10Server;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use POSIX;
|
|
|
|
use DBI;
|
|
|
|
use Socket;
|
|
|
|
use X10::ActiveHome;
|
2002-12-05 19:32:40 +08:00
|
|
|
|
2002-12-15 22:09:53 +08:00
|
|
|
our $dbh;
|
|
|
|
our $x10;
|
2002-12-05 19:32:40 +08:00
|
|
|
|
2002-12-24 19:53:41 +08:00
|
|
|
our %monitor_hash;
|
2002-12-15 22:09:53 +08:00
|
|
|
our %device_hash;
|
|
|
|
our %pending_tasks;
|
2002-12-05 19:32:40 +08:00
|
|
|
|
2002-12-15 22:09:53 +08:00
|
|
|
sub runServer
|
|
|
|
{
|
|
|
|
open( LOG, '>>'.main::X10_LOG_FILE ) or die( "Can't open log file: $!" );
|
|
|
|
select( LOG );
|
|
|
|
$| = 1;
|
|
|
|
print( LOG "X10 server starting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
|
2002-12-14 07:23:40 +08:00
|
|
|
|
2002-12-15 22:09:53 +08:00
|
|
|
socket( SERVER, PF_UNIX, SOCK_STREAM, 0 ) or die( "Can't open socket: $!" );
|
|
|
|
unlink( main::X10_SOCK_FILE );
|
|
|
|
my $saddr = sockaddr_un( main::X10_SOCK_FILE );
|
|
|
|
bind( SERVER, $saddr ) or die( "Can't bind: $!" );
|
|
|
|
listen( SERVER, SOMAXCONN ) or die( "Can't listen: $!" );
|
2002-12-14 07:23:40 +08:00
|
|
|
|
2003-01-11 17:08:57 +08:00
|
|
|
$dbh = DBI->connect( "DBI:mysql:database=".main::ZM_DB_NAME.";host=".main::ZM_DB_SERVER, main::ZM_DB_USERA, main::ZM_DB_PASSA );
|
2002-12-14 07:23:40 +08:00
|
|
|
|
2003-01-11 08:15:29 +08:00
|
|
|
$x10 = new X10::ActiveHome( port=>main::ZM_X10_DEVICE, house_code=>main::ZM_X10_HOUSE_CODE, debug=>1 );
|
2002-12-14 07:23:40 +08:00
|
|
|
|
2002-12-15 22:09:53 +08:00
|
|
|
loadTasks();
|
2002-12-14 07:23:40 +08:00
|
|
|
|
2002-12-15 22:09:53 +08:00
|
|
|
$x10->register_listener( \&x10listen );
|
2002-12-14 07:23:40 +08:00
|
|
|
|
2002-12-15 22:09:53 +08:00
|
|
|
my $rin = '';
|
|
|
|
vec( $rin, fileno(SERVER),1) = 1;
|
|
|
|
vec( $rin, $x10->select_fds(),1) = 1;
|
2002-12-24 19:53:41 +08:00
|
|
|
my $timeout = 0.2;
|
2002-12-15 22:09:53 +08:00
|
|
|
#print( "F:".fileno(SERVER)."\n" );
|
2002-12-24 19:53:41 +08:00
|
|
|
my $reload = undef;
|
2003-01-02 20:55:09 +08:00
|
|
|
my $reload_count = 0;
|
2003-01-11 08:15:29 +08:00
|
|
|
my $reload_limit = main::ZM_X10_DB_RELOAD_INTERVAL/$timeout;
|
2002-12-15 22:09:53 +08:00
|
|
|
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) )
|
2002-12-14 07:23:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
my $paddr = accept( CLIENT, SERVER );
|
|
|
|
my $message = <CLIENT>;
|
2002-12-14 07:23:40 +08:00
|
|
|
|
2002-12-15 22:09:53 +08:00
|
|
|
my ( $command, $unit_code ) = split( ';', $message );
|
|
|
|
|
|
|
|
my $device;
|
|
|
|
if ( defined($unit_code) )
|
2002-12-14 07:23:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
if ( $unit_code < 1 || $unit_code > 16 )
|
2002-12-14 07:23:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
dprint( "Error, invalid unit code '$unit_code'\n" );
|
|
|
|
next;
|
2002-12-14 07:23:40 +08:00
|
|
|
}
|
2002-12-15 22:09:53 +08:00
|
|
|
|
|
|
|
$device = $device_hash{$unit_code};
|
|
|
|
if ( !$device )
|
2002-12-14 07:23:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
$device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), status=>'unknown' };
|
2002-12-14 07:23:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-15 22:09:53 +08:00
|
|
|
my $result;
|
|
|
|
if ( $command eq 'on' )
|
|
|
|
{
|
|
|
|
$result = $device->{appliance}->on();
|
|
|
|
}
|
|
|
|
elsif ( $command eq 'off' )
|
2002-12-14 07:23:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
$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( $unit_code." ".$device->{status}."\n" );
|
|
|
|
}
|
|
|
|
else
|
2002-12-14 07:23:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
foreach my $unit_code ( sort( keys(%device_hash) ) )
|
|
|
|
{
|
|
|
|
my $device = $device_hash{$unit_code};
|
|
|
|
dprint( $unit_code." ".$device->{status}."\n" );
|
|
|
|
}
|
2002-12-14 07:23:40 +08:00
|
|
|
}
|
|
|
|
}
|
2002-12-15 22:09:53 +08:00
|
|
|
elsif ( $command eq 'shutdown' )
|
2002-12-14 07:23:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
last;
|
2002-12-14 07:23:40 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
dprint( "Error, invalid command '$command'\n" );
|
2002-12-14 07:23:40 +08:00
|
|
|
}
|
2002-12-15 22:09:53 +08:00
|
|
|
if ( defined($result) )
|
2002-12-14 07:23:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
if ( 1 || $result )
|
2002-12-14 07:23:40 +08:00
|
|
|
{
|
2003-01-02 20:24:00 +08:00
|
|
|
$device->{status} = uc($command);
|
2002-12-15 22:09:53 +08:00
|
|
|
dprint( $device->{appliance}->address()." $command, ok\n" );
|
2003-01-03 03:28:30 +08:00
|
|
|
#x10listen( new X10::Event( sprintf("%s %s", $device->{appliance}->address, uc($command) ) ) );
|
2002-12-14 07:23:40 +08:00
|
|
|
}
|
2002-12-15 22:09:53 +08:00
|
|
|
else
|
2002-12-14 07:23:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
dprint( $device->{appliance}->address()." $command, failed\n" );
|
2002-12-14 07:23:40 +08:00
|
|
|
}
|
|
|
|
}
|
2002-12-15 22:09:53 +08:00
|
|
|
close( CLIENT );
|
|
|
|
}
|
|
|
|
elsif ( vec( $rout, $x10->select_fds(),1) )
|
|
|
|
{
|
|
|
|
$x10->handle_input();
|
2002-12-14 07:23:40 +08:00
|
|
|
}
|
2002-12-15 22:09:53 +08:00
|
|
|
else
|
2002-12-14 07:23:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
die( "Bogus descriptor" );
|
2002-12-14 07:23:40 +08:00
|
|
|
}
|
|
|
|
}
|
2002-12-15 22:09:53 +08:00
|
|
|
elsif ( $nfound < 0 )
|
|
|
|
{
|
|
|
|
die( "Can't select: $!" );
|
|
|
|
}
|
|
|
|
else
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
#print( "Select timed out\n" );
|
2002-12-24 19:53:41 +08:00
|
|
|
# Check for state changes
|
|
|
|
foreach my $monitor_id ( sort(keys(%monitor_hash) ) )
|
|
|
|
{
|
|
|
|
my $monitor = $monitor_hash{$monitor_id};
|
|
|
|
my $state;
|
|
|
|
if ( !shmread( $monitor->{ShmId}, $state, 0, 4 ) )
|
|
|
|
{
|
|
|
|
print( "Can't read from shared memory: $!\n" );
|
|
|
|
$reload = !undef;
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
$state = unpack( "l", $state );
|
|
|
|
if ( defined( $monitor->{LastState} ) )
|
|
|
|
{
|
|
|
|
my $task_list;
|
|
|
|
if ( $state == 1 && $monitor->{LastState} == 0 ) # Gone into alarm state
|
|
|
|
{
|
2003-01-07 21:08:59 +08:00
|
|
|
print( "Applying ON_list\n" ) if ( main::VERBOSE );
|
2002-12-24 19:53:41 +08:00
|
|
|
$task_list = $monitor->{"ON_list"};
|
|
|
|
}
|
|
|
|
elsif ( $state == 0 && $monitor->{LastState} > 0 ) # Come out of alarm state
|
|
|
|
{
|
2003-01-07 21:08:59 +08:00
|
|
|
print( "Applying OFF_list\n" ) if ( main::VERBOSE );
|
2002-12-24 19:53:41 +08:00
|
|
|
$task_list = $monitor->{"OFF_list"};
|
|
|
|
}
|
|
|
|
if ( $task_list )
|
|
|
|
{
|
|
|
|
foreach my $task ( @$task_list )
|
|
|
|
{
|
|
|
|
processTask( $task );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$monitor->{LastState} = $state;
|
|
|
|
}
|
|
|
|
|
2002-12-15 22:09:53 +08:00
|
|
|
# Check for pending tasks
|
|
|
|
my $now = time();
|
|
|
|
foreach my $activation_time ( sort(keys(%pending_tasks) ) )
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
last if ( $activation_time > $now );
|
|
|
|
my $pending_list = $pending_tasks{$activation_time};
|
|
|
|
foreach my $task ( @$pending_list )
|
|
|
|
{
|
2003-01-02 20:55:09 +08:00
|
|
|
processTask( $task );
|
2002-12-15 22:09:53 +08:00
|
|
|
}
|
|
|
|
delete( $pending_tasks{$activation_time} );
|
2002-12-05 19:32:40 +08:00
|
|
|
}
|
2003-01-03 03:28:30 +08:00
|
|
|
if ( $reload || ++$reload_count >= $reload_limit )
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
loadTasks();
|
2002-12-24 19:53:41 +08:00
|
|
|
$reload = undef;
|
2003-01-02 20:55:09 +08:00
|
|
|
$reload_count = 0;
|
2002-12-05 19:32:40 +08:00
|
|
|
}
|
|
|
|
}
|
2002-12-15 22:09:53 +08:00
|
|
|
}
|
|
|
|
print( LOG "X10 server exiting at ".strftime( '%y/%m/%d %H:%M:%S', localtime() )."\n" );
|
|
|
|
close( LOG );
|
|
|
|
close( SERVER );
|
|
|
|
exit();
|
|
|
|
}
|
|
|
|
|
2002-12-24 19:53:41 +08:00
|
|
|
sub addToDeviceList
|
2002-12-15 22:09:53 +08:00
|
|
|
{
|
|
|
|
my $unit_code = shift;
|
|
|
|
my $event = shift;
|
|
|
|
my $monitor = shift;
|
|
|
|
my $function = shift;
|
|
|
|
my $limit = shift;
|
|
|
|
|
2003-01-07 21:08:59 +08:00
|
|
|
print( "Adding to device list, uc:$unit_code, ev:$event, mo:$monitor, fu:$function, li:$limit\n" ) if ( main::VERBOSE );
|
2002-12-15 22:09:53 +08:00
|
|
|
my $device = $device_hash{$unit_code};
|
|
|
|
if ( !$device )
|
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
$device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), status=>'unknown' };
|
2002-12-15 22:09:53 +08:00
|
|
|
}
|
|
|
|
|
2002-12-24 19:53:41 +08:00
|
|
|
my $task = { type=>"device", monitor=>$monitor->{Id}, function=>$function };
|
2002-12-15 22:09:53 +08:00
|
|
|
if ( $limit )
|
|
|
|
{
|
|
|
|
$task->{limit} = $limit
|
|
|
|
}
|
|
|
|
|
|
|
|
my $task_list = $device->{$event."_list"};
|
|
|
|
if ( !$task_list )
|
|
|
|
{
|
|
|
|
$task_list = $device->{$event."_list"} = [];
|
|
|
|
}
|
|
|
|
push( @$task_list, $task );
|
|
|
|
}
|
2002-12-05 19:32:40 +08:00
|
|
|
|
2002-12-24 19:53:41 +08:00
|
|
|
sub addToMonitorList
|
|
|
|
{
|
|
|
|
my $monitor = shift;
|
|
|
|
my $event = shift;
|
|
|
|
my $unit_code = shift;
|
|
|
|
my $function = shift;
|
|
|
|
my $limit = shift;
|
|
|
|
|
2003-01-07 21:08:59 +08:00
|
|
|
print( "Adding to monitor list, uc:$unit_code, ev:$event, mo:$monitor, fu:$function, li:$limit\n" ) if ( main::VERBOSE );
|
2002-12-24 19:53:41 +08:00
|
|
|
my $device = $device_hash{$unit_code};
|
|
|
|
if ( !$device )
|
|
|
|
{
|
2003-01-02 20:24:00 +08:00
|
|
|
$device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), status=>'unknown' };
|
2002-12-24 19:53:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
my $task = { type=>"monitor", device=>$device, function=>$function };
|
|
|
|
if ( $limit )
|
|
|
|
{
|
2003-01-02 20:55:09 +08:00
|
|
|
$task->{limit} = $limit;
|
2002-12-24 19:53:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
my $task_list = $monitor->{$event."_list"};
|
|
|
|
if ( !$task_list )
|
|
|
|
{
|
|
|
|
$task_list = $monitor->{$event."_list"} = [];
|
|
|
|
}
|
|
|
|
push( @$task_list, $task );
|
|
|
|
}
|
|
|
|
|
2002-12-15 22:09:53 +08:00
|
|
|
sub loadTasks
|
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
%monitor_hash = ();
|
2002-12-05 19:32:40 +08:00
|
|
|
|
2003-01-07 21:08:59 +08:00
|
|
|
print( "Loading tasks\n" ) if ( main::VERBOSE );
|
2002-12-15 22:09:53 +08:00
|
|
|
# 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} = [];
|
|
|
|
}
|
2002-12-14 07:23:40 +08:00
|
|
|
|
2002-12-15 22:09:53 +08:00
|
|
|
my $sql = "select * from Monitors";
|
|
|
|
my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() );
|
|
|
|
my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() );
|
|
|
|
while( my $monitor = $sth->fetchrow_hashref() )
|
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
if ( $monitor->{Function} ne 'None' )
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
$monitor_hash{$monitor->{Id}} = $monitor;
|
|
|
|
|
|
|
|
my $size = 4; # We only need the first 4 bytes really for the alarm state
|
|
|
|
$monitor->{ShmKey} = main::ZM_SHM_KEY|$monitor->{Id};
|
|
|
|
if ( !($monitor->{ShmId} = shmget( $monitor->{ShmKey}, $size, 0 )) )
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
print( "Can't get shared memory id: $!\n" );
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( $monitor->{Function} eq 'X10' && $monitor->{X10Activation} )
|
|
|
|
{
|
2003-01-07 21:08:59 +08:00
|
|
|
print( "$monitor->{Name} has active string '$monitor->{X10Activation}'\n" ) if ( main::VERBOSE );
|
2002-12-24 19:53:41 +08:00
|
|
|
foreach my $code_string ( split( ',', $monitor->{X10Activation} ) )
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
#print( "Code string: $code_string\n" );
|
|
|
|
my ( $invert, $unit_code, $modifier, $limit ) = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ );
|
|
|
|
$limit = 0 if ( !$limit );
|
|
|
|
if ( $unit_code )
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
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 );
|
|
|
|
}
|
2002-12-14 07:23:40 +08:00
|
|
|
}
|
2002-12-05 19:32:40 +08:00
|
|
|
}
|
|
|
|
}
|
2002-12-24 19:53:41 +08:00
|
|
|
if ( $monitor->{X10AlarmInput} )
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2003-01-07 21:08:59 +08:00
|
|
|
print( "$monitor->{Name} has alarm input string '$monitor->{X10AlarmInput}'\n" ) if ( main::VERBOSE );
|
2002-12-24 19:53:41 +08:00
|
|
|
foreach my $code_string ( split( ',', $monitor->{X10AlarmInput} ) )
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
#print( "Code string: $code_string\n" );
|
|
|
|
my ( $invert, $unit_code, $modifier, $limit ) = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ );
|
|
|
|
$limit = 0 if ( !$limit );
|
|
|
|
if ( $unit_code )
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
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 );
|
|
|
|
}
|
2002-12-05 19:32:40 +08:00
|
|
|
}
|
2002-12-24 19:53:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( $monitor->{X10AlarmOutput} )
|
|
|
|
{
|
2003-01-07 21:08:59 +08:00
|
|
|
print( "$monitor->{Name} has alarm output string '$monitor->{X10AlarmOutput}'\n" ) if ( main::VERBOSE );
|
2002-12-24 19:53:41 +08:00
|
|
|
foreach my $code_string ( split( ',', $monitor->{X10AlarmOutput} ) )
|
|
|
|
{
|
|
|
|
#print( "Code string: $code_string\n" );
|
|
|
|
my ( $invert, $unit_code, $modifier, $limit ) = ( $code_string =~ /^([!~])?(\d+)(?:([+-])(\d+)?)?$/ );
|
|
|
|
$limit = 0 if ( !$limit );
|
|
|
|
if ( $unit_code )
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
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 );
|
|
|
|
}
|
2002-12-05 19:32:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-12-15 22:09:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub addPendingTask
|
|
|
|
{
|
|
|
|
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 )
|
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
if ( $task->{type} eq "device" )
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
if (( $task->{monitor}->{Id} != $pending_task->{monitor}->{Id} )
|
|
|
|
|| ( $task->{function} != $pending_task->{function} ))
|
|
|
|
{
|
|
|
|
push( @$new_pending_list, $pending_task )
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elsif ( $task->{type} eq "monitor" )
|
|
|
|
{
|
2003-01-02 20:55:09 +08:00
|
|
|
if (( $task->{device}->{appliance}->unit_code() != $pending_task->{device}->{appliance}->unit_code() )
|
2002-12-24 19:53:41 +08:00
|
|
|
|| ( $task->{function} != $pending_task->{function} ))
|
|
|
|
{
|
|
|
|
push( @$new_pending_list, $pending_task )
|
|
|
|
}
|
2002-12-05 19:32:40 +08:00
|
|
|
}
|
2002-12-15 22:09:53 +08:00
|
|
|
}
|
|
|
|
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} = [];
|
|
|
|
}
|
2002-12-24 19:53:41 +08:00
|
|
|
my $pending_task;
|
|
|
|
if ( $task->{type} eq "device" )
|
|
|
|
{
|
2003-01-02 20:55:09 +08:00
|
|
|
$pending_task = { type=>$task->{type}, monitor=>$task->{monitor}, function=>$task->{function} };
|
2002-12-24 19:53:41 +08:00
|
|
|
$pending_task->{function} =~ s/start/stop/;
|
|
|
|
}
|
|
|
|
elsif ( $task->{type} eq "monitor" )
|
|
|
|
{
|
2003-01-02 20:55:09 +08:00
|
|
|
$pending_task = { type=>$task->{type}, device=>$task->{device}, function=>$task->{function} };
|
2002-12-24 19:53:41 +08:00
|
|
|
$pending_task->{function} =~ s/on/off/;
|
|
|
|
}
|
2002-12-15 22:41:41 +08:00
|
|
|
push( @$pending_list, $pending_task );
|
2002-12-15 22:09:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
sub processTask
|
|
|
|
{
|
|
|
|
my $task = shift;
|
|
|
|
|
2002-12-24 19:53:41 +08:00
|
|
|
if ( $task->{type} eq "device" )
|
2002-12-15 22:09:53 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
my ( $instruction, $class ) = ( $task->{function} =~ /^(.+)_(.+)$/ );
|
|
|
|
|
|
|
|
my $command;
|
|
|
|
if ( $class eq "active" )
|
2002-12-15 22:09:53 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
if ( $instruction eq "start" )
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2003-01-03 03:28:30 +08:00
|
|
|
$command = main::COMMAND_PATH."zmdc.pl start zma -m ".$task->{monitor};
|
2002-12-24 19:53:41 +08:00
|
|
|
if ( $task->{limit} )
|
|
|
|
{
|
|
|
|
addPendingTask( $task );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elsif( $instruction eq "stop" )
|
|
|
|
{
|
2003-01-03 03:28:30 +08:00
|
|
|
$command = main::COMMAND_PATH."zmdc.pl stop zma -m ".$task->{monitor};
|
2002-12-05 19:32:40 +08:00
|
|
|
}
|
|
|
|
}
|
2002-12-24 19:53:41 +08:00
|
|
|
elsif( $class eq "alarm" )
|
2002-12-15 22:09:53 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
if ( $instruction eq "start" )
|
|
|
|
{
|
|
|
|
$command = main::COMMAND_PATH."zmu --monitor ".$task->{monitor}." --alarm";
|
|
|
|
if ( $task->{limit} )
|
|
|
|
{
|
|
|
|
addPendingTask( $task );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elsif( $instruction eq "stop" )
|
|
|
|
{
|
|
|
|
$command = main::COMMAND_PATH."zmu --monitor ".$task->{monitor}." --cancel";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
print( "Executing command '$command'\n" );
|
|
|
|
if ( $command )
|
|
|
|
{
|
|
|
|
qx( $command );
|
2002-12-15 22:09:53 +08:00
|
|
|
}
|
|
|
|
}
|
2002-12-24 19:53:41 +08:00
|
|
|
elsif( $task->{type} eq "monitor" )
|
2002-12-15 22:09:53 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
if ( $task->{function} eq "on" )
|
2002-12-15 22:09:53 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
$task->{device}->{appliance}->on();
|
2002-12-15 22:09:53 +08:00
|
|
|
if ( $task->{limit} )
|
|
|
|
{
|
|
|
|
addPendingTask( $task );
|
|
|
|
}
|
|
|
|
}
|
2002-12-24 19:53:41 +08:00
|
|
|
elsif ( $task->{function} eq "off" )
|
2002-12-15 22:09:53 +08:00
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
$task->{device}->{appliance}->off();
|
2002-12-15 22:09:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub dprint
|
|
|
|
{
|
|
|
|
if ( fileno(CLIENT) )
|
|
|
|
{
|
|
|
|
print CLIENT @_
|
2002-12-05 19:32:40 +08:00
|
|
|
}
|
2003-01-03 03:28:30 +08:00
|
|
|
print @_;
|
2002-12-05 19:32:40 +08:00
|
|
|
}
|
2002-12-15 22:09:53 +08:00
|
|
|
|
|
|
|
sub x10listen
|
2002-12-05 19:32:40 +08:00
|
|
|
{
|
2002-12-15 22:09:53 +08:00
|
|
|
foreach my $event ( @_ )
|
|
|
|
{
|
2002-12-24 19:53:41 +08:00
|
|
|
#print( Data::Dumper( $_ )."\n" );
|
2003-01-11 08:15:29 +08:00
|
|
|
if ( $event->house_code() eq main::ZM_X10_HOUSE_CODE )
|
2002-12-15 22:09:53 +08:00
|
|
|
{
|
|
|
|
my $unit_code = $event->unit_code();
|
|
|
|
my $device = $device_hash{$unit_code};
|
|
|
|
if ( !$device )
|
|
|
|
{
|
2003-01-02 20:24:00 +08:00
|
|
|
$device = $device_hash{$unit_code} = { appliance=>$x10->Appliance( unit_code=>$unit_code ), status=>'unknown' };
|
2002-12-15 22:09:53 +08:00
|
|
|
}
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
print( LOG strftime( "%y/%m/%d %H:%M:%S", localtime() )." - ".$event->as_string()."\n" );
|
|
|
|
}
|
2002-12-05 19:32:40 +08:00
|
|
|
}
|
2002-12-15 22:09:53 +08:00
|
|
|
|
|
|
|
1;
|