bin/dragonbat

165 lines
3.4 KiB
Perl
Executable File

#!/usr/bin/perl
use warnings FATAL => 'all';
use strict;
use Data::Dumper;
# turn on autoflush
$| = 1;
sub booleq {
my ($s) = @_;
return sub { return $_[0] eq $s };
}
sub boolne {
my ($s) = @_;
return sub { return $_[0] ne $s };
}
sub numwh {
my ($s) = @_;
my ($n) = $s =~ m/^(.*) Wh$/;
return $n;
}
sub htime {
my ($s) = @_;
if ($s =~ m/^([0-9.]+) hours$/) {
return int($1 * 60);
} elsif ($s =~ m/^([0-9.]+) minutes$/) {
return int($1);
} else {
die "unknown time: $s";
}
}
sub stime {
my ($n) = @_;
my $h = $n / 60;
my $m = $n % 60;
return sprintf("%02d:%02d", $h, $m);
}
sub perc {
my ($n, $d) = @_;
return sprintf("%.1f%%", $n * 100 / $d);
}
sub charge_time {
my ($data) = @_;
return "--:--" if $data->{full} || $data->{tcharge} == 0;
return stime($data->{tcharge});
}
sub drain_time {
my ($data) = @_;
return "--:--" if $data->{tdrain} == 0;
return stime($data->{tdrain});
}
sub main {
if (@ARGV) {
my $t = $ARGV[0];
# require a positive number of seconds (e.g. 2, 4.5, 0.2, ...)
unless ($t =~ m/^([1-9][0-9]*(\.[0-9]+)?|0\.[0-9]*[1-9][0-9]*)$/) {
print "usage: $0 [POLL-SECS]\n";
exit(1);
}
do {
run();
select(undef, undef, undef, $t);
} while (999);
} else {
run();
}
}
sub run {
my $data = init();
#print Dumper($data) . "\n";
display1($data, 5);
}
sub mac_meta {
return (
"ExternalConnected" => [["connected", booleq("Yes")]],
"AvgTimeToEmpty" => [["tdrain", \&int]],
"AvgTimeToFull" => [["tcharge", \&int]],
"MaxCapacity" => [["max", \&int]],
"CurrentCapacity" => [["cur", \&int]],
"FullyCharged" => [["full", booleq("Yes")]],
"IsCharging" => [["charging", booleq("Yes")]],
);
}
sub linux_meta {
return (
"energy" => [["cur", \&numwh]],
"energy-full" => [["max", \&numwh]],
"time to empty" => [["tdrain", \&htime]],
"time to full" => [["tcharge", \&htime]],
"state" => [
["connected", boolne("discharging")],
["full", booleq("fully-charged")],
],
)
}
my $is_linux = $^O eq "linux";
my %meta = $is_linux ? linux_meta() : mac_meta();
sub mac_cmd {
return "ioreg -rc AppleSmartBattery";
}
sub mac_re {
return qr/^ *"(\w+)" = (.+)$/;
}
sub linux_cmd {
return "upower -i `upower -e | grep battery`";
}
sub linux_re {
return qr/^ *([^:]+): +(.+)$/;
}
sub init {
my $data = {};
$data->{tcharge} = 0;
my $cmd = $is_linux ? linux_cmd() : mac_cmd();
open(my $fh, "-|", $cmd);
my $re = $is_linux ? linux_re() : mac_re();
while (my $line = <$fh>) {
my ($key, $val) = $line =~ m/$re/;
next unless $key && $val;
my $r = $meta{$key};
next unless $r;
for my $p (@$r) {
$data->{$p->[0]} = $p->[1]->($val);
}
}
return $data;
}
sub icon {
my ($data) = @_;
return $data->{full} ? "☀" : "⚡" if $data->{connected};
return $data->{tdrain} < 30 ? "⚠" : "⌸";
}
sub display1 {
my ($data, $n) = @_;
my $c = $data->{connected};
my $p = perc($data->{cur}, $data->{max});
my $icon = icon($data);
my $f = $c ? \&charge_time : \&drain_time;
my $t = $f->($data);
printf("$icon %s (%s)\n", $t, $p);
}
main();