$VERSION
= 0.04;
sub
new
{
my
$type
=
shift
;
my
$self
=
bless
{
@_
},
$type
;
$self
->{verbose} = 1
if
$self
->{debug};
$self
->{logger} =
sub
{
$self
->syslog(
@_
) };
unless
(
$self
->{controller_type})
{
warn
"Interface type must be specified\n"
;
return
undef
;
}
my
$controller
=
$self
->{controller_type};
if
(
eval
"require $controller"
)
{
$controller
->
import
;
}
else
{
die
"Can't load module for $controller: "
, $@;
}
$self
->{controller} =
$controller
->new(
port
=>
$self
->{controller_port},
debug
=>
$self
->{debug},
verbose
=>
$self
->{verbose},
logger
=>
sub
{
$self
->syslog(
@_
) },
);
$self
->{controller}->register_listener(
sub
{
$self
->syslog(
'info'
,
"Event: %s"
,
$_
[0]->as_string) }
);
if
(
exists
$self
->{devices})
{
}
if
(
exists
$self
->{schedulerconfig})
{
$self
->{scheduler} = new X10::Scheduler(
configfile
=>
$self
->{schedulerconfig},
controller
=>
$self
->{controller},
debug
=>
$self
->{debug},
verbose
=>
$self
->{verbose},
logger
=>
sub
{
$self
->syslog(
@_
) },
latitude
=> 38.74274,
longitude
=> -90.560143,
);
unless
(
$self
->{scheduler})
{
warn
"Problem creating macro processor"
;
return
undef
;
}
}
if
(
exists
$self
->{macroconfig})
{
$self
->{macrop} = new X10::MacroProc(
configfile
=>
$self
->{macroconfig},
controller
=>
$self
->{controller},
debug
=>
$self
->{debug},
verbose
=>
$self
->{verbose},
logger
=>
sub
{
$self
->syslog(
@_
) },
);
unless
(
$self
->{macrop})
{
warn
"Problem creating macro processor"
;
return
undef
;
}
}
if
(
exists
$self
->{server_port})
{
$self
->{server} = new X10::Server(
controller
=>
$self
->{controller},
debug
=>
$self
->{debug},
verbose
=>
$self
->{verbose},
server_port
=>
$self
->{server_port},
logger
=>
sub
{
$self
->syslog(
@_
) },
);
unless
(
$self
->{server})
{
warn
"Problem creating network server"
;
return
undef
;
}
}
return
$self
;
}
sub
run
{
my
$self
=
shift
;
$self
->{running} = 1;
$SIG
{
'INT'
} =
sub
{
$self
->{running} = 0; };
$SIG
{
'TERM'
} =
sub
{
$self
->{running} = 0; };
$self
->syslog(
'info'
,
"%s service starting"
,
$self
->{controller_type});
my
$next_wakeup
= 0;
X10RUNMAINLOOP:
while
(
$self
->{running})
{
$self
->{logger}->(
'info'
,
"Entering mainloop"
)
if
$self
->{debug};
my
%fdindex
;
foreach
my
$module
(
grep
{
exists
$self
->{
$_
} }
qw(controller server macrop)
)
{
foreach
my
$fd
(
$self
->{
$module
}->select_fds)
{
$fdindex
{
$fd
} =
$self
->{
$module
};
}
}
$self
->syslog(
'info'
,
"All FDs are %s\n"
,
join
(
', '
,
keys
%fdindex
))
if
$self
->{debug};
my
$rfd
=
''
;
foreach
(
keys
%fdindex
) {
vec
(
$rfd
,
$_
, 1) = 1; }
my
$timeout
=
undef
;
if
(
$self
->{scheduler})
{
my
$next_event_time
=
$self
->{scheduler}->next_event_time;
if
(
$next_event_time
)
{
$timeout
=
$next_event_time
-
int
(
time
);
$timeout
= 0
if
(
$timeout
< 0);
}
if
( (
defined
$timeout
) &&
$next_event_time
!=
$next_wakeup
)
{
$next_wakeup
=
$next_event_time
;
$self
->syslog(
'info'
,
"Next Scheduled Event: %s (%s seconds away)"
,
strftime(
"%a %b %e %H:%M %Y"
,
localtime
(
$next_event_time
)),
$timeout
,
);
}
}
my
$readers
;
my
$fdcount
=
select
(
$readers
=
$rfd
,
undef
,
undef
,
$timeout
);
if
(
$fdcount
> 0)
{
$self
->{logger}->(
'info'
,
"Got %s FDs to handle"
,
$fdcount
)
if
$self
->{debug};
foreach
(
keys
%fdindex
)
{
if
(
vec
(
$readers
,
$_
, 1))
{
$self
->syslog(
'info'
,
"Processing input on FD %s (%s)\n"
,
$_
,
$fdindex
{
$_
})
if
$self
->{debug};
$fdindex
{
$_
}->handle_input;
}
}
}
elsif
(
$fdcount
< 0 && $! != 4)
{
$self
->{logger}->(
'info'
,
"Error %d in select(): %s"
, $!, $!);
}
if
(
$self
->{scheduler})
{
$self
->{scheduler}->run;
}
}
$self
->syslog(
'info'
,
"%s service shutting down"
,
$self
->{controller_type});
}
sub
syslog
{
my
$self
=
shift
;
my
$level
=
shift
;
my
$format
=
shift
;
my
$message
=
sprintf
(
$format
,
@_
);
my
$facility
=
"local5"
;
my
$tag
=
sprintf
"%s[%s]"
,
basename($0,
".pl"
),
$$,
;
if
(
$self
->{debug})
{
printf
"syslog message: %s\n"
,
$message
;
}
else
{
my
$fh
= new FileHandle;
$fh
->
open
(
"|/usr/bin/logger -p $facility.$level -t $tag"
);
$fh
->
print
(
$message
);
$fh
->
close
;
}
}
1;