Arch Linuxでバッテリー警告や通知を出す方法

##はじめに

バッテリーの警告を出すツールを作ってみました。

https://github.com/syui/battery-notify

```bash:
$ mkdir -p ~/.bin

$ cd ~/.bin

$ git clone https://github.com/syui/battery-notify

$ cd battery-notify

$ crontab battery-notify.txt
```

cronie, zsh, notify-send.sh, numix-icon-theme

##仕組み

```bash:
sudo pacman -S cronie zsh

# かっこいいアイコンを表示する場合
yaourt -S numix-icon-theme-git
```

zshには根本的に依存していませんが、パスの書き方を変更する必要が出て来ると思われます。

仕組みは簡単で、cronで1分おきに通知スクリプトを実行するというもの。スクリプトは、カーネルのバッテリーの値が通知条件にされています。

動かない場合は、`cat /sys/class/power_supply/BAT0/capacity`や` udevadm info -q property -a --path /sys/class/power_supply/BAT0`を確かめてみるといいかもしれません。

メッセージを消すショートカットキーを設定したければ、`.xbindkeysrc`を参考にしてください。

##crontab

タイマーです。

```bash:
# インストール
$ sudo pacman -S cronie

# 有効化と自動化
$ sudo systemctl start cronie
$ sudo systemctl enable cronie

# 設定
$ crontab -e

# 設定の確認
$ crontab -l
```

書き方は以下です。

```bash:
分 時 日 月 曜日 コマンド
# test-notify
*/1  *  *  *  * DISPLAY=:0.0 XAUTHORITY=~/.Xauthority /usr/bin/notify-send "test"
```

テスト、1分おきにnotify-sendで通知をします。

ちなみに、バッテリー関連は、Kernel領域になりますので、気になる方は調べればいいと思いますが、あまりおすすめはしません。ここでわかりやすいのは、`udev`です。

```bash:
# 容量やステータスを取得
# これらはカーネルの機能として書き出される情報の末端に過ぎませんので、完璧なものではありません
$ cat /sys/class/power_supply/BAT0/capacity
$ cat /sys/class/power_supply/BAT0/status

# udevから取得
$ udevadm info -q property -a --path /sys/class/power_supply/BAT0

# udevの設定を書く
# https://wiki.archlinux.org/index.php/Laptop
$ cat /etc/udev/rules.d/99-lowbat.rules
KERNEL=="BAT0", SUBSYSTEM=="power_supply", ATTR{status}=="Discharging", ATTR{capacity}=="[0-5]", RUN+="/usr/bin/systemctl hibernate"
```

udevの書き方は大体わかると思います。上記は、cat /sys/class/power_supply/BAT0/capacityで得られる値が0-5だった場合、ハイバネートと言って、休止するという感じのものになっています。systemctl hibernateがそれに当たるコマンドです。

##systemd-timer

また、`cron`以外にもArch Linuxには、`systemd-timer`という仕組みが使えます。

systemdのtimer機能についての設定の書き方です。hoge.serviceとhoge.timerの２つのファイルを用意し、設定を書きます。登録の方は、`systemctl start hoge.timer`, `systemctl enable hoge.timer`です。

```bash:/etc/systemd/system/test.service
[Unit]
Description=Run foo weekly and on boot

[Service]
Type=oneshot
# 実行したいスクリプト
ExecStart=/usr/local/bin/test.sh
User=nobody
Group=systemd-journal
```

```bash:/etc/systemd/system/test.timer
[Unit]
Description=Run foo weekly and on boot

[Timer]
# 起動後15分
OnBootSec=15min
# 毎週
OnUnitActiveSec=1w
# 実行させたいサービス
Unit=hoge.service

[Install]
WantedBy=timers.target
```

##xdotool

実は、`notify-send`のメッセージを消すコマンドが見つからなかったので、xdotoolでクリックしてみたのですが、何故かできなかった。

```bash:~/.xbindkeysrc
"xdotool mousemove 1300 40 click 1"
 Control+Shift + i
```

しかし、直接現在のシェルで実行すれば、クリックできる感じでした。

```bash:~/.zshrc
bindkey -s '^n^n' 'xdotool mousemove 1300 40 click 1'
```

##notify-send.sh

ここで、[notify-send.sh](https://github.com/vlevit/notify-send.sh/blob/master/notify-send.sh)というスクリプトを誰か書いてた。これは、idを発行し、closeを簡単にできるようになってる。

コードをざっと見た限りでは、やはりディスプレイマネージャーが関連してるっぽいです。


```bash:notify-send.sh
# これで値を取得し、handle_ouputに渡してる感じ
gdbus call "${NOTIFY_ARGS[@]}"  --method org.freedesktop.Notifications.Notify \
          "$APP_NAME" "$REPLACE_ID" "$ICON" "$SUMMARY" "$BODY" \
          [] "$(concat_hints "${HINTS[@]}")" "int32 $EXPIRE_TIME" | handle_ouput

# で、handle_ouputはこんな感じの関数
# ここでprint idを確認してる
handle_ouput() {
    if [[ -z "$PRINT_ID" ]] ; then
        cat > /dev/null
    else
        sed 's/(uint32 \([0-9]\+\),)/\1/g'
    fi
}

# print idがわかれば、それをcloseできるらしい
notify_close () {
    gdbus call "${NOTIFY_ARGS[@]}"  --method org.freedesktop.Notifications.CloseNotification "$1" >/dev/null
}
```

```bash:
# これでidを取得
$ ./notify-send.sh -u critical test -p
01

# これでidを指定しメッセージをclose
$ ./notify-send.sh -s 01
```

参考

https://wiki.archlinux.org/index.php/Cron

https://wiki.archlinux.org/index.php/Systemd/Timers

https://wiki.archlinux.org/index.php/Udev

https://github.com/vlevit/notify-send.sh