amplifierPower.pl 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use IPC::System::Simple qw( system capture );
  5. use Time::HiRes qw( usleep sleep time );
  6. # Local modules
  7. use Cwd qw(abs_path);
  8. use File::Basename qw(dirname);
  9. use lib dirname(abs_path($0));
  10. use DMX;
  11. # Prototypes
  12. sub sendCmd($$);
  13. # App config
  14. my $DATA_DIR = DMX::dataDir();
  15. my $STATE_SOCK = 'AMPLIFIER_POWER';
  16. my $AMP_SOCK = 'AMPLIFIER';
  17. my $OUTPUT_FILE = $DATA_DIR . $STATE_SOCK;
  18. my $PUSH_TIMEOUT = 20;
  19. my $PULL_TIMEOUT = $PUSH_TIMEOUT * 3;
  20. my $DELAY = $PULL_TIMEOUT / 2;
  21. my $CMD_DELAY = 5.0;
  22. my $AUTO_CMD = 'INPUT_AUTO';
  23. # Debug
  24. my $DEBUG = 0;
  25. if ($ENV{'DEBUG'}) {
  26. $DEBUG = 1;
  27. }
  28. # Sockets
  29. DMX::stateSocket($STATE_SOCK);
  30. DMX::stateSubscribe($STATE_SOCK);
  31. my $amp = DMX::clientSock($AMP_SOCK);
  32. # State
  33. my $state = 'OFF';
  34. my $mode = 'SURROUND';
  35. my $input = 'TV';
  36. my $stateLast = $state;
  37. my %exists = ();
  38. my $pushLast = 0;
  39. my $pullLast = time();
  40. my $update = 0;
  41. my $lastMode = 0;
  42. my $lastInput = 0;
  43. my $lastPower = 0;
  44. # Loop forever
  45. while (1) {
  46. # State is calculated; use newState to gather data
  47. my $newState = $state;
  48. # Wait for state updates
  49. my $cmdState = DMX::readState($DELAY, \%exists, undef(), undef());
  50. # Avoid repeated calls to time()
  51. my $now = time();
  52. # Record only valid states
  53. if (defined($cmdState)) {
  54. $newState = $cmdState;
  55. $pullLast = time();
  56. }
  57. # Die if we don't see regular updates
  58. if ($now - $pullLast > $PULL_TIMEOUT) {
  59. die('No update on state socket in past ' . $PULL_TIMEOUT . " seconds. Exiting...\n");
  60. }
  61. # Calculate the new state
  62. $stateLast = $state;
  63. if ($newState eq 'PLAY') {
  64. $state = 'ON';
  65. } elsif ($exists{'RAVE'}) {
  66. $state = 'RAVE';
  67. } elsif ($newState eq 'PAUSE') {
  68. $state = 'ON';
  69. } else {
  70. $state = 'OFF';
  71. }
  72. # Calculate the channel mode
  73. if ($exists{'STEREO_CMD'} || $exists{'PLAYING_TYPE'} eq 'audio' || $state eq 'RAVE') {
  74. $mode = 'STEREO';
  75. } else {
  76. $mode = 'SURROUND';
  77. }
  78. # Force updates on a periodic basis
  79. if (!$update && $now - $pushLast > $PUSH_TIMEOUT) {
  80. # Not for the amp
  81. #if ($DEBUG) {
  82. # print STDERR "Forcing periodic update\n";
  83. #}
  84. #$update = 1;
  85. }
  86. # Force updates on any state change
  87. if (!$update && $stateLast ne $state) {
  88. if ($DEBUG) {
  89. print STDERR 'State change: ' . $stateLast . ' => ' . $state . "\n";
  90. }
  91. $update = 1;
  92. }
  93. # Force updates when there is a physical state mistmatch
  94. if (!$update && (($state eq 'OFF' && $exists{'AMPLIFIER'}) || ($state eq 'ON' && !$exists{'AMPLIFIER'}))) {
  95. if ($DEBUG) {
  96. print STDERR 'Physical state mismatch: ' . $state . ':' . $exists{'AMPLIFIER'} . "\n";
  97. }
  98. $update = 1;
  99. }
  100. # Set the channel mode as needed
  101. if ($exists{'AMPLIFIER'} && $exists{'AMPLIFIER_MODE'} ne $mode && $lastMode < $now - $CMD_DELAY) {
  102. $lastMode = $now;
  103. if ($DEBUG) {
  104. print STDERR 'Setting mode to: ' . $mode . "\n";
  105. }
  106. DMX::say('Amplifier mode: ' . $mode);
  107. sendCmd($amp, $mode);
  108. # Reset the input mode anytime we switch to SURROUND
  109. if ($mode eq 'SURROUND') {
  110. sendCmd($amp, $AUTO_CMD);
  111. }
  112. }
  113. # Set the amplifier input as needed
  114. if ($exists{'AMPLIFIER'} && $exists{'AMPLIFIER_INPUT'} ne $input && $lastInput < $now - $CMD_DELAY) {
  115. $lastInput = $now;
  116. if ($DEBUG) {
  117. print STDERR 'Setting input to: ' . $input . "\n";
  118. }
  119. DMX::say('Amplifier input: ' . $input);
  120. sendCmd($amp, $input);
  121. }
  122. # Update the amp
  123. if ($update) {
  124. # Extra debugging to record pushes
  125. if ($DEBUG) {
  126. print STDERR 'State: ' . $state . "\n";
  127. }
  128. # Send master power state
  129. my $cmd = undef();
  130. if ($state eq 'OFF' || $state eq 'ON') {
  131. $cmd = $state;
  132. } elsif ($state eq 'RAVE') {
  133. $cmd = 'ON';
  134. }
  135. if (defined($cmd) && $lastPower < $now - $CMD_DELAY) {
  136. $lastPower = $now;
  137. sendCmd($amp, $cmd);
  138. }
  139. # No output file
  140. # Update the push time
  141. $pushLast = $now;
  142. # Clear the update flag
  143. $update = 0;
  144. }
  145. }
  146. # Send the requested command and enforce an inter-command delay
  147. sub sendCmd($$) {
  148. my ($amp, $cmd) = @_;
  149. # Send the command
  150. $amp->send($cmd)
  151. or die('Unable to write command to amp socket: ' . $cmd . ": ${!}\n");
  152. # A tiny delay to keep the serial port stable in repeated calls
  153. sleep(0.1);
  154. }