Comment faire dormir mon ordinateur portable lorsqu'il atteint un certain seuil de batterie faible?

24

J'utilise Ubuntu, mais j'ai i3 comme gestionnaire de fenêtres au lieu d'un environnement de bureau.

Lorsque ma batterie atteint 0%, l'ordinateur s'arrête brusquement, sans avertissement ni rien.

Y a-t-il un script ou une configuration simple que je peux mettre en place pour qu'il se mette en veille, disons 4% de batterie?

o_o_o--
la source

Réponses:

12

Voici un petit script qui vérifie le niveau de batterie et appelle une commande personnalisée, ici pm-hibernate, au cas où le niveau de batterie serait inférieur à un certain seuil.

#!/bin/sh

###########################################################################
#
# Usage: system-low-battery
#
# Checks if the battery level is low. If “low_threshold” is exceeded
# a system notification is displayed, if “critical_threshold” is exceeded
# a popup window is displayed as well. If “OK” is pressed, the system
# shuts down after “timeout” seconds. If “Cancel” is pressed the script
# does nothing.
#
# This script is supposed to be called from a cron job.
#
###########################################################################

# This is required because the script is invoked by cron. Dbus information
# is stored in a file by the following script when a user logs in. Connect
# it to your autostart mechanism of choice.
#
# #!/bin/sh
# touch $HOME/.dbus/Xdbus
# chmod 600 $HOME/.dbus/Xdbus
# env | grep DBUS_SESSION_BUS_ADDRESS > $HOME/.dbus/Xdbus
# echo 'export DBUS_SESSION_BUS_ADDRESS' >> $HOME/.dbus/Xdbus
# exit 0
#
if [ -r ~/.dbus/Xdbus ]; then
  . ~/.dbus/Xdbus
fi

low_threshold=10
critical_threshold=4
timeout=59
shutdown_cmd='/usr/sbin/pm-hibernate'

level=$(cat /sys/devices/platform/smapi/BAT0/remaining_percent)
state=$(cat /sys/devices/platform/smapi/BAT0/state)

if [ x"$state" != x'discharging' ]; then
  exit 0
fi

do_shutdown() {
  sleep $timeout && kill $zenity_pid 2>/dev/null

  if [ x"$state" != x'discharging' ]; then
    exit 0
  else
    $shutdown_cmd
  fi
}

if [ "$level" -gt $critical_threshold ] && [ "$level" -lt $low_threshold ]; then
  notify-send "Battery level is low: $level%"
fi

if [ "$level" -lt $critical_threshold ]; then

  notify-send -u critical -t 20000 "Battery level is low: $level%" \
    'The system is going to shut down in 1 minute.'

  DISPLAY=:0 zenity --question --ok-label 'OK' --cancel-label 'Cancel' \
    --text "Battery level is low: $level%.\n\n The system is going to shut down in 1 minute." &
  zenity_pid=$!

  do_shutdown &
  shutdown_pid=$!

  trap 'kill $shutdown_pid' 1

  if ! wait $zenity_pid; then
    kill $shutdown_pid 2>/dev/null
  fi

fi

exit 0

C'est un script très simple, mais je pense que vous avez l'idée et pouvez facilement l'adapter à vos besoins. Le chemin d'accès au niveau de la batterie peut être différent sur votre système. Un peu plus portable serait probablement d'utiliser quelque chose comme acpi | cut -f2 -d,pour obtenir le niveau de batterie. Ce script peut être planifié par cron pour s'exécuter toutes les minutes. Modifiez votre crontab avec crontab -eet ajoutez le script:

*/1 * * * * /home/me/usr/bin/low-battery-shutdown

Une autre solution serait d'installer un environnement de bureau comme Gnome ou Xfce (et de changer votre gestionnaire de fenêtres en i3). Les deux environnements destop mentionnés comportent des démons de gestion de l'alimentation qui se chargent d'éteindre l'ordinateur. Mais je suppose que vous ne les utilisez pas délibérément et que vous recherchez une solution plus minimaliste.

Marco
la source
Hm, j'ai essayé de courir sleepd -b 40et rien ne s'est passé après la barre des 40%. J'ai aussi essayé sudo sleepd -b 40 -s pm-suspendet rien ne se passe ...
o_o_o--
@NoamGagliardi Confirmé, cela ne fonctionne pas non plus ici. De plus, le paquet semble non entretenu. J'essaie si je peux trouver une meilleure alternative et mettre à jour ma réponse, sinon je vais la supprimer.
Marco
(TIL " cut".) Le script fonctionne! J'ai acpi | cut -f2 -d, | cut -f1 d%- je vais lire sur cron pour le faire fonctionner seul. Merci!
o_o_o--
Je n'ai pas d' /sys/devices/platform/smapi/annuaire. Où puis-je trouver le pourcentage restant de la batterie? J'utilise un noyau personnalisé 3.10
Martin Vegter
2
@MartinVegter Cela dépend de votre matériel, vous pouvez essayer /sys/class/power_supply/BAT0/capacity. Sinon, utilisez la acpicommande.
Marco
6

Au lieu de pirater vos propres scripts et si vous utilisez Ubuntu comme le suggère la balise, vous pouvez simplement installer le package upower. Il devrait être disponible sur tous les dérivés Debian, y compris Ubuntu. Par défaut, il est livré avec une configuration dans /etc/UPower/UPower.conflaquelle active le sommeil hybride une fois que le niveau de la batterie atteint des valeurs critiques. La valeur par défaut pour le niveau critique est de 2%.

Pour les utilisateurs d'autres distributions, les entrées pertinentes pour /etc/UPower/UPower.confsont:

PercentageAction=2
CriticalPowerAction=HybridSleep

Vous pouvez également utiliser TimeActionavec UsePercentageForPolicy=falsepour laisser l'action être exécutée une fois qu'il ne reste que le temps spécifié:

TimeAction=120

Les valeurs valides pour CriticalPowerActionsont PowerOff, Hibernateet HybridSleep. Si HybridSleep est défini mais n'est pas disponible, Hibernate sera utilisé. Si Hibernate est défini mais n'est pas disponible, PowerOff sera utilisé.

L'avantage de HybridSleep est qu'en plus d'écrire de la mémoire dans votre zone de swap, il suspend ensuite le système. La suspension consommera toujours de la batterie, mais si vous revenez avant que la batterie ne soit épuisée, vous pouvez reprendre beaucoup plus rapidement à partir d'un système suspendu que d'un système en veille prolongée. Dans le cas où la batterie s'épuise avant de revenir à une prise de courant, vous pouvez reprendre le système de l'hibernation une fois que vous avez de nouveau l'alimentation.

josch
la source
Remarque: Je pense que HybridSleepnécessite d'avoir un espace de swap.
2
@cipricus qui est correct mais upower choisira gracieusement d'arrêter la machine à la place si elle ne peut pas hiberner.
josch
2

La réponse actuellement acceptée est excellente, mais un peu dépassée pour Ubuntu 16.04:

  • Les commandes pour obtenir l'état de la batterie ont changé.
  • Les variables d'environnement requises pour notifier-envoyer au travail ont changé .
  • Le script qui y est donné ne fonctionne plus depuis l'utilisateur cron car hibernate nécessite root.
  • systemctl hibernateest préféré à pm-hibernate.

Donc, ici est l'utilisation I script:

#!/usr/bin/env bash

# Notifies the user if the battery is low.
# Executes some command (like hibernate) on critical battery.
# This script is supposed to be called from a cron job.
# If you change this script's name/path, don't forget to update it in crontab !!

level=$(cat /sys/class/power_supply/BAT1/capacity)
status=$(cat /sys/class/power_supply/BAT1/status)

# Exit if not discharging
if [ "${status}" != "Discharging" ]; then
  exit 0
fi


# Source the environment variables required for notify-send to work.
. /home/anmol/.env_vars

low_notif_percentage=20
critical_notif_percentage=15
critical_action_percentage=10


if [ "${level}" -le ${critical_action_percentage} ]; then
  # sudo is required when running from cron
  sudo systemctl hibernate
  exit 0
fi

if [ "${level}" -le ${critical_notif_percentage} ]; then
  notify-send -i '/usr/share/icons/gnome/256x256/status/battery-caution.png' "Battery critical: ${level}%"
  exit 0
fi

if [ "${level}" -le ${low_notif_percentage} ]; then
  notify-send -i '/usr/share/icons/gnome/256x256/status/battery-low.png' "Battery low: $level%"
  exit 0
fi

Les variables d'environnement requises pour notify-sendfonctionner sont créées à l'aide de ce script :

#!/usr/bin/env bash

# Create a new file containing the values of the environment variables
# required for cron scripts to work.
# This script is supposed to be scheduled to run at startup.

env_vars_path="$HOME/.env_vars"

rm -f "${env_vars_path}"
touch "${env_vars_path}"
chmod 600 "${env_vars_path}"

# Array of the environment variables.
env_vars=("DBUS_SESSION_BUS_ADDRESS" "XAUTHORITY" "DISPLAY")

for env_var in "${env_vars[@]}"
do
    echo "$env_var"
    env | grep "${env_var}" >> "${env_vars_path}";
    echo "export ${env_var}" >> "${env_vars_path}";
done

Ce fichier doit être exécuté au démarrage (peut être fait en utilisant n'importe quelle méthode de votre choix; j'utilise les applications de démarrage intégrées d'Ubuntu ).

Remarque: sudo systemctl hibernate peut ne pas fonctionner à partir de cron. Suivez ceci pour le résoudre.

Anmol Singh Jaggi
la source
0

Il existe de nombreuses façons de l'implémenter, car il existe de nombreux schémas de gestion de l'alimentation différents en fonction de ce que vous avez installé.

Ce simple fonctionne pour moi sur Debian Jessie minimaliste sans aucun environnement de bureau, juste avec un gestionnaire de fenêtres icewm petit et rapide. (Il est réduit car trop lent sinon, et de cette façon, il surpasse GNOME sur un bien meilleur matériel)

Plus précisément, j'ai installé les packages suivants: acpi acpi-fakekey acpi-support acpi-support-base acpid pm-utils mais je n'ai AUCUN des éléments suivants (après les avoir purgés): gnome * kde * systemd * uswsusp upower laptop-mode-tools hibernate policykit-1

Je viens donc de mettre cela /etc/cron.d/battery_low_check(tout en une seule ligne, divisé pour plus de lisibilité):

*/5 * * * *   root  acpi --battery | 
   awk -F, '/Discharging/ { if (int($2) < 10) print }' | 
   xargs -ri acpi_fakekey 205

Il est rapide, utilise peu de ressources et ne dépend pas d'autres démons (si tel est le cas, il sera ignoré s'ils sont actifs - voir /usr/share/acpi-support/policy-funcspour plus de détails).

Ce qu'il fait: toutes les 5 minutes ( */5- vous pouvez passer à chaque minute en utilisant simplement *si vous en avez besoin pour vérifier la batterie plus souvent) il interrogera l'état de la batterie (" acpi --battery ") et exécutera la commande après xargs -riseulement si la batterie est " Décharge "(c'est-à-dire que vous n'êtes pas connecté au secteur) et l'état de la batterie est inférieur à 10%(" int (2 $) <10 "- n'hésitez pas à l'adapter à vos besoins)

acpi_fakekey 205enverra par défaut un KEY_SUSPENDévénement ACPI (comme vous avez appuyé sur une touche d'un ordinateur portable demandant la suspension), qui fera alors tout ce qu'il fait habituellement pour vous (configuré dans /etc/default/acpi-support) - pour moi, il hiberne sur le disque.

Vous pouvez utiliser une autre commande au lieu de acpi_fakekey 205bien sûr: comme hibernate(à partir du package hibernate), s2diskou s2mem(à partir du package uswsusp), pm-suspend-hybrid(à partir du package pm-utils), etc.

BTW, les numéros de clés magiques comme KEY_SUSPEND = 205 ci-dessus sont définis dans /usr/share/acpi-support/key-constants(un autre intéressant est probablement KEY_SLEEP = 142 )

Matija Nalis
la source
cela semble très sympa! mais cela pourrait-il être utilisé avec la minuterie systemd au lieu de cron? (exemple ici ) Je suis sur Solus OS où cron est absent.
@cipricus Je suppose que oui, mais j'évite systemd donc je ne peux pas donner d'exemple. Il me semble que systemd a ses propres gestionnaires d'alimentation ACPI, donc si vous êtes coincé avec systemd, vous voudrez probablement éviter de vous heurter à cela
Matija Nalis
merci, j'ai trouvé une alternative impliquant uname: github.com/jerrinfrncs/batterynotif/blob/master/…