Created
May 7, 2018 19:59
-
-
Save truckershitch/99c4c0c23dd30d7512bdc9bc04e50d60 to your computer and use it in GitHub Desktop.
Blink arduino (and optionally esp8266) in response to inotify events
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
# | |
# blink_media_activity.pl | |
# Drives Arduino Nano to blink with media activity | |
# Version 1.1 5/7/18 15:57 | |
# Some refactoring - added SendWifiBeat | |
# | |
# Inspired by a script created by Ryan Babchishin | |
# Ryan Babchishin <rbabchishin@win2ix.ca> | |
# http://www.win2ix.ca | |
# | |
# Refactored with tons of help from this page | |
# https://jmorano.moretrix.com/2012/10/recursive-inotify-daemon/ | |
# This new version has better garbage collection. | |
# Copyright 2012 Johnny Morano | |
# | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
use strict; | |
use warnings; | |
use 5.010; # for state variables | |
use Device::SerialPort; | |
# Load the inotify perl module | |
use Linux::Inotify2; | |
use File::Find; | |
use POSIX; | |
use AnyEvent; | |
use Time::HiRes qw ( time tv_interval ); | |
use IO::Socket; | |
my $send_wifi_beat = 1; | |
# Set up the serial port | |
# 19200, 81N on the USB ftdi driver | |
my $port = Device::SerialPort->new("/dev/ttyUSB0"); | |
$port->databits(8); | |
$port->baudrate(19200); | |
$port->parity("none"); | |
$port->stopbits(1); | |
$port->dtr_active(0); | |
my @mediaDirs = ("/storage/samba/videos/TV", "/storage/samba/videos/Movies", | |
"/storage/samba/videos/Daemons", "/storage/recordings"); | |
my $cv = AnyEvent->condvar; | |
# Create inotify object | |
my $inotify = Linux::Inotify2->new or die "unable to create new inotify object: $!"; | |
my %watches; | |
foreach my $dir (@mediaDirs) { | |
ScanDirs($dir); | |
} | |
# Create event loop poller | |
my $poller = AnyEvent->io( | |
fh => $inotify->fileno, | |
poll => 'r', | |
cb => sub { $inotify->poll } | |
); | |
# Receive event signals (inotify signals) | |
$cv->recv; | |
sub SendWifiBeat { | |
my $request = shift; | |
my $PORTNO = 2390; | |
my $TIMEOUT = 5; | |
my $server_host = "192.168.1.81"; | |
my $sock = IO::Socket::INET->new(Proto => 'udp', | |
PeerPort => $PORTNO, | |
PeerAddr => $server_host) | |
or die "Creating socket: $!\n"; | |
$sock->send($request) or die "send: $!"; | |
} | |
sub Heartbeat { | |
state $bitmask = 0; | |
state $last_time = time; | |
state $beats = 0; | |
my $input = shift; | |
if ($input > 0) { | |
$bitmask |= $input; | |
} | |
my $elapsed = tv_interval([$last_time]); | |
my $beatcomplete = ($elapsed >= $beats * 0.5 + 1 || $beats == 0); # time is up | |
if ($bitmask > 0 && $beatcomplete) { | |
$beats = $bitmask; | |
$last_time = time; | |
#print "Elapsed: $elapsed\tBeats: $beats\n"; | |
$port->write($beats); | |
if ($send_wifi_beat) { | |
SendWifiBeat($beats) | |
} | |
$bitmask = 0; | |
} | |
elsif ($beatcomplete) { # will this case ever occur? | |
$beats = 0; | |
} | |
} | |
sub ScanDirs { | |
my $topdir = $_[0]; | |
find({ wanted => sub { -d $_ && CreateWatcher($inotify, $File::Find::name) } } , $topdir); | |
print "Scanned $topdir\n"; | |
} | |
sub CreateWatcher { | |
my ($inotify, $dir) = @_; | |
my $watcher = $inotify->watch($dir, IN_CREATE | IN_CLOSE_WRITE | IN_MOVE | IN_DELETE | IN_ACCESS | IN_MODIFY, sub { | |
# added IN_CLOSE_WRITE event to catch events that were slipping through. | |
my $e = shift; | |
my $filename = $e->fullname; | |
if (-d $filename) { # is directory | |
if ($e->IN_CREATE || $e->IN_CLOSE_WRITE) { | |
print "New directory. Adding watch for $filename\n"; | |
CreateWatcher($inotify, $filename); | |
ScanDirs($filename); | |
return; | |
} | |
elsif($e->IN_MOVED_TO) { | |
# dir moved to watched directory | |
print "Renamed directory. Scanning path: $filename\n"; | |
ScanDirs($filename); | |
} | |
#Heartbeat(0); # is this needed? | |
} | |
elsif (-f $filename) { # is a file | |
if (index($filename, $mediaDirs[2]) == 0) { | |
Heartbeat(2); # we have d/l activity | |
} | |
elsif (index($filename, $mediaDirs[3]) == 0) { | |
Heartbeat(4); # we have mythtv activity | |
} | |
else { | |
Heartbeat(1); # we have share activity | |
} | |
} | |
else { # filename is now invalid | |
if ($e->IN_MOVED_FROM || $e->IN_DELETE) { # file/dir moved to new path | |
if ($e->IN_ISDIR) { | |
foreach my $subdir(sort keys %watches) { # put in nice order | |
# recursively remove watches | |
if (index($subdir, $filename) != -1) { | |
print "Deleting watch: $subdir\n"; | |
my $watchtodelete = $watches{$subdir}; | |
$watchtodelete->cancel; | |
delete $watches{$subdir}; | |
} | |
} | |
} | |
} | |
} | |
}); | |
$watches{$dir} = $watcher; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment