Как заставить мой ноутбук спать, когда он достигает некоторого низкого порога батареи?

24

Я использую Ubuntu, но у меня в качестве оконного менеджера i3, а не среда рабочего стола.

Когда моя батарея достигнет 0%, компьютер просто внезапно выключится, без предупреждений или чего-либо еще.

Есть ли простой сценарий или конфигурация, которую я могу настроить, чтобы она перешла в режим сна, скажем, 4% заряда батареи?

o_o_o--
источник

Ответы:

12

Вот небольшой скрипт, который проверяет уровень заряда батареи и вызывает пользовательскую команду pm-hibernate, если уровень заряда батареи ниже определенного порога.

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

Это очень простой сценарий, но я думаю, что вы поняли идею и можете легко адаптировать ее к вашим потребностям. Путь к уровню заряда батареи может отличаться в вашей системе. Возможно, немного более портативным было бы использовать что-то вроде acpi | cut -f2 -d,уровня заряда батареи. Этот сценарий может быть запланирован на запуск cron каждую минуту. Отредактируйте ваш crontab crontab -eи добавьте скрипт:

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

Другим решением было бы установить среду рабочего стола, такую ​​как Gnome или Xfce (и изменить ваш оконный менеджер на i3). Обе упомянутые среды destop имеют демонов управления питанием, которые заботятся о выключении компьютера. Но я предполагаю, что вы сознательно не используете их и ищете более минималистичное решение.

Marco
источник
Хм, я пробовал бегать, sleepd -b 40и после 40% отметки ничего не произошло. Я тоже пытался, sudo sleepd -b 40 -s pm-suspendи ничего не происходит ...
o_o_o--
@NoamGagliardi Подтверждено, здесь тоже не работает. Кроме того, пакет, кажется, не поддерживается. Я пытаюсь найти лучшую альтернативу и обновить свой ответ, иначе я ее удалю.
Марко
(TIL " cut".) Сценарий работает! У меня есть acpi | cut -f2 -d, | cut -f1 d%- я прочитаю о cron, чтобы заставить его работать самостоятельно. Благодарность!
o_o_o--
У меня нет /sys/devices/platform/smapi/каталога. Где я могу найти оставшийся процент заряда батареи? Я использую собственное ядро ​​3.10
Martin Vegter
2
@MartinVegter Это зависит от вашего оборудования, вы можете попробовать /sys/class/power_supply/BAT0/capacity. В противном случае используйте acpiкоманду.
Марко
6

Вместо того, чтобы взламывать свои собственные сценарии, и если вы используете Ubuntu, как подсказывает тег, вы можете просто установить пакет upower. Он должен быть доступен на всех производных Debian, включая Ubuntu. По умолчанию он поставляется с конфигурацией, в /etc/UPower/UPower.confкоторой активируется гибридный режим ожидания, когда уровень заряда батареи достигает критических значений. Значение по умолчанию для критического уровня составляет 2%.

Для пользователей других дистрибутивов соответствующие записи для /etc/UPower/UPower.conf:

PercentageAction=2
CriticalPowerAction=HybridSleep

Вы также можете использовать TimeActionвместе с, UsePercentageForPolicy=falseчтобы позволить выполнению действия, когда осталось только указанное время:

TimeAction=120

Допустимые значения CriticalPowerActionявляются PowerOff, Hibernateи HybridSleep. Если HybridSleep установлен, но недоступен, будет использоваться Hibernate. Если Hibernate установлен, но недоступен, будет использоваться PowerOff.

Преимущество HybridSleep заключается в том, что, помимо записи памяти в область подкачки, она затем приостанавливает работу системы. При приостановке все равно будет расходоваться некоторое количество батареи, но если вы вернетесь до того, как батарея разрядится, вы сможете гораздо быстрее возобновить работу из приостановленной системы, чем из спящего режима. Если батарея разрядится до того, как вы вернетесь к электрической розетке, вы можете вывести систему из режима гибернации, как только снова включите питание.

josch
источник
Примечание: я думаю, что HybridSleepтребуется место подкачки.
2
@cipricus, это правильно, но upower изящно выберет выключение машины, если она не может перейти в спящий режим.
17
2

В настоящее время принят хороший ответ, но он немного устарел для Ubuntu 16.04:

  • Команды для получения статуса батареи изменились.
  • Переменные среды, необходимые для уведомления-отправки на работу , изменены .
  • Приведенный там скрипт больше не работает от пользователя cron, так как hibernate требует root.
  • systemctl hibernateпредпочтительнее pm-hibernate.

Итак, вот скрипт, который я использую:

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

Переменные среды, необходимые для notify-sendработы, создаются с помощью этого скрипта :

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

Этот файл должен запускаться при запуске (это можно сделать любым методом по вашему выбору; я использую встроенные приложения запуска Ubuntu ).

Примечание: sudo systemctl hibernate может не работать с cron. Следуйте этому, чтобы решить это.

Анмол Сингх Джагги
источник
0

Существует много способов его реализации, так как в зависимости от того, что вы установили, реализовано много разных схем управления питанием.

Этот простой работает для меня на минималистичном Debian Jessie без какой-либо рабочей среды, только с небольшим и быстрым оконным менеджером icewm. (Он урезан, потому что в противном случае он слишком медленный, и таким образом он превосходит GNOME на гораздо лучшем оборудовании)

В частности, я установил следующие пакеты: acpi acpi-fakekey acpi-support acpi-support-base acpid pm-utils, но НЕТ НИКАКОГО из следующих (очистив их): gnome * kde * systemd * uswsusp upower laptop-mode-tools Hibernate Policykit-1

Так что я просто вставил это /etc/cron.d/battery_low_check(все в одну строку, разделить для удобства чтения):

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

Он быстрый, использует мало ресурсов и не зависит от других демонов (если это так, он будет проигнорирован, если они активны - см. /usr/share/acpi-support/policy-funcsПодробности).

Что он делает: каждые 5 минут ( */5- вы можете переключиться на каждую минуту, просто используя, *если вам нужно, чтобы чаще проверять батарею), он будет опрашивать состояние батареи (« acpi --battery ») и выполнять команду после, xargs -riтолько если батарея заряжена » Разряжается "(то есть вы не подключены к сети переменного тока), и состояние аккумулятора ниже 10%(" int ($ 2) <10 "- не стесняйтесь настроить его в соответствии с вашими потребностями)

acpi_fakekey 205по умолчанию отправит KEY_SUSPENDсобытие ACPI (как вы нажали клавишу на ноутбуке, запрашивающем приостановку), которое затем будет делать то, что обычно для вас (настроено в /etc/default/acpi-support) - для меня оно переводится в режим гибернации на диск.

Вместо этого вы можете использовать другую команду acpi_fakekey 205: например hibernate(из пакета hibernate) s2diskили s2mem(из пакета uswsusp), pm-suspend-hybrid(из пакета pm-utils) и т. Д.

Кстати, магические номера ключей, такие как KEY_SUSPEND = 205 выше, определены в /usr/share/acpi-support/key-constants(другой интересный, вероятно, KEY_SLEEP = 142 )

Матия Налис
источник
это кажется очень хорошим! но можно ли использовать системный таймер вместо cron? (пример здесь ) Я на Solus OS, где Cron отсутствует.
@cipricus Я так думаю, но я избегаю systemd, поэтому не могу привести пример. Кажется, я помню, что systemd имеет свои собственные обработчики питания ACPI, поэтому, если вы застряли с systemd, вам, вероятно, следует избегать столкновений с этим
Matija Nalis
спасибо, я нашел альтернативу с участием uname: github.com/jerrinfrncs/batterynotif/blob/master/...
0

Мне нравится это решение, которое частично вдохновлено другими ответами: https://github.com/jerrinfrncs/batterynotif , а именно сценарием batterynotif(uname).sh.

Смотрите скрипт здесь: https://github.com/jerrinfrncs/batterynotif/blob/master/batterynotif%28uname%29.sh

Для собственного использования я изменил сценарий, чтобы ввести гибридный сон вместо выключения с помощью команды systemctl hybrid-sleep. (Для этой опции требуется пространство подкачки.)


источник