web-dev-qa-db-ja.com

systemdサービスがpythonスクリプトを実行していません

RaspberryPi3のバッテリー通知スクリプトを作成していました。私がするとき、スクリプトは実行されています

/usr/bin/python /home/pi/Documents/shutdown.py

ポップアップ通知を表示します。ただし、サービスはそれを実行していないか、通知を表示していません。 Sudo systemctl status battery-notifier.serviceを実行すると、pythonプロセスが表示されます。

バッテリー-notifer.service

[Unit]
Description=Battery Notifier

[Service]
Type=simple
WorkingDirectory=/home/pi/Documents
ExecStart=/usr/bin/python /home/pi/Documents/shutdown.py

[Install]
WantedBy=multi-user.target

shutdown.py

import raspiupshat
import statistics
import subprocess
from time import sleep
raspiupshat.init()
while(True):
    voltagesList = []
    sleep(0.5)
    currentVoltage = raspiupshat.getv()
    voltagesList.append(currentVoltage)
    medianVoltage = statistics.median(voltagesList)
    if(medianVoltage>4):
        subprocess.Popen(["notify-send","Battery Full!"])

これは、Sudo systemctl status battery-notifier.serviceを実行したときのサービスのステータスです。

● battery-notifier.service - Battery Notifier
   Loaded: loaded (/lib/systemd/system/battery-notifier.service; enabled)
   Active: active (running) since Sat 2017-07-15 04:05:18 UTC; 48min ago
 Main PID: 28384 (python)
   CGroup: /system.slice/battery-notifier.service
           └─28384 /usr/bin/python /home/pi/Documents/shutdown.py

Jul 15 04:05:18 raspberrypi systemd[1]: Started Battery Notifier.
1
avistein

編集して追加:プログラムはユーザーのグラフィカルデスクトップ(pi)にアクセスしようとしますが、それ自体はsystemdによって実行されます。つまり、ユーザーpiとしてではなく、デフォルトでrootとして実行されます。さらに、これが開始された時点では、グラフィカルデスクトップすら存在しない可能性があります。

したがって、いくつかのパスに進むことができます。

  • Systemd経由ではなく、ログインしたユーザーがグラフィカルデスクトップを起動したときにプログラムを起動します。したがって、プログラムの開始をファイル_~/.xinitrc_または_~/.xprofile_に入れる必要があります。 自動起動に関するArch Wiki を参照してください。
  • Systemdサービスに_User=pi_という行を追加します。これは、元の投稿へのコメントで言及した解決策です
  • systemdは、ユーザーがログインしたときに(システムモードではなく)ユーザーモードで実行されるように構成できます。この方法でサービスを開始させることができます。 systemd/UserのArchWiki を参照してください。

元の答え:

this SO question を参照してください。使用できるsubprocess.Popen(.)関数には_env=_パラメーターがあります。

または、shの機能を使用して、呼び出しの直前に変数を割り当てると、その変数がその呼び出しに対して(のみ)設定されます。

_myvar=world
# cannot use echo $myvar, because $myvar would be substituted before echo is launched
myvar=hello declare -x myvar 
echo $myvar
_

与える

_declare -x myvar="hello"
world
_

POSIX仕様の対応する章へのリンク

だからあなたのために:

_subprocess.call("DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-goOEk5dZcK,‌​guid=9c1f14175e6be09‌​92b16e5155969b46c notify-send 'Battery full!'",s‌​hell=True)
_

質問へのコメントで言及した呼び出しは、次のプロセスにつながるため機能しません

  • subprocess.Popen('export DBUS_SESSION_BUS_ADRESS=..., Shell = True)

    • シェルを起動する
    • このシェルとすべてのサブシェルに環境変数_DBUS_SESSION_BUS_ADRESS=..._を設定します(これがexportの機能です)。

      内容[〜#〜] not [〜#〜]:マシン上にあるすべてのシェルに変数を設定してください!

    • シェルを閉じます。これで、_DBUS_SESSION_BUS_ADRESS_の値が再び失われます。
  • subprocess.Popen(['notify-send',...], Shell=True)
    • シェルを起動する
    • 前のシェルのexport呼び出しは、これら2つのシェルが完全に無関係であるため、ここでは力がありません。
    • 元の質問と同じように_notify-send_を起動します

したがって、環境変数の設定はここでは効果がありません。

2
akraf