Como faço para o meu laptop dormir quando atinge um limite de bateria fraca?

24

Estou usando o Ubuntu, mas tenho o i3 como meu gerenciador de janelas em vez de um ambiente de desktop.

Quando minha bateria atinge 0%, o computador é desligado abruptamente, sem aviso ou qualquer coisa.

Existe um script ou configuração simples que eu possa definir para que durma, digamos, 4% de bateria?

o_o_o--
fonte

Respostas:

12

Aqui está um pequeno script que verifica o nível da bateria e chama um comando personalizado aqui pm-hibernate, caso o nível da bateria esteja abaixo de um determinado limite.

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

É um script muito simples, mas acho que você entendeu a idéia e pode adaptá-la facilmente às suas necessidades. O caminho para o nível da bateria pode ser diferente no seu sistema. Um pouco mais portátil provavelmente seria usar algo como acpi | cut -f2 -d,para obter o nível da bateria. Esse script pode ser agendado pelo cron para ser executado a cada minuto. Edite seu crontab crontab -ee adicione o script:

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

Outra solução seria instalar um ambiente de desktop como o Gnome ou o Xfce (e alterar o gerenciador de janelas para i3). Os dois ambientes de destop mencionados mencionam recursos daemons de gerenciamento de energia que cuidam de desligar o computador. Mas suponho que você deliberadamente não os use e esteja buscando uma solução mais minimalista.

Marco
fonte
Hum, tentei correr sleepd -b 40e nada aconteceu depois da marca de 40%. Eu também tentei sudo sleepd -b 40 -s pm-suspende nada acontece ...
o_o_o-- 25/07
@NoamGagliardi Confirmado, também não funciona aqui. Além disso, o pacote parece não mantido. Eu tento encontrar uma alternativa melhor e atualizar minha resposta, caso contrário, eu a excluo.
25413 Marco Marco
(TIL " cut".) O script funciona! Eu tenho acpi | cut -f2 -d, | cut -f1 d%- vou ler sobre o cron para fazê-lo funcionar por conta própria. Obrigado!
o_o_o--
Eu não tenho /sys/devices/platform/smapi/diretório. Onde posso encontrar a porcentagem restante de energia da bateria? Estou usando o kernel personalizado 3.10
Martin Vegter
2
@ MartinVegter Depende do seu hardware, você pode tentar /sys/class/power_supply/BAT0/capacity. Caso contrário, use o acpicomando
Marco
6

Em vez de invadir seus próprios scripts e se você estiver usando o Ubuntu como a tag sugere, basta instalar o pacote upower. Ele deve estar disponível em todos os derivados do Debian, incluindo o Ubuntu. Por padrão, ele vem com uma configuração na /etc/UPower/UPower.confqual ativa o sono híbrido quando o nível da bateria atinge valores críticos. O padrão para o nível crítico é 2%.

Para usuários de outras distribuições, as entradas relevantes para /etc/UPower/UPower.confsão:

PercentageAction=2
CriticalPowerAction=HybridSleep

Você também pode usar TimeActionjunto com UsePercentageForPolicy=falsepara permitir que a ação seja executada uma vez que resta apenas o tempo especificado:

TimeAction=120

Os valores válidos para CriticalPowerActionsão PowerOff, Hibernatee HybridSleep. Se HybridSleep estiver definido, mas não disponível, o Hibernate será usado. Se o Hibernate estiver definido, mas não disponível, o PowerOff será usado.

A vantagem do HybridSleep é que, além de gravar memória na sua área de troca, ele suspende o sistema. A suspensão ainda consumirá alguma bateria, mas se você voltar antes que a bateria acabe, poderá retomar muito mais rapidamente a partir de um sistema suspenso do que de um sistema hibernado. Caso a bateria se esgote antes de você voltar para uma tomada, é possível retomar o sistema da hibernação depois de ter energia novamente.

Josch
fonte
Nota: Eu acho que HybridSleeprequer um espaço de troca.
2
O @cipricus que está correto, mas o upower irá optar por desligar a máquina se não puder hibernar.
Josch
2

A resposta atualmente aceita é ótima, mas um pouco desatualizada para o Ubuntu 16.04:

  • Os comandos para obter o status da bateria foram alterados.
  • As variáveis ​​de ambiente necessárias para a notificação de envio para o trabalho foram alteradas .
  • O script fornecido lá não funciona mais com o cron do usuário, pois o hibernate requer raiz.
  • systemctl hibernateé o preferido pm-hibernate.

Então, aqui está o script que eu uso:

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

As variáveis ​​de ambiente necessárias para o notify-sendtrabalho são criadas usando este 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

Este arquivo precisa ser executado na inicialização (pode ser feito usando qualquer método de sua escolha; eu uso os Aplicativos de Inicialização incorporados do Ubuntu ).

Nota: sudo systemctl hibernate pode não funcionar no cron. Siga isto para resolvê-lo.

Anmol Singh Jaggi
fonte
0

Existem várias maneiras de implementá-lo, pois existem muitos esquemas de gerenciamento de energia diferentes, dependendo do que você instalou.

Este simples funciona para mim no Debian Jessie minimalista, sem qualquer ambiente de desktop, apenas com o gerenciador de janelas pequeno e rápido do icewm. (Ele é reduzido porque é muito lento, caso contrário, e dessa maneira supera o GNOME em um hardware muito melhor)

Especificamente, eu instalei os seguintes pacotes: acpi acpi-fakekey acpi-support acpi-support-base acpid pm-utils, mas NENHUMA das seguintes opções (após eliminá-las): gnome * kde * systemd * uswsusp upower laptop-mode-tools policykit-1 do hibernate

Então, eu apenas coloquei isso /etc/cron.d/battery_low_check(tudo em uma linha, divida para facilitar a leitura):

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

É rápido, usa pouco recurso e não depende de outros daemon (se for verdade, será ignorado se estiver ativo - veja /usr/share/acpi-support/policy-funcspara obter detalhes).

O que faz: a cada 5 minutos ( */5- você pode mudar para cada minuto usando apenas *se precisar verificar a bateria com mais frequência), ele pesquisará o status da bateria (" acpi --battery ") e executará o comando depois xargs -riapenas se a bateria estiver " Descarregando "(ou seja, você não está conectado à corrente alternada) e o status da bateria é menor que 10%(" int ($ 2) <10 "- fique à vontade para ajustá-lo às suas necessidades)

acpi_fakekey 205por padrão, envia o KEY_SUSPENDevento ACPI (como você pressionou uma tecla no laptop solicitando suspensão), que fará o que costuma fazer por você (configurado em /etc/default/acpi-support) - para mim, ele hiberna para o disco.

Você pode usar outro comando em vez de, é acpi_fakekey 205claro: como hibernate(do pacote hibernate) s2diskou s2mem(do pacote uswsusp), pm-suspend-hybrid(do pacote pm-utils) etc.

BTW, números mágicos de chave como KEY_SUSPEND = 205 acima são definidos em /usr/share/acpi-support/key-constants(outro interessante é provavelmente KEY_SLEEP = 142 )

Matija Nalis
fonte
isso parece muito legal! mas isso poderia ser usado com o timer do systemd em vez do cron? (exemplo aqui ) Estou no Solus OS onde o cron está ausente.
@ Cipricus Acho que sim, mas evito o systemd, por isso não posso dar exemplo. Eu parecem systemd recordação tem seus próprios manipuladores de energia ACPI, por isso, se você está preso com systemd você provavelmente quer evitar confronto com isso
Matija Nalis
obrigado, eu ter encontrado uma alternativa envolvendo uname: github.com/jerrinfrncs/batterynotif/blob/master/...