电池电量不足时,如何使笔记本电脑进入睡眠状态?


24

我正在使用Ubuntu,但是我将i3作为窗口管理器而不是桌面环境。

当我的电池电量达到0%时,计算机将突然关闭,没有任何警告或其他任何信息。

我是否可以设置一个简单的脚本或配置,以便以4%的电池电量进入睡眠状态?

Answers:


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)。提到的两种停止环境均具有电源管理守护程序,该守护程序负责关闭计算机电源。但是我认为您有意不使用它们,而是在寻求更简单的解决方案。


嗯,我尝试跑步sleepd -b 40,但40%大关后什么也没发生。我也尝试过sudo sleepd -b 40 -s pm-suspend,什么也没发生……
o_o_o--

@NoamGagliardi确认,在这里也不起作用。此外,该软件包似乎没有维护。我尝试是否可以找到更好的替代方法并更新答案,否则我将其删除。
Marco Marco

(TIL“ cut”。)该脚本有效!我有acpi | cut -f2 -d, | cut -f1 d%-我将阅读有关cron的信息,以使其独立运行。谢谢!
o_o_o--

我没有/sys/devices/platform/smapi/目录。在哪里可以找到电池电量的剩余百分比?我正在使用自定义内核3.10
Martin Vegter 2014年

2
@MartinVegter取决于您的硬件,您可以尝试/sys/class/power_supply/BAT0/capacity。否则,使用acpi命令。
Marco Marco

6

您可以仅安装upower软件包,而不用黑客入侵自己的脚本,并且如果您按照标签所指示的那样使用Ubuntu,则可以安装该软件包。它应在包括Ubuntu在内的所有Debian衍生产品中可用。默认情况下,它带有一种配置,/etc/UPower/UPower.conf一旦电池电量达到临界值,便会激活混合睡眠。关键级别的默认值为2%。

对于其他发行版的用户,与之相关的条目/etc/UPower/UPower.conf是:

PercentageAction=2
CriticalPowerAction=HybridSleep

您还可以TimeAction将与一起使用,UsePercentageForPolicy=false以使操作仅在指定的时间还剩时执行:

TimeAction=120

为有效值CriticalPowerActionPowerOffHibernateHybridSleep。如果设置了HybridSleep但不可用,将使用休眠模式。如果设置了休眠但不可用,将使用PowerOff。

HybridSleep的优点是,除了将内存写出到交换区之外,它还挂起了系统。挂起仍会消耗一些电池,但是如果您在用完电池之前又回来了,那么从挂起的系统中恢复比从休眠的系统中恢复要快得多。万一电池没电再回到电源插座,一旦恢复供电,便可以从休眠状态恢复系统。


注意:我认为HybridSleep需要有一个交换空间。

2
@cipricus是正确的,但是如果无法休眠,上位机将优雅地选择关闭计算机。
josch

2

当前接受的答案很好,但是对于Ubuntu 16.04来说有些过时了:

  • 获取电池状态的命令已更改。
  • 通知发送工作所需的环境变量已更改
  • 由于休眠需要root用户,因此此处给出的脚本不能再由cron用户使用。
  • 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笔记本电脑模式工具休眠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_SUSPENDACPI事件(就像您按笔记本电脑上的某个键请求挂起一样),然后它将为您执行通常为您做的任何事情(在中配置/etc/default/acpi-support)-对我来说它会休眠到磁盘。

您可以使用其他命令来代替,acpi_fakekey 205例如hibernate:(从hibernate包)s2disks2mem(从uswsusp包),pm-suspend-hybrid(从pm-utils包)等等。

顺便说一句,上面定义了像KEY_SUSPEND = 205这样的魔术钥匙号/usr/share/acpi-support/key-constants(另一个有趣的可能是KEY_SLEEP = 142


看起来很好!但是可以与systemd timer而不是cron一起使用吗?(此处为示例)我在不存在cron的Solus OS上。

@cipricus我想是的,但是我避免使用systemd,所以不能举个例子。我似乎确实记得systemd拥有自己的ACPI电源处理程序,因此,如果您对systemd
感到困惑

谢谢,我发现涉及替代unamegithub.com/jerrinfrncs/batterynotif/blob/master/...

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.