Wie kann ich meinen Laptop in den Ruhezustand versetzen, wenn er einen niedrigen Batteriestand erreicht?

24

Ich benutze Ubuntu, habe aber i3 als Fenstermanager anstelle einer Desktop-Umgebung.

Wenn mein Akku 0% erreicht, wird der Computer nur abrupt heruntergefahren, ohne Warnung oder irgendetwas.

Gibt es ein einfaches Skript oder eine Konfiguration, die ich so einrichten kann, dass es in den Energiesparmodus wechselt, z. B. 4% Batterie?

o_o_o--
quelle

Antworten:

12

Hier ist ein kleines Skript, das den Batteriestand überprüft und einen benutzerdefinierten Befehl aufruft pm-hibernate, falls der Batteriestand unter einem bestimmten Schwellenwert liegt.

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

Es ist ein sehr einfaches Skript, aber ich denke, Sie haben die Idee und können es leicht an Ihre Bedürfnisse anpassen. Der Pfad zum Akkuladestand kann auf Ihrem System unterschiedlich sein. Etwas portabler wäre es wahrscheinlich, etwas acpi | cut -f2 -d,zu verwenden, um den Akkuladestand zu ermitteln. Dieses Skript kann von cron so geplant werden, dass es jede Minute ausgeführt wird. Bearbeiten Sie Ihre Crontab mit crontab -eund fügen Sie das Skript hinzu:

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

Eine andere Lösung wäre, eine Desktop-Umgebung wie Gnome oder Xfce zu installieren (und Ihren Fenstermanager auf i3 zu ändern). Beide genannten Destop-Umgebungen verfügen über Power-Management-Daemons, die den Computer ausschalten. Aber ich gehe davon aus, dass Sie sie absichtlich nicht verwenden und nach einer minimalistischeren Lösung suchen.

Marco
quelle
Hm, ich habe versucht zu rennen sleepd -b 40und nach der 40% -Marke ist nichts passiert. Ich habe es auch versucht sudo sleepd -b 40 -s pm-suspendund nichts passiert ...
o_o_o-
@NoamGagliardi Bestätigt, es funktioniert auch hier nicht. Darüber hinaus scheint das Paket nicht gepflegt. Ich versuche, eine bessere Alternative zu finden und meine Antwort zu aktualisieren, andernfalls lösche ich sie.
Marco
(BIS " cut".) Das Skript funktioniert! Ich habe acpi | cut -f2 -d, | cut -f1 d%- ich werde über cron lesen, damit es von alleine läuft. Vielen Dank!
o_o_o-
Ich habe kein /sys/devices/platform/smapi/Verzeichnis. Wo finde ich den verbleibenden Prozentsatz der Batterieleistung? Ich benutze benutzerdefinierten Kernel 3.10
Martin Vegter
2
@MartinVegter Es hängt von deiner Hardware ab, die du ausprobieren kannst /sys/class/power_supply/BAT0/capacity. Verwenden Sie andernfalls den acpiBefehl.
Marco
6

Anstatt Ihre eigenen Skripte zu hacken und wenn Sie Ubuntu verwenden, wie es das Tag vorschlägt, können Sie einfach das Paket upower installieren. Es sollte auf allen Debian-Derivaten einschließlich Ubuntu verfügbar sein. Standardmäßig wird eine Konfiguration mitgeliefert, bei der /etc/UPower/UPower.confder Hybridschlaf aktiviert wird, sobald der Akkuladestand kritische Werte erreicht. Die Standardeinstellung für das kritische Niveau ist 2%.

Für Benutzer anderer Distributionen sind folgende Einträge relevant /etc/UPower/UPower.conf:

PercentageAction=2
CriticalPowerAction=HybridSleep

Sie können auch TimeActionzusammen mit verwenden UsePercentageForPolicy=false, um die Aktion auszuführen, sobald nur noch die angegebene Zeit übrig ist:

TimeAction=120

Die gültigen Werte für CriticalPowerActionsind PowerOff, Hibernateund HybridSleep. Wenn HybridSleep eingestellt, aber nicht verfügbar ist, wird der Ruhezustand verwendet. Wenn der Ruhezustand aktiviert, aber nicht verfügbar ist, wird PowerOff verwendet.

Der Vorteil von HybridSleep ist, dass das System nicht nur in den Swap-Bereich geschrieben, sondern auch angehalten wird. Der Energiesparmodus verbraucht immer noch einen Teil des Akkus. Wenn Sie jedoch vor dem Ende des Akkus zurückkehren, können Sie den Energiesparmodus von einem gesperrten System aus viel schneller fortsetzen als von einem in den Ruhezustand versetzten. Sollte der Akku leer sein, bevor Sie wieder an eine Steckdose angeschlossen werden, können Sie den Ruhezustand des Systems wiederherstellen, sobald Sie wieder mit Strom versorgt werden.

josch
quelle
Hinweis: Ich denke HybridSleep, muss ein Swap Space haben.
2
@cipricus ist korrekt, aber upower fährt den Computer ordnungsgemäß herunter, wenn er nicht in den Ruhezustand versetzt werden kann.
josch
2

Die aktuell akzeptierte Antwort ist großartig, aber für Ubuntu 16.04 etwas veraltet:

  • Die Befehle zum Abrufen des Batteriestatus haben sich geändert.
  • Die Umgebungsvariablen, die für das Senden von Benachrichtigungen an die Arbeit erforderlich sind, wurden geändert .
  • Das dort angegebene Skript funktioniert nicht mehr von Benutzer cron, da für den Ruhezustand root erforderlich ist.
  • systemctl hibernatewird vorgezogen pm-hibernate.

Also, hier ist das Skript, das ich benutze:

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

Die für notify-senddie Arbeit erforderlichen Umgebungsvariablen werden mit diesem Skript erstellt :

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

Diese Datei muss beim Start ausgeführt werden (kann mit einer beliebigen Methode Ihrer Wahl ausgeführt werden; ich verwende Ubuntus integrierte Startup-Anwendungen ).

Hinweis: Funktioniert sudo systemctl hibernate möglicherweise nicht mit cron. Befolgen Sie diese Schritte , um das Problem zu lösen.

Anmol Singh Jaggi
quelle
0

Es gibt viele Möglichkeiten, dies zu implementieren, da abhängig von Ihrer Installation viele verschiedene Energieverwaltungsschemata implementiert werden.

Dieser einfache funktioniert für mich auf minimalistischem Debian Jessie ohne Desktop-Umgebung, nur mit kleinem und schnellem icewm-Fenstermanager. (Es wird gekürzt, weil es sonst einfach zu langsam ist und auf diese Weise GNOME auf viel besserer Hardware übertrifft.)

Konkret habe ich folgende Pakete installiert: acpi acpi-fakekey acpi-support acpi-support-base acpid pm-utils, aber KEINE der folgenden (nachdem ich sie gelöscht habe): gnome * kde * systemd * uswsusp upower laptop-mode-tools Ruhezustand Policykit-1

Also habe ich dies einfach eingegeben /etc/cron.d/battery_low_check(alles in einer Zeile, zur besseren Lesbarkeit aufgeteilt):

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

Es ist schnell, ressourcenschonend und hängt nicht von anderen Deamons ab (wenn tatsächlich, wird es ignoriert, wenn sie aktiv sind - siehe /usr/share/acpi-support/policy-funcsfür Details).

Was es tut: Alle 5 Minuten ( */5- Sie können zu jeder Minute wechseln, indem Sie nur verwenden, *wenn Sie die Batterie öfter prüfen müssen), wird der Batteriestatus abgefragt (" acpi --battery ") und der Befehl xargs -rierst ausgeführt, wenn die Batterie leer ist. Entladen "(das heißt, Sie sind nicht an das Stromnetz angeschlossen) und der Batteriestatus ist geringer als 10%(" int ($ 2) <10 "- Sie können ihn jederzeit an Ihre Bedürfnisse anpassen)

acpi_fakekey 205Sendet standardmäßig ein KEY_SUSPENDACPI-Ereignis (wie Sie eine Taste auf dem Laptop gedrückt haben, um das Anhalten anzufordern), das dann das tut, was es normalerweise für Sie tut (konfiguriert in /etc/default/acpi-support) - für mich wird es auf der Festplatte in den Ruhezustand versetzt.

Sie können stattdessen acpi_fakekey 205natürlich auch einen anderen Befehl verwenden : wie hibernate(aus dem Ruhezustandspaket) s2diskoder s2mem(aus dem uswsusp-Paket), pm-suspend-hybrid(aus dem pm-utils-Paket) usw.

Übrigens sind magische Schlüsselnummern wie oben KEY_SUSPEND = 205 definiert /usr/share/acpi-support/key-constants(eine andere interessante ist wahrscheinlich KEY_SLEEP = 142 ).

Matija Nalis
quelle
das scheint sehr schön zu sein! aber könnte das mit systemd timer anstelle von cron verwendet werden? (Beispiel hier ) Ich bin auf Solus OS, wo cron fehlt.
@cipricus Ich denke schon, aber ich vermeide systemd, also kann ich kein Beispiel geben. Ich scheine mich zu erinnern, dass systemd seine eigenen ACPI-Power-Handler hat. Wenn Sie also bei systemd stecken bleiben, möchten Sie wahrscheinlich vermeiden, dass es zu Konflikten kommt
Matija Nalis,
danke, ich habe eine Alternative gefunden, die uname