# [HOWTO] Come spegnere il tuo laptop se la batteria e' finita

## quantumwire

[EDIT 12/12/05]

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:

https://forums.gentoo.org/viewtopic.php?t=174846&highlight=acpi+batteria

https://forums.gentoo.org/viewtopic.php?t=158030&highlight=acpi+batteria

https://forums.gentoo.org/viewtopic.php?t=137711&highlight=acpi+batteria

senza ottenere grande risultati comunque ecco lo script in Perl:

```

#!/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                            #

#                                                                          #

############################################################################

```

Per ``installarlo'' basta copiarlo dove si vuole tipo:

```

# cp ./checkbattery.pl /usr/local/bin

# chmod 744 /usr/local/bin/checkbattery.pl

```

e poi editare i seguenti file:

```

# nano -w /etc/conf.d/local.start

```

aggiungendo la linea:

```

/usr/local/bin/checkbattery.pl & echo $! > /tmp/checkbattery.pid

```

```

# nano -w /etc/conf.d/local.stop

```

aggiungendo la linea:

```

if [ -f /tmp/checkbattery.pid ]; then

  kill -15 `cat /tmp/checkbattery.pid`

  rm /tmp/checkbattery.pid

fi

```

ed in fine:

```

# /etc/init.d/local restart

```

Volendo e' possibile anche lanciarlo utilizzando il seguente script di init:

```
#vim checkbattery
```

```
#!/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

}
```

ricordandosi poi di dare un bel:

```
# rc-update add checkbattery default
```

alla fine.

Come 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':

```

[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

```

il quale poi e' uno dei settaggi di default dello script associato alla variabile $state_file.

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   :Wink:  

Nel caso 3 si potrebbero cosi commentare le ultime due righe di codice come segue:

```

...

  } else {

  system("$logger".'battery state not defined');

# system("$shutdown");  # --- DECISIONE UN PO DRASTICA ORA DEL TUTTO INNOQUA --- #

# last;

  sleep(30);

  }

}

```

In questo caso vera' eseguito solo il "logger" per la notifica dell'evento ultrastrano oltre ad bel sleep di 30 secondi per non entrare in un loop mostruoso che ciuccerebbe tutta la vostra CPU (oltre a riempirvi il file di log!!!! e quindi l'HD alla velocita' del loop!!!!) nel caso in cui l'evento ultrastrano diventasse permanente.Last edited by quantumwire on Mon Dec 12, 2005 12:09 pm; edited 15 times in total

----------

## SilveRo

Complimenti per il tuo script, mi e' stato molto utile. =)

Lo sto usando pure io, ma prima ho dovuto fare delle modifiche, perche': 

1) la mia batteria quando e' carica come stato mi dice unknown.

2) la capacita' della mia batteria e' espressa in mWh.

Ecco le modifiche che ho fatto in get_remaining_capacity:

```

    if ($row =~ m/^remaining\s+capacity:\s+(\d+)\s+mWh$/) {

```

ed ecco il mio main:

```

while (1) {

  $state = &get_charging_state($state_file);

  if ($state eq 'discharging') {

    $capacity = &get_remaining_capacity($state_file);

    system("$logger"."battery discharging: capacity ``$capacity'' mWh");

    if ($capacity <= $capacity_warning) {

      system("$logger"."battery discharging: capacity too much low");

      system("$shutdown");

      last;

    } else {

      sleep(15);

    }

  } else {

      sleep(60);

  }

}

```

Se qualcuno vuole usare le mie modifiche, si ricordi di cambiare $capacity_warning, e impostarlo al (per esempio) 4% della capacita' in mWh.

Inoltre, come comando di shutdown ho preferito mettere "shutdown -h now".

=)

----------

## federico

Su Sideralis da mesi erano presenti programmi destinati a tale scopo... (eventualmente utilizzabili anche tramite interfaccia grafica!)

http://www.sideralis.net

Federico

----------

## fedeliallalinea

Aggiunto nei post utilissimi

----------

## Cagnulein

verramente ottimo lo stile di commento che hai addottato per le funzioni, penso che lo utilizzerò anche io magari usando un template  :Smile: 

----------

## quantumwire

 *federico wrote:*   

> Su Sideralis da mesi erano presenti programmi destinati a tale scopo... (eventualmente utilizzabili anche tramite interfaccia grafica!)
> 
> Federico

 

Buono a sapersi... appena ho un po' di tempo spulcio il sito.

 *fedeliallalinea wrote:*   

> 
> 
> Aggiunto nei post utilissimi
> 
> 

 

Grazie ragazzi... mi sento emozionato a palla... e' un piacere sapere che puo' servire.

Thanks.

----------

## SilveRo

Mi sembrava strano che in due mesi nessuno avesse risposto al tuo thread, considerato anche quanto e' utile il tuo script.... Ero certo che ti sarebbe piaciuto leggere qualche conferma che sia servito a qualcuno  =P.

Se non lo hai gia' fatto, dovresti postarlo anche nella sezione Documentation, Tips and Tricks, in inglese, perche' ci sono tanti utenti di Gentoo che l'italiano non lo capiscono  =)

----------

## quantumwire

Grazie.

Ho appena modificato leggermente il codice e aggiunto un paio di note  relative a possibili malfunzionamenti che possono derivare dall'uso dello stesso.

Ciao e grazie ancora.

----------

## SilveRo

 *quantumwire wrote:*   

> Grazie.
> 
> Ho appena modificato leggermente il codice e aggiunto un paio di note  relative a possibili malfunzionamenti che possono derivare dall'uso dello stesso.
> 
> Ciao e grazie ancora.

 

ghehehe, makke' dici, grazie a TE che hai fatto sto script  =)

----------

## akiross

Salve!

Bello lo script, peccato che non mi sia proprio utile...

Ovviamente ai mac non ci pensa nessuno...  :Very Happy: 

Ecco, ho fatto giusto 2 righe di BASH, che restituiscono lo stato della batteria (AC se alimentato, un numero se a batteria).

```

#!/bin/bash

### SETTINGS ###

# Files Used

PWR_FILE='/proc/pmu/info'

BAT_FILE='/proc/pmu/battery_0'

### GETTING INFO ##

USING_AC_PWR=`grep 'AC Power' $PWR_FILE | tr -s ' ' | cut -d ' ' -f4`

if [[ $USING_AC_PWR = '1' ]]; then

   echo "AC"

   exit

fi

MAX_CHARGE=`grep '^max_charge' $BAT_FILE | tr -s ' ' | cut -d ' ' -f3`

ACT_CHARGE=`grep '^charge' $BAT_FILE | tr -s ' ' | cut -d ' ' -f3`

#   echo "Max charge: $MAX_CHARGE"

#   echo "Act charge: $ACT_CHARGE"

PERCENT_CHARGE=$(($ACT_CHARGE * 100 / $MAX_CHARGE))

#   echo "Actual charge: $PERCENT_CHARGE%"

echo $PERCENT_CHARGE

```

Potete integrarlo facilmente a questo script se avete un mac, anche se comunque (non per svalutare il lavoro del nostro quantumwire) esistono plugin per gkrellm per monitorare la batteria ed eventualmente eseguire un comando quando raggiunge un certo stato.

Ciauz

----------

## quantumwire

 *akiross wrote:*   

> ...anche se comunque esistono plugin per gkrellm per monitorare la batteria ed eventualmente eseguire un comando quando raggiunge un certo stato.
> 
> 

 

Credo gkrellm funzioni solo in presenza di X.

----------

## Cazzantonio

Visto che me lo sono ricordato posto le mie modifiche a questo script.

Nel mio caso la batteria, quando è carica, riporta lo stato "charged", pertanto lo script me lo identificava come "battery state not defined" ed entrava nel loop dei reboot...   :Rolling Eyes: 

ho aggiunto un paio di righe alla funzione main per ovviare al problema... ecco il mio main:

```
while (1) {

  $state_is = &get_charging_state($state_file);

  if ($state_is eq 'charging') {

    sleep($more);

  } elsif ($state_is eq 'charged') {

    sleep($more);

  } elsif ($state_is eq 'discharging') {

    $capacity_is = &get_remaining_capacity($state_file);

    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".'battery state not defined');

#    system("$shutdown");  # --- DECISIONE UN PO DRASTICA --- #

#    last;

    sleep(30);

  }

}
```

Inoltre invece di mettere il servizio in local.start ho trovato più comodo creare uno script di init apposito. In questo modo ho creato un'altro runlevel (copia del mio di default tranne questo script) in modo da avviare questo nel caso volessi avviare il notebook ignorando il check della batteria.

Ecco lo script di init:

```
 #!/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

}
```

[EDIT] aggiunta allo start una riga per il controllo del pid

----------

## quantumwire

 *Cazzantonio wrote:*   

> Visto che me lo sono ricordato posto le mie modifiche a questo script.

 

Hey dude! Belle modifiche!

Le apportero' anch'io super-presto allo script!

----------

## .:deadhead:.

Mi raccomanda quantumwire, poi aggiorna anche questo 3d  :Very Happy: 

----------

## quantumwire

 *.:deadhead:. wrote:*   

> Mi raccomanda quantumwire, poi aggiorna anche questo 3d 

 

Cioe' il mio post in testa?

----------

## Cazzantonio

Siccome non mi intendo di perl faccio questa domanda...

E' possibile aggiungere due righe per fare in modo che dorma (che so... 60 secondi) nel caso la riga "present" dia "no"? (ovvero la batteria è disinserita)

Le minuscole modifiche fatte prima le ho fatte ad occhio pur non conoscendo il perl... questa mi risulta più ostica...

Pensavo di bypassare tutto questo mettendo un ciclo nel bash script che lancia checkbattery... tuttavia risulta più elegante ed efficiente se tale funzione fosse integrata nello script   :Wink: 

----------

## quantumwire

 *Cazzantonio wrote:*   

> E' possibile aggiungere due righe per fare in modo che dorma (che so... 60 secondi) nel caso la riga "present" dia "no"? (ovvero la batteria è disinserita)

 

Ottima domanda... supponendo che la batteria non sia un device hotplug (credo sia rischioso provare a toglierla o inserirla durante il normale funzionamento del laptop) ho fatto le seguenti modifiche:

1. prima di tutto introduciamo queste ulteriori subroutines:

```
############################################################################

#                                                                          #

# SUB: ABORT(ExitNumber)                                                   #

#                                                                          #

# DESCRIPTION: Exits script ubnormally.                                    #

#                                                                          #

# USAGE: &abort(ExitNumber)                                                #

#                                                                          #

# EXAMPLE: &abort(5);                                                      #

#                                                                          #

# EXTERNAL DATA USED: None                                                 #

#                                                                          #

############################################################################

sub abort {

  exit($_[0]);

}

############################################################################

#                                                                          #

# 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 = 'no';

  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;

}
```

2. nella parte dichiarativa aggiungiamo la variabile battery_presence:

```
############################################################################

#                                                                          #

# 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             = 15;   # seconds

my $capacity_is      = '';

my $state_is         = '';

my $battery_presence = '';
```

3. ed in fine modifichiamo il main come segue:

```

$battery_presence = &get_battery_presence($state_file);

if ($battery_presence eq 'yes') {

  while (1) {

    $state_is = &get_charging_state($state_file);

    if ($state_is eq 'charging') {

      sleep($more);

    } elsif ($state_is eq 'charged') {

      sleep($more);

    } elsif ($state_is eq 'discharging') {

      $capacity_is = &get_remaining_capacity($state_file);

      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".'battery state not defined');

#      system("$shutdown");  # --- DECISIONE UN PO DRASTICA --- #

#      last;

      sleep(30);

    }

  }

} else {

  system("$logger"."battery not present: ``$pname'' unloaded.);

  &abort(1);

}
```

Che cosa fa di diverso checkbattery.pl con questo codice modificato?

Se il file /proc/acpi/battery/BAT0/state e' assente (acpi non presente nel kernel!) oppure e' presente ma il laptop e' sprovvisto della batteria allora checkbattery.pl si autokillera' ritornando come valore d'errore al tuo script di init il valore 1 (per intenderci: echo $? produrra' 1).

Quello che dovresti fare ora e' quindi modificare il tuo script di init in modo tale da gestire questa eventualita' ovvero... oltre a printare sullo schermo "Failed..." gli dovresti anche fare rimuovere il file temporaneo contenente il pid nella directory /tmp.

A proposito ho pero' un po di dubbi in quanto il $? che tu stai usando dovrebbe essere quello complessivo del comando /scripts/sbin/checkbattery.pl & echo $! > /tmp/checkbattery.pid il quale, per definizione, dovrebbe sempre essere eseguito correttamente indipendentemente dal valore eventualmente ritornato dal checkbattery.pl!!! Il tuo $? dovrebbe essere relativo alla domanda: "Sei riuscito a scrivere il pid del checkbattery.pl nel file temporaneo?... tant'e' vero che il checkbattery.pl deve essere lanciato in parallelo per fare in modo che il tuo script di init termini... come fare allora????

Si potrebbe fare in modo che... tu mi mandi in parallelo ma il controllo del "se c'e' la batteria" lo fai leggendo un file temporaneo che io ti scrivo nella directory tmp prima di autokillarmi... ma forse esiste qualcosa di piu' elegante... qualche idea???

NOTA: come si puo vedere dal codice, il controllo della presenza/assenza della batteria viene eseguito una sola volta ovvero in fase di avvio dello stesso script. Tale scelta corrisponde all'assunzione di una politica per la batteria del laptop di tipo non hotplug.Last edited by quantumwire on Sun Dec 11, 2005 4:38 pm; edited 2 times in total

----------

## Cazzantonio

Per le batterie hotplug (devo dire che non ho mai sentito parlare di una batteria non hotplug...) potrebbe andare bene questo main?

```
while (1) {

  $state_is = &get_charging_state($state_file);

  $battery_presence = &get_battery_presence($state_file);

  

  if ($battery_presence eq 'yes') {

    if ($state_is eq 'charging') {

    sleep($more);

    } elsif ($state_is eq 'charged') {

    sleep($more);

    } elsif ($state_is eq 'discharging') {

      $capacity_is = &get_remaining_capacity($state_file);

      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".'battery state not defined');

#      system("$shutdown");  # --- DECISIONE UN PO DRASTICA --- #

#      last;

      sleep(30);

    }

  } else {

    system("$logger"."battery not present");

    sleep(60);

  }

}

```

Attendo conferma visto che ti ripeto che non conosco il perl e vado un po' ad occhio   :Wink: 

In questo caso non dovrebbe essere nemmeno necessaria la funzione "abort" e si risolve anche il problema del pid!   :Wink:  (visto che il programma non viene più abortito...

Per la soluzione non hotplug (anche se ti ripeto che mi pare così improbabile.... hai un portatile con la batteria non hotplug per caso?) si potrebbe fare un controllo accessorio (tipo "ps aux |grep checkbattery.pl") per vedere se è effettivamente attivo e cancellare il pid in caso contrario...

Ovvero cambiare lo start dello script di init in qualcosa di simile:

```
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

}
```

----------

## quantumwire

 *Cazzantonio wrote:*   

> 
> 
> ```
> while (1) {
> 
> ...

 

E' giusto... ma io lo modificherei cosi:

```
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);

      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".'battery state not defined');

#      system("$shutdown");  # --- DECISIONE UN PO DRASTICA --- #

#      last;

      sleep($less);

    }

  } else {

    system("$logger".'battery not present');

    sleep($more);

  }

}
```

Per quanto riguarda il tuo init script... perfetta l'aggiunta! Io la lascerei che male non fa!

/EDIT

Forse invece c'e' un problemino... e se capitasse che mi autokillo dopo che tu hai fatto il controllo del pid (checkbattery.pl un po' lento nell'aprire i files etc....)???

PS: Non ho mai provato a rimuovere la batteria del mio laptop mantre sta funzionando... a parte che dovrei quasi smontarlo per toglierla comunque se dici che la tua e' hotplug, lo script cosi' modificato dovrebbe anfare.

Fammi sapere se funziona... in tal caso modifichero' anche quello in testa riportando tutte le modifiche introdotte.

----------

## Cazzantonio

Si la tua versione è decisamente più carina   :Wink: 

A me lo script funziona egregiamente... del resto la batteria la tolgo e la metto a seconda delle esigente (di solito se attacco la spina stacco la batteria, almeno che non voglia ricaricarla). Prima mi si riempivano i log di "battery state not defined" etc... ora posso eliminare il logging (commentando la riga) quando ho la spina attaccata  :Wink: 

Il tuo dubbio sul controllo per il pid non so quanto possa essere fondato... in fondo non cambia niente che rimanga il file del pid in /tmp o meno mi pare... e poi penso che ps aux ti dica in tempo reale i programmi che girano... se checkbattery è partito nella linea precedente dello script dovrebbe bastare...

P.S. peccato che avevo postato la riga dello script di init senza mettere il pezzo più importante...   :Rolling Eyes: 

L'ho corretta e ora funziona   :Wink: 

----------

## Dr.Dran

Scusa se mi intrometto, ma mi chiedevo se avevi provato anche il pacchetto laptop-mode-tools; mi interessa anche perchè mi deve arrivare un nuovo portatilino tutto fiammante ex-novo e mi piacerebbe partizionarlo con xfs e fare delle prove... magari lo si può integrare con questo utile script.

Comunque complimenti un bel lavoro   :Very Happy: 

----------

## quantumwire

 *DranXXX wrote:*   

> Scusa se mi intrometto, ma mi chiedevo se avevi provato anche il pacchetto laptop-mode-tools; mi interessa anche perchè mi deve arrivare un nuovo portatilino tutto fiammante ex-novo e mi piacerebbe partizionarlo con xfs e fare delle prove... magari lo si può integrare con questo utile script.
> 
> Comunque complimenti un bel lavoro  

 

Quel pacchetto non l'ho mai utilizzato sul mio laptop... provero' a dargli un'occhiata e ti faccio sapere.

----------

## codadilupo

 *DranXXX wrote:*   

> Scusa se mi intrometto, ma mi chiedevo se avevi provato anche il pacchetto laptop-mode-tools; mi interessa anche perchè mi deve arrivare un nuovo portatilino tutto fiammante ex-novo e mi piacerebbe partizionarlo con xfs e fare delle prove... magari lo si può integrare con questo utile script.
> 
> Comunque complimenti un bel lavoro  

 

ah, quindi é andata bene  :Wink: 

Coda

----------

## Dr.Dran

@CodadiLupo

Si, oggi mi è arrivata l'e-mail per la conferma di tutto e mi chiedono addirittura una Foto e 2 righe per poi pubblicarle nella pagina per l'annucio della premiazione:

http://www.via.com.tw/en/products/notebook/winner_mascot_naming2.jsp

 :Very Happy: 

@quantumwire

Grazie mille io per il momento non posso essere di aiuto fino a che non ho la materia prima   :Wink: 

----------

## neryo

 *quantumwire wrote:*   

> 
> 
> 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.
> 
> 

 

fichissimo! complimenti..   :Wink: 

----------

## lucapost

Ne ho fatto uno anche io utilizzando le info acpi.

Quando la batteria arriva al 3%, incomincia un fastidioso /root/sound/beep.wav e dopo circa 1 minuto spegne il notebook.

L'ho salvato in /root/script/battery:

```
#!/bin/bash                                                                                      

WARNING=3

TMP=60

FULL=`cat /proc/acpi/battery/BAT0/info |awk '/full\ capacity:/ { print $4 }'`

while true ; do

PRESENT=`cat /proc/acpi/battery/BAT0/state |awk '/present:/ { print $2}'`

STATE=`cat /proc/acpi/battery/BAT0/state |awk '/charging\ state:/ { print $3 }'`

REMAINING=`cat /proc/acpi/battery/BAT0/state |awk '/remaining\ capacity:/ { print $3 }'`

  sleep 5

  

  if [ "$PRESENT" = "yes" ] ; then

     case $STATE in

       charged)

             TMP=60 ;;

       charging)

             TMP=60 ;;

       discharging)

         CHARGE=$((${REMAINING}*100/${FULL}))

         if [ "$CHARGE" -le "$WARNING" ] ; then

             let "TMP -=5"

             aplay /root/sound/beep.wav &>/dev/null

           if [ "$TMP" -le 1 ] ; then 

             /sbin/shutdown -h now

           fi

         else

             TMP=60

         fi

       ;;

     esac

  fi

done
```

La cosa carina è che anche dopo il beep, se si attacca l'alimentazione ac entro un minuto si salva la sessione.

Questo sopra può andare bene per tutti, ma ne ho fatta una versione, leggermente più complessa per integrarlo con dwm, se vi interessa lo potete trovare in questo post 4021898

EDIT: dimenticavo, nello script originale in perl, l'ultimo elseif è un elsif!

----------

## Cazzantonio

quindi questo script parte dal presupposto che il pc ci metta almeno 60 secondi  a passare da batteria=3 a batteria=1 ...

----------

## lucapost

non ho capito bene....

Comunque, lo script suppone che la batteria per passare dal 3% al 1% ci metta più di 1minuto naturalmente.

Secondo me è una buona stima, infatti facendo due conti, supponendo che la batteria si scarichi linearmente ad abbia un'autonomia di almeno 2 ore, il 2% percento di 2 ore è più di 2 minuti, quindi il mio minuto è più che "abbondante"...

Casomai si può sempre aumentare la percentuale di WARNING.

Mandi.

----------

## table

Ciao,

mi riallaccio a questo argomento.

Ho notato che il mio laptop si spegne bruscamente senza fare nulla quando la batteria va a 0. Quindi stavo pensando si usare questo script.

Il problema però è che il percorso della batteria sotto proc non esiste:

```
stealth / # ls -l /proc/acpi/

total 0

dr-xr-xr-x 4 root root 0 Mar  6 10:42 button

dr-xr-xr-x 3 root root 0 Mar  6 10:42 embedded_controller

dr-xr-xr-x 2 root root 0 Mar  6 10:42 power_resource

dr-xr-xr-x 4 root root 0 Mar  6 10:42 processor

dr-xr-xr-x 2 root root 0 Mar  6 10:42 thermal_zone

-rw-r--r-- 1 root root 0 Mar  6 10:42 wakeup

```

nel kernel ho abilitato in built.in tutti i moduli per i quali ho bisogno di gestire l'ACPI:

```

--- ACPI (Advanced Configuration and Power Interface) Support

 [ ]   Deprecated /proc/acpi files

 [ ]   Deprecated power /proc/acpi directories

 [*]   Future power /sys interface

 [ ]   Deprecated /proc/acpi/event support

 <*>   AC Adapter

 <*>   Battery

 <*>   Button

 <*>   Fan

  -*-   Dock

 < >     Removable Drive Bay (EXPERIMENTAL)

 <*>   Processor

 <*>     Thermal Zone

 -*-   ACPI0004,PNP0A05 and PNP0A06 Container Driver (EXPERIMENTAL)

 <*>   Smart Battery System

```

l'output di dmesg invece non mostra problemi di riconoscimento della batteria:

```
stealth linux # dmesg | grep -e "BAT"

[    0.346953] ACPI: Battery Slot [BAT1] (battery present)

```

 :Rolling Eyes: 

----------

## Scen

 *table wrote:*   

> Il problema però è che il percorso della batteria sotto proc non esiste:
> 
> ```
> stealth / # ls -l /proc/acpi/
> 
> ...

 

Devi abilitare anche le voci "Deprecated /proc/acpi ecc. ecc.", per cui:

```

--- ACPI (Advanced Configuration and Power Interface) Support

 [*]   Deprecated /proc/acpi files

 [*]   Deprecated power /proc/acpi directories

 [*]   Future power /sys interface

 [*]   Deprecated /proc/acpi/event support

 <*>   AC Adapter

 <*>   Battery

 <*>   Button

 <*>   Fan

  -*-   Dock

 < >     Removable Drive Bay (EXPERIMENTAL)

 <*>   Processor

 <*>     Thermal Zone

 -*-   ACPI0004,PNP0A05 and PNP0A06 Container Driver (EXPERIMENTAL)

 <*>   Smart Battery System

```

----------

## table

 *Scen wrote:*   

> 
> 
> Devi abilitare anche le voci "Deprecated /proc/acpi ecc. ecc.", per cui: 
> 
> 

 

hai ragione, grazie   :Wink: 

----------

## lucapost

se ti riferisci al mio script, nei mesi ho raggiunto anche queste modifiche:

```
      FULL=`cat /sys/class/power_supply/BAT0/charge_full' 

      PRESENT=`cat /sys/class/power_supply/BAT0/present`

      CHARGE=`cat /sys/class/power_supply/BAT0/charge_now`

      STATUS=`cat /sys/class/power_supply/BAT0/status`
```

e senza moduli deprecati.

/EDIT:

da qualche mese gestisco lo spegnimento del laptop a batteria scarica direttamente tramite l'acpi:

```
#> cat /etc/acpi/events/hotkey 

event=.*

action=/etc/acpi/hotkey.sh %e
```

```

#> grep -vE '(^[[:space:]]*($|(#|!|;|//)))' /etc/acpi/hotkey.sh

ac_offline () {

        CHARGE=`cat /sys/class/power_supply/BAT0/charge_now`

        FULL=`cat /sys/class/power_supply/BAT0/charge_full`

        AC=`cat /sys/class/power_supply/AC0/online`

        PERC=5

        TIME=55

        if test "$AC" != "1" && test "$((${CHARGE}*100/${FULL}))" -le "$PERC";then

            sleep $TIME

          if test "$AC" != "1";then

            /sbin/halt

          fi

        fi

}

[ "$1:$2" = hotkey:ATKD ] && case "$3" in

        00000057) ac_offline ;;

esac
```

funge solamente quando serve!   :Wink: 

----------

