1. modificato il metodo di avvio dello script (cazzantonio)
2. gestione batteria hotplug (cazzantonio)
3. aumentata la verbosita' dello script (log + precisi) (io)
4. leggero abbellimento complessivo del codice (io)
Alla fine dopo molte ricerche ho deciso di arrangiarmi usando Perl.
Il problema e' quello di voler spegnere il mio laptop quando, in presenza di una prolungata assenza di alimentazione di rete, anche la batteria arriva verso la fine.
Avevo postato qui:
http://forums.gentoo.org/viewtopic.php? ... i+batteria
http://forums.gentoo.org/viewtopic.php? ... i+batteria
http://forums.gentoo.org/viewtopic.php? ... i+batteria
senza ottenere grande risultati comunque ecco lo script in Perl:
Code: Select all
#!/usr/bin/perl -w
#
# checkbattery.pl
#
# Checks your laptop battery state... if it's too low a nice
# command like `/sbin/poweroff' will be executed.
#
# Copyright (C) 2004 Matteo Guglielmi
#
#
# License:
#
# 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 2 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, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
############################################################################
# #
# DECLARATIONS #
# #
############################################################################
# SOME OF THE FLAGS BELOW WILL BE SET LATER ON BY THIS SCRIPT
my $pname = 'checkbattery.pl';
my $state_file = '/proc/acpi/battery/BAT0/state';
my $shutdown = '/sbin/poweroff';
my $logger = "/usr/bin/logger -t $pname ";
my $capacity_warning = 400;
my $more = 60; # seconds
my $less = 30; # seconds
my $capacity_is = '';
my $state_is = '';
############################################################################
# #
# SUBROUTINES #
# #
############################################################################
############################################################################
# #
# SUB: get_battery_presence #
# #
# DESCRIPTION: Gets battery presence state #
# #
# USAGE: &get_battery_presence(BatteryStateFile) #
# #
# EXAMPLE: &get_battery_presence('/proc/acpi/battery/BAT0/state'); #
# #
# EXTERNAL DATA USED: None #
# #
############################################################################
sub get_battery_presence {
my $read_state = 'not defined';
if (open(STATEFILE, "<$_[0]")) {
while (defined($row = <STATEFILE>)) {
chomp($row);
if ($row =~ m/^present:\s+([a-z]+)$/) {
$read_state = $1;
last;
}
}
close(STATEFILE);
}
return $read_state;
}
############################################################################
# #
# SUB: get_charging_state #
# #
# DESCRIPTION: Gets battery charging state #
# #
# USAGE: &get_charging_state(BatteryStateFile) #
# #
# EXAMPLE: &get_charging_state('/proc/acpi/battery/BAT0/state'); #
# #
# EXTERNAL DATA USED: None #
# #
############################################################################
sub get_charging_state {
my $read_state = 'not defined';
if (open(STATEFILE, "<$_[0]")) {
while (defined($row = <STATEFILE>)) {
chomp($row);
if ($row =~ m/^charging\s+state:\s+([a-z]+)$/) {
$read_state = $1;
last;
}
}
close(STATEFILE);
}
return $read_state;
}
############################################################################
# #
# SUB: get_remaining_capacity #
# #
# DESCRIPTION: Gets battery remaining capacity #
# #
# USAGE: &get_remaining_capacity(BatteryStateFile) #
# #
# EXAMPLE: &get_remaining_capacity('/proc/acpi/battery/BAT0/state'); #
# #
# EXTERNAL DATA USED: None #
# #
############################################################################
sub get_remaining_capacity {
my $read_capacity = 'not defined';
if (open(STATEFILE, "<$_[0]")) {
while (defined($row = <STATEFILE>)) {
chomp($row);
if ($row =~ m/^remaining\s+capacity:\s+(\d+)\s+mAh$/) {
$read_capacity = $1;
last;
}
}
close(STATEFILE);
}
return $read_capacity;
}
############################################################################
# #
# BEGIN MAIN SCRIPT #
# #
############################################################################
while (1) {
$battery_presence = &get_battery_presence($state_file);
if ($battery_presence eq 'yes') {
$state_is = &get_charging_state($state_file);
if ($state_is eq 'charging' || $state_is eq 'charged') {
sleep($more);
} elsif ($state_is eq 'discharging') {
$capacity_is = &get_remaining_capacity($state_file);
if ($capacity_is eq 'not defined') {
system("$logger"."could not open ``$state_file'' or capacity state $capacity_is");
} else {
system("$logger"."battery discharging: capacity ``$capacity_is'' mAh");
if ($capacity_is <= $capacity_warning) {
system("$logger"."battery discharging: capacity too much low");
system("$shutdown");
last;
} else {
sleep($less);
}
}
} else {
system("$logger"."could not open ``$state_file'' or battery state $state_is");
# system("$shutdown"); # --- DECISIONE UN PO DRASTICA --- #
# last;
sleep($less);
}
} elseif ($battery_presence eq 'no') {
system("$logger"."battery not present");
sleep($more);
} else {
system("$logger"."could not open ``$state_file'' or battery presence $battery_presence");
sleep($more);
}
}
############################################################################
# #
# END MAIN SCRIPT #
# #
############################################################################
Code: Select all
# cp ./checkbattery.pl /usr/local/bin
# chmod 744 /usr/local/bin/checkbattery.pl
Code: Select all
# nano -w /etc/conf.d/local.start
Code: Select all
/usr/local/bin/checkbattery.pl & echo $! > /tmp/checkbattery.pid
Code: Select all
# nano -w /etc/conf.d/local.stop
Code: Select all
if [ -f /tmp/checkbattery.pid ]; then
kill -15 `cat /tmp/checkbattery.pid`
rm /tmp/checkbattery.pid
fi
Code: Select all
# /etc/init.d/local restart
Code: Select all
#vim checkbatteryCode: Select all
#!/sbin/runscript
depend() {
need localmount acpid logger
}
start() {
ebegin "Starting checkbattery script"
/scripts/sbin/checkbattery.pl & echo $! > /tmp/checkbattery.pid
eend $? "Failed to start checkbattery script"
[ `ps aux |grep checkbattery.pl|wc -l` -eq 1 ] && rm /tmp/checkbattery.pid
}
stop() {
ebegin "Stopping checkbattery script"
if [ -f /tmp/checkbattery.pid ]; then
kill -15 `cat /tmp/checkbattery.pid`
rm /tmp/checkbattery.pid
fi
}Code: Select all
# rc-update add checkbattery defaultCome funziona:
prima di tutto acpi deve essere installato ovvero dovete avere in /proc/acpi/da/qualche/parte il file relativo allo stato della batteria; il mio state file e':
Code: Select all
[stekkino:~] > cat /proc/acpi/battery/BAT0/state
present: yes
capacity state: ok
charging state: charging
present rate: 29 mA
remaining capacity: 4030 mAh
present voltage: 16848 mV
Se il vostro file sta in una posizione diversa basta modificare il valore di tale variabile nello script.
Nota:
se fate un cat del vostro state file come root dovreste vedere qualcosa di molto simile al mio output.
Questo e' molto importante perche' lo script si basa sul riconoscimento delle due righe che iniziano con ``charging state:'' e ``remaining capacity:''
Lo script non fa altro che aprire lo state file e cercare la riga che comincia con ``charging state:'', a questo punto capisce se l'alimentazione dalla rete e' presente o meno: se e' presente (``charging'') allora il check successivo lo fa dopo un minuto, se non e' presente (``discharging'') allora prosegue ricavando sempre dallo stesso file l'informazine relativa ai MilliApereOra che rimangono (riga ``remaining capacity: ??? mAh'').
Se tale valore e' maggiore della soglia di default pari a 400 (variabile $capacity_warning) allora ripete tutto dall'inizio dopo 15 secondi altrimenti manda un messaggio sul log file /var/log/messages tramite il programma ``logger'' e quindi spegne il pc tramite il comando ``poweroff''.
I due tempi di attesa come il valore di soglia di carica bassa ed i due programmi usati per mandare un log sul file messages e spegnere il pc sono modificabili a piacimento.
Dimenticavo.... chiaramente Perl deve essere presente nel vostro sistema.
Come vedete la soluzione non ha nessuna pretesa di complessita'e miglioramenti sono ben accetti.
Vorrei comunque risolvere ancora i miei dubbi evidenziati nei post indicati all'inizio di tale topic.
PS al commento "DECISIONE UN PO DRASTICA":
questa riga di codice e' un po' pericolosa perche' se per qualche ultra strano motivo con alimentazione di rete inserita si presenta
questo evento in modo stabile... il vostro/mio laptop appeno acceso si spegnera' di conseguenza ancora prima che abbiate il tempo di loggarvi e sistemare la faccenda.
In questo maleaugurato caso bisognerebbe:
- 1 - o entrare con un runlevel che non attivi il servizio di check della batteria ovvero che non esegua il file /etc/init.d/local.start
2 - o avviare il laptop con un CD autoavviante e disabilitare lo scrip di check
3 - o modificare quella "DECISIONE UN PO DRASTICA" fin d'ora
Code: Select all
...
} else {
system("$logger".'battery state not defined');
# system("$shutdown"); # --- DECISIONE UN PO DRASTICA ORA DEL TUTTO INNOQUA --- #
# last;
sleep(30);
}
}






