fan.pl 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use IO::Socket;
  5. use Time::HiRes qw( usleep );
  6. use File::Temp qw( tempfile );
  7. # Prototypes
  8. sub dim($);
  9. # Channels:
  10. # 0 => All channels
  11. # 1 => Couch-side hidden
  12. # 2 => Couch-side exposed
  13. # 3 => Stairs
  14. # 4 => <Unused>
  15. # 5 => Bar-side hidden
  16. # 6 => Bar-side bar-shelves
  17. # 7 => Bar-side exposed
  18. # 8 => Bar-side ceiling
  19. # 9 => <Unused>
  20. # 10 => <Unused>
  21. # 11 => Fan
  22. # 12 => Bias Light
  23. # User config
  24. my %DIM = (
  25. 'OFF' => [
  26. { 'channel' => 11, 'value' => 0, 'time' => 0 }
  27. ],
  28. 'ON' => [
  29. { 'channel' => 11, 'value' => 255, 'time' => 0 }
  30. ],
  31. );
  32. my $TIMEOUT = 180;
  33. # App config
  34. my $SOCK_TIMEOUT = 5;
  35. my $TEMP_DIR = `getconf DARWIN_USER_TEMP_DIR`;
  36. chomp($TEMP_DIR);
  37. my $DATA_DIR = $TEMP_DIR . 'plexMonitor/';
  38. my $CMD_FILE = $DATA_DIR . 'DMX.socket';
  39. # Debug
  40. my $DEBUG = 0;
  41. if ($ENV{'DEBUG'}) {
  42. $DEBUG = 1;
  43. }
  44. # Command-line arguments
  45. my ($DELAY) = @ARGV;
  46. if (!$DELAY) {
  47. $DELAY = 0.5;
  48. }
  49. $DELAY *= 1000000; # Microseconds;
  50. # Sanity check
  51. if (!-d $DATA_DIR || !-S $CMD_FILE) {
  52. die("Bad config\n");
  53. }
  54. # Socket init
  55. my $sock = IO::Socket::UNIX->new(
  56. 'Peer' => $CMD_FILE,
  57. 'Type' => SOCK_DGRAM,
  58. 'Timeout' => $SOCK_TIMEOUT
  59. ) or die('Unable to open socket: ' . $CMD_FILE . ": ${@}\n");
  60. # State
  61. my $state = 'INIT';
  62. my $stateLast = $state;
  63. my $fan = 0;
  64. my $projector = 0;
  65. # Always force lights out at launch
  66. dim({'channel' => 11, 'value' => 0, 'time' => 0});
  67. # Loop forever
  68. while (1) {
  69. # Monitor the PROJECTOR file for state
  70. {
  71. $projector = 0;
  72. my $fh;
  73. open($fh, $DATA_DIR . 'PROJECTOR')
  74. or die("Unable to open PROJECTOR\n");
  75. my $text = <$fh>;
  76. close($fh);
  77. if ($text =~ /1/) {
  78. $projector = 1;
  79. }
  80. if ($DEBUG) {
  81. print STDERR 'Projector: ' . $projector . "\n";
  82. }
  83. }
  84. # Monitor the FAN_CMD file for presence
  85. {
  86. # Clear the flag when the projector is off
  87. if ($fan && !$projector) {
  88. unlink($DATA_DIR . 'FAN_CMD');
  89. }
  90. $fan = 0;
  91. if (-e $DATA_DIR . 'FAN_CMD') {
  92. $fan = 1;
  93. }
  94. if ($DEBUG) {
  95. print STDERR 'Fan: ' . $fan . "\n";
  96. }
  97. }
  98. # Calculate the new state
  99. $stateLast = $state;
  100. if ($fan) {
  101. if ($projector) {
  102. $state = 'ON';
  103. } else {
  104. $state = 'OFF';
  105. }
  106. } else {
  107. $state = 'OFF';
  108. }
  109. if ($state eq 'INIT') {
  110. $state = 'OFF';
  111. }
  112. # Update the fan state
  113. if ($stateLast ne $state) {
  114. if ($DEBUG) {
  115. print STDERR 'State: ' . $stateLast . ' => ' . $state . "\n";
  116. foreach my $data (@{ $DIM{$state} }) {
  117. print STDERR "\t" . $data->{'channel'} . ' => ' . $data->{'value'} . ' @ ' . $data->{'time'} . "\n";
  118. }
  119. }
  120. # Send the dim command
  121. my @values = ();
  122. foreach my $data (@{ $DIM{$state} }) {
  123. dim($data);
  124. push(@values, $data->{'channel'} . ' => ' . $data->{'value'} . ' @ ' . $data->{'time'});
  125. }
  126. # Save the state and value to disk
  127. my ($fh, $tmp) = tempfile($DATA_DIR . 'FAN.XXXXXXXX', 'UNLINK' => 0);
  128. print $fh 'State: ' . $state . "\n" . join("\n", @values) . "\n";
  129. close($fh);
  130. rename($tmp, $DATA_DIR . 'FAN');
  131. }
  132. # Wait and loop
  133. usleep($DELAY);
  134. }
  135. # Send the command
  136. sub dim(%) {
  137. my ($args) = @_;
  138. if (! defined($args->{'delay'})) {
  139. $args->{'delay'} = 0;
  140. }
  141. if (! defined($args->{'channel'}) || ! defined($args->{'time'}) || ! defined($args->{'value'})) {
  142. die('Invalid command for socket: ' . join(', ', keys(%{$args})) . ': ' . join(', ', values(%{$args})) . "\n");
  143. }
  144. my $cmd = join(':', $args->{'channel'}, $args->{'time'}, $args->{'value'}, $args->{'delay'});
  145. $sock->send($cmd)
  146. or die('Unable to write command to socket: ' . $CMD_FILE . ': ' . $cmd . ": ${!}\n");
  147. }