Как стать автором
Обновить

Выключение ноутбука по таймеру в ждущем режиме

Время на прочтение3 мин
Количество просмотров5.7K

В systemd есть режим suspend-then-hibernate который выполняет гибернацию (режим сна) через указанное время после простоя в ждущем режиме.

Настроим подобный режим, только с автоматическим выключение ноутбука при длительном нахождении в ждущем режиме. Это может быть полезно если нет желания использовать гибернацию (большой объём RAM, SSD или медленный HDD), но хочется обезопасить аккумулятор от глубокого разряда.

Режимы сна

SystemD поддерживает следующие режимы сна:

  • suspend "Ждущий режим." Приостанавливает работу системы, данные продолжают хранится в оперативной памяти. Активирует цель suspend.target.

  • hibernate "Спящий режим." Приостанавливает работу системы, сохраняет оперативную память на жёсткий диск. Активирует цель hibernate.target. Выключает питания.

  • hybrid-sleep "Гибридный режим." Приостанавливает работу системы, сохраняет оперативную память на жёсткий диск, но не выключает питания. Активирует цель hybrid-sleep.target.

  • suspend-then-hibernate Переход в ждущий режим(suspend) с последующим переход в спящий режим(hibernate) через указанное время. Активирует цель suspend-then-hibernate.target.

Детально параметры сна настраиваются в файле sleep.conf.

Ловим переход в ждущий режим

Создадим сервис /etc/systemd/system/sleep-auto-poweroff.service со следующим содержимым:

[Unit]
Before=sleep.target
StopWhenUnneeded=yes
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -c "echo Start pending-poweroff.timer"
ExecStop=/bin/bash -c "echo Stop pending-poweroff.timer"
[Install]
WantedBy=sleep.targe

Этот сервис зависит от цели sleep.target и будет запускаться при переходе в ждущий и спящий режимы.
Здесь важно пояснить два параметра:

  • RemainAfterExit=yes Сервис будет считаться активным пока не будет явно остановлен, даже если команда в ExecStart завершится.

  • StopWhenUnneeded=yes Если служба активна, то она будет остановлена, когда все зависящие от неё юниты остановлены. В данном случае когда завершится sleep.target.

За счёт установки этих параметров, команда из параметра ExecStart будет выполнена до переходя в ждущий режим, а команда из ExecStop, после выхода из этого режима.
Перед переходом в ждущий будем запускать таймер, а после возобновления работы - останавливать.

Также для обработки перехода в ждущий режим можно использовать пару сервисов:

#/etc/systemd/system/suspend.service
[Unit]
Before=sleep.target
[Service]
Type=oneshot
ExecStart=-before_sleep.sh
[Install]
WantedBy=sleep.target

#/etc/systemd/system/resume.service
[Unit]
After=sleep.target
[Service]
Type=oneshot
ExecStart=-after_sleep.sh
[Install]
WantedBy=sleep.target

Таймер обратного отсчёта

Создаём таймер /etc/systemd/system/pending-poweroff.timer:

[Timer]
AccuracySec=1h
OnActiveSec=72h
WakeSystem=true
RemainAfterElapse=false
Unit=systemd-poweroff.service
[Install]
WantedBy=timers.target

Разберём важные параметры:

  • AccuracySec - допустимое отклонение таймера, точность, по умолчанию 1 минута.

  • OnActiveSec - время от активации таймера до срабатывания.

  • WakeSystem - таймер будет работать и в ждущем режиме, при срабатывании компьютер возобновит работу.

  • RemainAfterElapse=false - таймер будет деактивирован после срабатывания.

  • Unit - юнит который будет запущен при срабатывании таймера.

Таймер запускается в ручную командой systemctl start pending-poweroff.timer, ждёт время указанное в OnActiveSec (72 часа) и выполняет юнит systemd-poweroff.service. Остановить таймер можно командой systemctl stop pending-poweroff.timer.

Для отладки удобно создать сервис, который пишет сообщение в журнал, и указать его в параметре Unit таймера pending-poweroff.timer. Ещё можно изменить значения AccuracySec и OnActiveSec.

#/etc/systemd/system/nop.service
[Unit]
Description=Test
[Service]
Type=oneshot
ExecStart=-/usr/bin/echo "Hello! The system is shutdowning."

#/etc/systemd/system/pending-poweroff.timer
...
[Timer]
Unit=nop.service
...

Готовый вариант

 #/etc/systemd/system/sleep-auto-poweroff.service
[Unit]
Description=Automatic shutdown after waiting
Before=sleep.target
StopWhenUnneeded=yes
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -c "systemctl start pending-poweroff.timer && echo Start pending-poweroff.timer"
ExecStop=/bin/bash -c "sleep 3 && systemctl stop pending-poweroff.timer && echo Stop pending-poweroff.timer"
[Install]
#suspend.target, hibernate.target and hybrid-sleep.target and because sleep.target
WantedBy=sleep.target

#/etc/systemd/system/pending-poweroff.timer
[Unit]
Description=Poweroff the system after this timer is stoped.
[Timer]
AccuracySec=1h
OnActiveSec=72h
WakeSystem=true
RemainAfterElapse=false
Unit=systemd-poweroff.service
[Install]
WantedBy=timers.target

Вызов sleep в ExecStop нужен чтобы таймер успел выполнится, когда выход из режима сна вызван самим таймером.

Теги:
Хабы:
Всего голосов 13: ↑12 и ↓1+14
Комментарии7

Публикации

Истории

Ближайшие события

7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань