announce.pl 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use Email::MIME;
  5. use Email::Sender::Simple qw(sendmail);
  6. use File::Basename qw(dirname);
  7. use Sys::Hostname;
  8. # Local modules
  9. use Cwd qw(abs_path);
  10. use lib dirname(abs_path($0));
  11. use DMX;
  12. # App config
  13. my $DATA_DIR = DMX::dataDir();
  14. my $STATE_SOCK = 'ANNOUNCE';
  15. my $OUTPUT_FILE = $DATA_DIR . $STATE_SOCK;
  16. my $PUSH_TIMEOUT = 20;
  17. my $PULL_TIMEOUT = $PUSH_TIMEOUT * 3;
  18. my $DELAY = $PULL_TIMEOUT / 2;
  19. my $SPEAK_DELAY = 5;
  20. # Debug
  21. my $DEBUG = 0;
  22. if ($ENV{'DEBUG'}) {
  23. $DEBUG = 1;
  24. }
  25. # State
  26. my %exists = ();
  27. my %last = ();
  28. my %mtime = ();
  29. my $pullLast = time();
  30. my $speakLast = time();
  31. # Sockets
  32. DMX::stateSocket($STATE_SOCK);
  33. DMX::stateSubscribe($STATE_SOCK);
  34. # Loop forever
  35. while (1) {
  36. # Remember the last state, for comparison
  37. %last = %exists;
  38. # Wait for state updates
  39. my $cmdState = DMX::readState($DELAY, \%exists, \%mtime, undef());
  40. # Avoid repeated calls to time()
  41. my $now = time();
  42. # Record only valid states
  43. if (defined($cmdState)) {
  44. $pullLast = $now;
  45. }
  46. # Die if we don't see regular updates
  47. if ($now - $pullLast > $PULL_TIMEOUT) {
  48. die('No update on state socket in past ' . $PULL_TIMEOUT . " seconds. Exiting...\n");
  49. }
  50. # Speak when BRIGHT changes
  51. if (exists($exists{'BRIGHT'}) && exists($last{'BRIGHT'}) && $exists{'BRIGHT'} ne $last{'BRIGHT'}) {
  52. if ($exists{'BRIGHT'}) {
  53. DMX::say('Lights - Full power');
  54. } else {
  55. DMX::say('Lights - Nominal power');
  56. }
  57. }
  58. # Speak when LIGHTS changes
  59. if (exists($exists{'LIGHTS'}) && exists($last{'LIGHTS'}) && $exists{'LIGHTS'} ne $last{'LIGHTS'}) {
  60. if ($exists{'LIGHTS'}) {
  61. DMX::say('Lights up');
  62. } else {
  63. DMX::say('Lights down');
  64. }
  65. }
  66. # Speak when NO_MOTION changes
  67. if (exists($exists{'NO_MOTION'}) && exists($last{'NO_MOTION'}) && $exists{'NO_MOTION'} ne $last{'NO_MOTION'}) {
  68. if ($exists{'NO_MOTION'}) {
  69. DMX::say('Motion detectors: Disabled');
  70. } else {
  71. DMX::say('Motion detectors: Enabled');
  72. }
  73. }
  74. # Speak when LOCK changes
  75. if (exists($exists{'LOCK'}) && exists($last{'LOCK'}) && $exists{'LOCK'} ne $last{'LOCK'}) {
  76. if ($exists{'LOCK'}) {
  77. DMX::say('System locked');
  78. } else {
  79. DMX::say('System unlocked');
  80. }
  81. }
  82. # Email when ALARM is asserted
  83. if (exists($exists{'ALARM'}) && exists($last{'ALARM'}) && $exists{'ALARM'} && !$last{'ALARM'}) {
  84. my @exists_tmp = ();
  85. foreach my $key (sort(keys(%exists))) {
  86. push(@exists_tmp, $key . ":\t" . $exists{$key} . ' @ ' . $mtime{$key});
  87. }
  88. my $message = Email::MIME->create(
  89. header_str => [
  90. To => 'zach@kotlarek.com',
  91. From => $ENV{'USER'} . '@' . Sys::Hostname::hostname(),
  92. Subject => 'Alarm Activated',
  93. ],
  94. attributes => {
  95. encoding => 'quoted-printable',
  96. charset => 'ISO-8859-1',
  97. },
  98. body_str => 'Alarm activated: ' . localtime() . "\n\nState: " . $cmdState . "\n" . join("\n", @exists_tmp) . "\n",
  99. );
  100. sendmail($message);
  101. }
  102. # Ongoing spoken ALARM
  103. if ($exists{'ALARM'}) {
  104. if ($now - $speakLast > $SPEAK_DELAY) {
  105. $speakLast = $now;
  106. DMX::say('Unauthorized access detected.');
  107. }
  108. }
  109. }