2021年07月30日 更新

systemdで定期的にスクリプト実行

どうも、クラゲです。
systemdを使って、定期的にスクリプトを実行させる方法です。今回は、1分毎に効果音を鳴らすというスクリプト例で作成してみます。

古い方法でcronというものがありますが、そのうちサポートされなくなる可能性があるため、systemdを使ってタイマーを行います。

systemdタイマーの作成ステップ

ステップは大きく4つです。
「その他」はタイマーの停止やトラブルシューティングの説明です。

[TOC]

スクリプトファイル作成

定期的に実行させたいスクリプトを作成します。今回は1分毎に効果音を鳴らすという例です。フォルダ作成と効果音を用意し、最後にPythonスクリプトを作成します。

フォルダ作成

まずスクリプトファイルを置くフォルダを作ります。 /home/pi/myapp にしましたが、場所も名前も自由に決められます。

mkdir /home/pi/myapp
cd /home/pi/myapp

効果音準備

ラズパイにデフォルトで入っているwavファイルを利用します。
/usr/share/sounds/alsa というフォルダにいくつか音声ファイルが入っているので、今回は Rear_Right.wav をコピーして活用します。

cp /usr/share/sounds/alsa/Rear_Right.wav /home/pi/myapp/timer.wav

音声ファイルをコピーして /home/pi/myapp フォルダに入れて、ファイル名を timer.wav にしています。上記コマンドがうまくいかなかったり、他の音を使いたい人は、自分で好きに準備してもらってOKです。ちなみに、ウェブ上で「効果音 wav」などで検索するとすぐに見つかります。

Pythonコード

同じフォルダ内に以下の内容で timer_app.py というスクリプトファイルを作成します。以下はテキストエディッタnanoを使って書く場合のコマンドです。

nano /home/pi/myapp/timer_app.py

aplayコマンドで timer.wav を再生するだけのスクリプトです。

import subprocess
subprocess.run(['aplay', 'timer.wav'])

nanoは Ctrl + O Enter で保存し、 Ctrl + X で終了します。

サービスファイル作成

/etc/systemd/system の下にサービスファイルを作成します。

sudo nano /etc/systemd/system/timer_app.service

書く内容は以下の通りです。

[Unit]
Description=Play the sound every minute
After=network.target

[Service]
ExecStart=/usr/bin/python3 timer_app.py
WorkingDirectory=/home/pi/myapp

[Unit] [Service] の2つを書きます。それぞれの中身を簡単に説明します。

Unit

Description= の後の文字列はスクリプトの説明メモです。任意の文字列を書けます。
After=network.target を書くことでインターネット接続を待ってから処理が始まります。

Service

ExecStart= の後に実行させたい内容を書きます。今回はPython3でtimer_app.pyを実行しています。
WorkingDirectory= の後にスクリプトファイルのディレクトリを書きます。これを書くことで、ExecStart での記述が相対パスで良いだけでなく、スクリプトファイルの中身も相対パスのままでOKとなるので絶対おすすめ。

タイマーファイル作成

/etc/systemd/system の下にタイマーファイルを作成します。
拡張子は .timer ですが、名前はサービスファイル名と同じにしてください。

sudo nano /etc/systemd/system/timer_app.timer
[Unit]
Description=Play the sound every minute
After=network.target

[Timer]
OnCalendar=*-*-* *:*:00

[Install]
WantedBy=timers.target

[Unit] [Timer] [Install] の3つを書きます。それぞれの中身を簡単に説明します。

Unit

ここはサービスファイルと全く同じです。

Timer

OnCalendar= でスクリプトを実行させる定刻の設定ができます。
例えば 0分だけ(つまり1時間毎)という設定にしたい場合は OnCalendar=*-*-* *:00:00 と書きます。 別の例で、0分/15分/30分/45分 というように15分毎に設定したい場合は OnCalendar=*-*-* *:00,15,30,45 と書きます。
その他、月日や曜日などで設定も出来ます。詳細設定方法はこちらを参照してください。

Install

WantedBy=timers.target は必須の記述です。

タイマー有効化

ファイルを作るだけではダメで、有効にする必要があります。ただし、有効にするのはタイマーファイルだけでOKです。
以下のコマンドで有効になります。

sudo systemctl enable timer_app.timer

これで完了!
ラズパイを再起動すれば実行されるようになります。
ただし、きっちり1分毎ではなく、おそらくラズパイのシステムが忙しくないときに実行されているので、揺らぎはあります。

その他

タイマー無効化

以下のコマンドで無効化できます。
再び有効化させたい場合は先程のタイマー有効化コマンドだけでOK。

sudo systemctl disable timer_app.timer

実際にタイマーが止まるのは再起動した後です。すぐに止めたい場合は下記の「一時的に無効化する」も併用してください。

一時的に有効化する

タイマー無効中に、以下のコマンドを実行することで、一時的にタイマーを有効にできます。再起動すると無効状態に戻ります。

sudo systemctl start timer_app.timer

一時的に無効化する

タイマー有効中に、以下のコマンドを実行することで、一時的にタイマーを無効にできます。再起動すると有効状態に戻ります。

sudo systemctl stop timer_app.timer

トラブルシューティング

  • ファイルを編集した場合は systemctl daemon-reload と打つ
  • Pythonスクリプトで subprocess.Popen が実行されない場合があるので subprocess.run に変えてみる
  • 状態やログ確認は systemctl status timer_app.servicesystemctl status timer_app.timer と打ち込む。Ctrl + Cで終了。

以上、「systemdを使って定期的にスクリプト実行」でした!