#!/usr/bin/perl # hibernates laptop if battery discharging and charge is too low use strict; use warnings "all"; use Fcntl; $0 = 'acpid.pl'; my $debug = 0; sub logger ($) { if ($debug != 0) { my $msg = shift; $msg = localtime() . ' ' . $msg; syswrite STDOUT, $msg; } } sub i3wmstate { my $flag = 0; opendir(P, '/proc') || die 'no /proc found!'; while (readdir(P)) { my $pid = $_; next unless(defined($pid)); next if ($pid eq ''); if (-d "/proc/$pid") { # dir UID == APCID.pl process user owner if ((stat("/proc/$pid"))[4] == int(getpwnam($ENV{'LOGNAME'}))) { next unless(-r "/proc/$pid/cmdline"); open(CMDLINE, "/proc/$pid/cmdline") || die "unable to open /proc/$pid/cmdline"; my $cl = ; close(CMDLINE); if(defined($cl)) { if ((substr($cl, 0, 2) eq 'i3') and (length($cl) <= 4)) { $flag = 1; undef $cl; undef $pid; last; } } undef $cl; } } undef $pid; } return $flag; } my $base = '/sys/class/power_supply/BAT0'; unless(-f "$base/present") { logger("Battery info at /sys/class/BAT0/present not found, quitting.\n"); exit 0; } my $battery_present = 2; my $battery_check = 2; my $charging = 2; while ( sleep(180) ) { # check that battery is in place open(ACPI, "$base/present") or next; my $buf = ''; my $ac = 0; # assume, we're on battery if (read(ACPI, $buf, 1)) { if ($battery_check == 0) { logger("Ability to read from /sys/class/BAT0/present restored\n"); $battery_check = 1; } if ($buf == '0') { if ($battery_present != 0) { logger("We have no battery, skipping charge level polling until it appears\n"); $battery_present = 0; } close ACPI; next; } } else { if ($battery_check != 0) { logger("Unable to read from /sys/class/BAT0/present\n"); $battery_check = 0; } close ACPI; next; } close ACPI; $battery_present = 1; # check status, we have no need to poll battery if it charging/charged unless (-f "$base/status") { logger("Something broken in /sys, unable to find $base/status, quitting\n"); exit 1; } # TODO: file access save state and print on change open(STATUS, "$base/status") or do { logger("Unable to open $base/status\n"); next; }; $buf = ; close STATUS; chomp($buf); if ($buf ne 'Discharging') { if ($charging != 1) { logger("Battery charging.\n"); $charging = 1; } $ac = 1; } else { if ($charging != 0) { logger("Battery discharging.\n"); $charging = 0; } } # read charge state unless (-f "$base/capacity") { logger("Something broken in /sys, unable to find $base/capacity, quitting\n"); exit 1; } # TODO: file access save state and print on change open(CHARGE, "$base/capacity") or do { logger("Unable to open $base/capacity\n"); next; }; read(CHARGE, $buf, 3) or do { logger("Unable to read $base/capacity\n"); next; }; chomp($buf); if (($ac == 0) and ($buf < 10)) { logger("Battery charge is less than 10%, hibernating\n"); `dbus-send --system --print-reply --dest="org.freedesktop.UPower" /org/freedesktop/UPower org.freedesktop.UPower.Hibernate`; } else { logger("Charge is $buf%\n"); if (($ac == 1) and ($buf > 100)) { system ('notify-send', '-u', 'normal', '-t', '3000', 'Battery overcharging'); } } }