Code for a Linux + Arduino CPU load monitor
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

loaduino.pl 2.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use 5.10.0;
  5. use Device::SerialPort;
  6. use POSIX qw(setsid);
  7. use File::Slurp;
  8. use Getopt::Long;
  9. use LWP::UserAgent;
  10. my $remote;
  11. my $refresh_rate = 10;
  12. my $daemon = 0;
  13. my $cpucount = 2; # default to 2 CPUs
  14. my $device = '/dev/ttyUSB0';
  15. my $getopt_result = GetOptions (
  16. "device=s" => \$device, # string
  17. "refresh=i" => \$refresh_rate, # numeric
  18. "remote=s" => \$remote, # string
  19. "daemon" => \$daemon, # flag
  20. "cores=i" => \$cpucount # numeric
  21. );
  22. say "Talking to Arduino on $device";
  23. if ($daemon) {
  24. daemonize();
  25. }
  26. # set a count explicitly - need this for remotes
  27. if ($remote && $cpucount) {
  28. countcpus($cpucount);
  29. }
  30. # connect to the arduino
  31. my $port = Device::SerialPort->new($device)
  32. or die "Couldn't connect to $device";
  33. $port->databits(8);
  34. $port->baudrate(9600);
  35. $port->parity('none');
  36. $port->stopbits(1);
  37. # ^C
  38. $SIG{INT} = "cleanup";
  39. while (1) {
  40. my $degrees = getdegrees();
  41. # pack into a 16 bit int (i think) and send to the arduino
  42. my $count_out = $port->write(pack 's', $degrees)
  43. or die "Unable to write to $device";
  44. say "$degrees degrees, $count_out bytes sent" unless $daemon;
  45. sleep $refresh_rate;
  46. }
  47. sub getdegrees {
  48. my $loadstring;
  49. if ($remote) {
  50. $loadstring = getremoteload($remote);
  51. } else {
  52. $loadstring = read_file('/proc/loadavg');
  53. }
  54. my ($load) = split / /, $loadstring;
  55. say "Load: $load" unless $daemon;
  56. return 1 if $load >= countcpus();
  57. return int(($load / countcpus()) * 180);
  58. }
  59. # sometimes i miss writing a language that's too clever for its own good
  60. { my $count;
  61. sub countcpus {
  62. my ($setcount) = @_;
  63. if ($setcount) {
  64. say "CPUs explicitly set to $setcount" unless $daemon;
  65. $count = $setcount;
  66. }
  67. $count //= grep { /^processor\s+: [0-9]/ } read_file('/proc/cpuinfo');
  68. }
  69. }
  70. sub getremoteload {
  71. my ($remote) = @_;
  72. # Create a user agent object
  73. my $ua = LWP::UserAgent->new;
  74. $ua->agent("loaduino/0.1 ");
  75. # Create a request
  76. my $req = HTTP::Request->new(GET => $remote);
  77. # Pass request to the user agent and get a response back
  78. my $res = $ua->request($req);
  79. # Check the outcome of the response
  80. my $loadstring;
  81. if ($res->is_success) {
  82. $loadstring = $res->content;
  83. } else {
  84. say $res->status_line;
  85. $loadstring = '0.0';
  86. }
  87. say "Load string: $loadstring";
  88. return $loadstring;
  89. }
  90. sub daemonize {
  91. chdir '/';
  92. umask 0;
  93. open STDIN, '/dev/null';
  94. open STDOUT, '>', '/dev/null';
  95. open STDERR, '>', '/dev/null';
  96. defined(my $pid = fork)
  97. or die "Can't fork: $!";
  98. exit if $pid;
  99. setsid
  100. or die "Can't start a new sesssion: $!";
  101. }
  102. sub cleanup {
  103. say "cleaning up";
  104. $port->close() || warn "close failed";
  105. undef $port;
  106. die "murdered!";
  107. }
  108. END {
  109. if (defined $port) {
  110. cleanup();
  111. }
  112. }