|
@@ -0,0 +1,161 @@
|
|
|
|
|
+#!/usr/bin/perl
|
|
|
|
|
+use strict;
|
|
|
|
|
+use warnings;
|
|
|
|
|
+use IO::Socket;
|
|
|
|
|
+use Time::HiRes qw( usleep );
|
|
|
|
|
+use File::Temp qw( tempfile );
|
|
|
|
|
+
|
|
|
|
|
+# Prototypes
|
|
|
|
|
+sub dim($$$);
|
|
|
|
|
+
|
|
|
|
|
+# Channels:
|
|
|
|
|
+# 0 => All channels
|
|
|
|
|
+# 1 => Couch-side hidden
|
|
|
|
|
+# 2 => Couch-side exposed
|
|
|
|
|
+# 3 => Stairs
|
|
|
|
|
+# 4 => <Unused>
|
|
|
|
|
+# 5 => Bar-side hidden
|
|
|
|
|
+# 6 => Bar-side bar-shelves
|
|
|
|
|
+# 7 => Bar-side exposed
|
|
|
|
|
+# 8 => Bar-side ceiling
|
|
|
|
|
+# 9 => <Unused>
|
|
|
|
|
+# 10 => <Unused>
|
|
|
|
|
+# 11 => Fan
|
|
|
|
|
+# 12 => Bias Light
|
|
|
|
|
+
|
|
|
|
|
+# User config
|
|
|
|
|
+my %DIM = (
|
|
|
|
|
+ 'OFF' => [
|
|
|
|
|
+ { 'channel' => 11, 'value' => 0, 'time' => 0 }
|
|
|
|
|
+ ],
|
|
|
|
|
+ 'ON' => [
|
|
|
|
|
+ { 'channel' => 11, 'value' => 255, 'time' => 0 }
|
|
|
|
|
+ ],
|
|
|
|
|
+);
|
|
|
|
|
+my $TIMEOUT = 180;
|
|
|
|
|
+
|
|
|
|
|
+# App config
|
|
|
|
|
+my $SOCK_TIMEOUT = 5;
|
|
|
|
|
+my $TEMP_DIR = `getconf DARWIN_USER_TEMP_DIR`;
|
|
|
|
|
+chomp($TEMP_DIR);
|
|
|
|
|
+my $DATA_DIR = $TEMP_DIR . 'plexMonitor/';
|
|
|
|
|
+my $CMD_FILE = $DATA_DIR . 'DMX.socket';
|
|
|
|
|
+
|
|
|
|
|
+# Debug
|
|
|
|
|
+my $DEBUG = 0;
|
|
|
|
|
+if ($ENV{'DEBUG'}) {
|
|
|
|
|
+ $DEBUG = 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# Command-line arguments
|
|
|
|
|
+my ($DELAY) = @ARGV;
|
|
|
|
|
+if (!$DELAY) {
|
|
|
|
|
+ $DELAY = 0.5;
|
|
|
|
|
+}
|
|
|
|
|
+$DELAY *= 1000000; # Microseconds;
|
|
|
|
|
+
|
|
|
|
|
+# Sanity check
|
|
|
|
|
+if (!-d $DATA_DIR || !-S $CMD_FILE) {
|
|
|
|
|
+ die("Bad config\n");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# Socket init
|
|
|
|
|
+my $sock = IO::Socket::UNIX->new(
|
|
|
|
|
+ 'Peer' => $CMD_FILE,
|
|
|
|
|
+ 'Type' => SOCK_DGRAM,
|
|
|
|
|
+ 'Timeout' => $SOCK_TIMEOUT
|
|
|
|
|
+) or die('Unable to open socket: ' . $CMD_FILE . ": ${@}\n");
|
|
|
|
|
+
|
|
|
|
|
+# State
|
|
|
|
|
+my $state = 'INIT';
|
|
|
|
|
+my $stateLast = $state;
|
|
|
|
|
+my $fan = 0;
|
|
|
|
|
+my $projector = 0;
|
|
|
|
|
+
|
|
|
|
|
+# Always force lights out at launch
|
|
|
|
|
+dim(11, 0, 0);
|
|
|
|
|
+
|
|
|
|
|
+# Loop forever
|
|
|
|
|
+while (1) {
|
|
|
|
|
+
|
|
|
|
|
+ # Monitor the PROJECTOR file for state
|
|
|
|
|
+ {
|
|
|
|
|
+ $projector = 0;
|
|
|
|
|
+ my $fh;
|
|
|
|
|
+ open($fh, $DATA_DIR . 'PROJECTOR')
|
|
|
|
|
+ or die("Unable to open PROJECTOR\n");
|
|
|
|
|
+ my $text = <$fh>;
|
|
|
|
|
+ close($fh);
|
|
|
|
|
+ if ($text =~ /1/) {
|
|
|
|
|
+ $projector = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($DEBUG) {
|
|
|
|
|
+ print STDERR 'Projector: ' . $projector . "\n";
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # Monitor the FAN_CMD file for presence
|
|
|
|
|
+ {
|
|
|
|
|
+ # Clear the flag when the projector is off
|
|
|
|
|
+ if ($fan && !$projector) {
|
|
|
|
|
+ unlink($DATA_DIR . 'FAN_CMD');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $fan = 0;
|
|
|
|
|
+ if (-e $DATA_DIR . 'FAN_CMD') {
|
|
|
|
|
+ $fan = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($DEBUG) {
|
|
|
|
|
+ print STDERR 'Fan: ' . $fan . "\n";
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # Calculate the new state
|
|
|
|
|
+ $stateLast = $state;
|
|
|
|
|
+ if ($fan) {
|
|
|
|
|
+ if ($projector) {
|
|
|
|
|
+ $state = 'ON';
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $state = 'OFF';
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $state = 'OFF';
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($state eq 'INIT') {
|
|
|
|
|
+ $state = 'OFF';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # Update the fan state
|
|
|
|
|
+ if ($stateLast ne $state) {
|
|
|
|
|
+ if ($DEBUG) {
|
|
|
|
|
+ print STDERR 'State: ' . $stateLast . ' => ' . $state . "\n";
|
|
|
|
|
+ foreach my $data (@{ $DIM{$state} }) {
|
|
|
|
|
+ print STDERR "\t" . $data->{'channel'} . ' => ' . $data->{'value'} . ' @ ' . $data->{'time'} . "\n";
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # Send the dim command
|
|
|
|
|
+ my @values = ();
|
|
|
|
|
+ foreach my $data (@{ $DIM{$state} }) {
|
|
|
|
|
+ dim($data->{'channel'}, $data->{'time'}, $data->{'value'});
|
|
|
|
|
+ push(@values, $data->{'channel'} . ' => ' . $data->{'value'} . ' @ ' . $data->{'time'});
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # Save the state and value to disk
|
|
|
|
|
+ my ($fh, $tmp) = tempfile($DATA_DIR . 'FAN.XXXXXXXX', 'UNLINK' => 0);
|
|
|
|
|
+ print $fh 'State: ' . $state . "\n" . join("\n", @values) . "\n";
|
|
|
|
|
+ close($fh);
|
|
|
|
|
+ rename($tmp, $DATA_DIR . 'FAN');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ # Wait and loop
|
|
|
|
|
+ usleep($DELAY);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+# Send the command
|
|
|
|
|
+sub dim($$$) {
|
|
|
|
|
+ my ($channel, $duration, $intensity) = @_;
|
|
|
|
|
+ my $cmd = join(':', $channel, $duration, $intensity);
|
|
|
|
|
+ $sock->send($cmd)
|
|
|
|
|
+ or die('Unable to write command to socket: ' . $CMD_FILE . ': ' . $cmd . ": ${!}\n");
|
|
|
|
|
+}
|