質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
systemd

systemdは、Linuxの起動処理及びシステム管理を行う技術です。他にも多くのサービス管理機能を備えており、ユーザープロセスを並列に起動しシステムの起動処理に要する時間を短縮できるなどの特徴があります。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

3747閲覧

systemdを使ってpythonプログラムを自動起動させると、ローカルPCからブラウザが開かない

Uka

総合スコア28

systemd

systemdは、Linuxの起動処理及びシステム管理を行う技術です。他にも多くのサービス管理機能を備えており、ユーザープロセスを並列に起動しシステムの起動処理に要する時間を短縮できるなどの特徴があります。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/07/29 12:36

編集2021/07/30 04:04

前提・実現したいこと

ラズパイをWiFiアクセスポイント化して、ローカルPCからブラウザを開くと所望の画面が表示できるようなプログラムを実装しています。ラズパイのコマンドプロントから直接pythonプログラムを実行した際には問題なく画面が表示されますが、systemdを使ってpythonプログラムの自動起動を設定してみたところ、以下のようなメッセージが表示され、画面に表示できませんでした。どこに原因があるのかご教示いただけますと幸いです。よろしくお願いいたします。

※追記
serviceファイルの自動起動実行後、ステータスを確認してみたところ、failedとなっており、自動起動に失敗していることが判明しましたが、原因がわかりません。

【ファイルの構成】
app.py
|
templatesフォルダ--index.html
|
staticフォルダ--Chart.bundle.js, jquery.min.js

発生している問題・エラーメッセージ

「このサイトにアクセスできません192.168.123.9 で接続が拒否されました。」とともに、
ブラウザ画面のコンソールでエラー詳細を確認したところ、以下のメッセージがでました。

crbug/1173575, non-JS module files deprecated.

該当のソースコード(app.py)

python

1import os 2#その他のimportは省略 3 4script_path = os.path.dirname(os.path.abspath(__file__)) 5 6#測定用 7y1={} 8yy1 = [] 9 10#ブラウザ送受信用 11analog = [] 12message = [] 13a11 = [] 14data11 = {} 15 16def save_all_frames(video_path, dir_path, basename, ext='jpg'): 17 18 #省略 19 20a1 = [] 21 22a4 = [] 23a5 = [] 24 25def scanning(img): 26 #省略 27 28def scanning2(img, tension_h): 29 #省略 30 31app = Flask(__name__) 32 33@app.route('/') 34def index(): 35 return render_template('index.html') 36 37@app.route('/publish') 38#@app.route('/publish', methods=['POST']) 39def publish(): 40 41 if request.environ.get('wsgi.websocket'): 42 ws = request.environ['wsgi.websocket'] 43 #message = "" 44 for t in range(0,2): #ブラウザ画面でパラメータ入力したのを受け取る 45 data11[t] = ws.receive() 46 47 a11.append(data11[t]) 48        49 50 path_sh = os.path.join(script_path, '/home/pi/final_program/trial/satsuei.sh') 51 52 subprocess.run(['sh', path_sh]) 53 save_all_frames('/home/pi/final_program/trial/test11.h264', 'image', 'test') 54 DIR='/home/pi/final_program/trial/image' 55 file_num=sum(os.path.isfile(os.path.join(DIR, name)) for name in os.listdir(DIR)) 56 57 for f in range(0,file_num): 58 img_path = "/home/pi/final_program/trial/image" 59 img_name = "test_"+str(f).zfill(16)+".jpg" 60 target_path = os.path.join(img_path, img_name) 61 img = cv2.imread(target_path) 62      63 input1, input2 = scanning(img) 64 #省略 65 66 ws.send(json.dumps(data_all)) #ブラウザにデータを送信して結果を表示させる 67 68 69 return "200 ok" 70 71if __name__ == '__main__': 72 app.debug = True 73 #HTMLno wstoicchisitenaitoikenai 74 #server = pywsgi.WSGIServer(('localhost', 5050), app, handler_class=WebSocketHandler) 75 server = pywsgi.WSGIServer(('192.168.123.9', 5050), app, handler_class=WebSocketHandler) 76 server.serve_forever()

該当のソースコード(index.html)

html

1!DOCTYPE html> 2<html lang="ja"> 3<head> 4 <meta charset="utf-8"> 5 <title>graph test</title> 6 7 <script type="text/javascript" src="{{url_for('static', filename='jquery.min.js')}}"></script> 8 <script type="text/javascript" src="{{url_for('static', filename='Chart.bundle.js')}}"></script> 9</head> 10 11<style> 12#省略 13</style> 14 15<script type="text/javascript"> 16 17$(document).ready(function(){ 18 $('form').submit(function(event){ 19 var inputText=$(".textBox").map(function(index,el){ 20 21 ws.send($(this).val()) 22 console.log($(this).val()) 23 return false; 24 }); 25 return false; 26 }); 27}); 28 29 30var ws = new WebSocket("ws://192.168.123.9:5050/publish"); 31 32//websocket経由で受け取ったデータをparseしてChart.jsのデータに渡す 33ws.onmessage = function (msg) { 34 //const json_string = JSON.stringify(msg.data); 35 //var obj = JSON.parse(msg.json_string); 36 var obj = JSON.parse(msg.data); 37 console.log(obj); 38 var obj_result1 = obj.slice(0,63); 39 var obj_result2 = obj.slice(63,126); 40 var obj_result3 = obj.slice(126,189); 41 42 var html = ""; 43 for (var i = 0; i < 63; i++) { 44 var firstBlockRecord = obj_result1[i]; 45 var secondBlockRecord = obj_result2[i]; 46 var thirdBlockRecord = obj_result3[i]; 47 48 html += ` 49 <tr> 50 <td>${firstBlockRecord.x}</td> 51 <td>${firstBlockRecord.y}</td> 52 <td>${secondBlockRecord.x}</td> 53 <td>${thirdBlockRecord.x}</td> 54 <td>${secondBlockRecord.y}</td> 55 <td>${thirdBlockRecord.z}</td> 56 <tr/> 57 `; 58 } 59 60 var tbody = document.createElement("tbody"); 61 tbody.innerHTML = html; 62 document.querySelector("#dataTable").append(tbody); 63 64 #省略(グラフ表示) 65 66</script> 67 68<body> 69 <form method='POST' action='#'> 70 <fieldset class="chart-container" > 71 <legend>入力フォーム</legend> 72 73 <div class="inline-text"><label for="input-sample">入力1: </label><input type="text" name='data2' id="Text2" class="textBox" size="7"><font size="-1"> m</font></div> 74 75 <div class="inline-text"><label for="input-sample">入力2: </label><input type="text" name='data5' id="Text5" class="textBox" size="7"><font size="-1"> m</font></div> 76 77 78 <div><input type='submit'></div> 79 </fieldset> 80 </form> 81 82 83 <div> 84 <div class="chart-container" position:relative; height:300px; width:100%;><canvas id="chart1" width="300" height="300"></canvas></div> 85 <div class="chart-container" position:relative; height:300px; width:100%;><canvas id="chart2" width="300" height="300"></canvas></div> 86 <div class="chart-container" position:relative; height:300px; width:100%;><canvas id="chart3" width="300" height="300"></canvas></div> 87 </div> 88 89 <table id="dataTable"> 90 #省略 91 </table> 92 </body> 93 94 </html>

試したこと

ラズパイの自動起動ファイル(browser.service)を/etc/systemd/systemに配置し、ラズパイのコマンドプロントから
sudo systemctl etc/systemd/system/browser.serviceを実行してラズパイを再起動後、ローカルPCから所望する画面が表示されるかどうかを確認しましたが、上記のエラーがでて表示できませんでした。

service

1[Unit] 2Description=MJPG-Streamer with /dev/video0 3 4[Service] 5Type=simple 6ExecStart=/usr/bin/python3 /home/pi/final_program/trial/app.py 7Restart=always 8 9[Install] 10WantedBy=multi-user.target

browser.serviceのステータスを確認してみたところ、failedになっていました。

pi@raspberrypi:~ $ systemctl status browser ● browser.service - measurement Loaded: loaded (/etc/systemd/system/browser.service; enabled; ven Active: failed (Result: exit-code) since Thu 2021-06-24 14:45:31 JST; 39s ago Process: 651 ExecStart=/usr/bin/python3 /home/pi/final_program/trial Main PID: 651 (code=exited, status=1/FAILURE) 6月 24 14:45:31 raspberrypi systemd[1]: browser.service: Service Re 6月 24 14:45:31 raspberrypi systemd[1]: browser.service: Scheduled 6月 24 14:45:31 raspberrypi systemd[1]: Stopped measurement. 6月 24 14:45:31 raspberrypi systemd[1]: browser.service: Start requ 6月 24 14:45:31 raspberrypi systemd[1]: browser.service: Failed wit 6月 24 14:45:31 raspberrypi systemd[1]: Failed to start measurement.

補足情報(FW/ツールのバージョンなど)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2021/07/29 20:41 編集

/var/log/syslog あたりにエラーメッセージ出てませんか? あと、正常に動くことを確認するまでは Restart=always はコメントアウトした方が良いのでは…。 それから、質問のタグが JavaScript になってますが、Python に直してもらえると助かります。
CHERRY

2021/07/29 23:19

app.py は、 root ユーザーで正常に動作するのでしょうか? sudo /usr/bin/python3 /home/pi/final_program/trial/app.py を実行すると どのような結果になるのでしょうか?
Uka

2021/07/30 04:45 編集

hoshi-takanoriさん CHERRYさん ご回答いただきましてありがとうございます。 syslogファイルを確認してみましたが、今回のserviceのログについては見つけられませんでした。 アドバイスいただいたとおり、serviceファイルのなかの Restart=alwaysについてはコメントアウトし、 ExecStart=sudo /usr/bin/python3 /home/pi/final_program/trial/app.py として、sudoを冒頭につけてservice自動起動を実行後、再起動してserviceのステータスを確認したところ、以下のメッセージが表示されました。 ● browser.service - measurement Loaded: loaded (/etc/systemd/system/browser.service; enabled; vendor preset: Active: failed (Result: exit-code) since Thu 2021-06-24 15:42:52 JST; 34s ago Process: 376 ExecStart=/usr/bin/sudo /usr/bin/python3 /home/pi/final_program/trial Main PID: 376 (code=exited, status=1/FAILURE) 6月 24 15:42:34 raspberrypi systemd[1]: Started measurement. 6月 24 15:42:35 raspberrypi sudo[376]: root : TTY=unknown ; PWD=/ ; USER=root ; COMMAN 6月 24 15:42:35 raspberrypi sudo[376]: pam_unix(sudo:session): session opened for user roo 6月 24 15:42:52 raspberrypi sudo[376]: Traceback (most recent call last): 6月 24 15:42:52 raspberrypi sudo[376]: File "/home/pi/final_program/trial 6月 24 15:42:52 raspberrypi sudo[376]: from gevent import pywsgi 6月 24 15:42:52 raspberrypi sudo[376]: ModuleNotFoundError: No module named 'gevent' 6月 24 15:42:52 raspberrypi sudo[376]: pam_unix(sudo:session): session closed for user roo 6月 24 15:42:52 raspberrypi systemd[1]: browser.service: Main process exited, 6月 24 15:42:52 raspberrypi systemd[1]: browser.service: Failed with result 'e ModuleNotFoundError: No module named 'gevent' のメッセージについてですが、こちらはpythonプログラムのなかで、以下のモジュールをimportしています。 from gevent import pywsgi from geventwebsocket.handler import WebSocketHandler from flask import Flask, request, render_template
hoshi-takanori

2021/07/30 04:45

gevent や、その他お使いのモジュールはどこにありますか? ラズパイはデフォルトユーザーである pi でお使いだと思いますが、/etc/systemd/system に登録したプログラムはスーパーユーザーである root で実行されます。また、カレントディレクトリや環境変数なども通常とは異なる状態になると思います。このために gevent モジュールが見つけられないのでしょう。 CHERRY さんがお書きになった sudo をつけて実行してみてはというアドバイスは、browser.service の中に ExecStart=sudo 〜 と書くということではなく、ラズパイのコマンドプロントで sudo をつけて実行すると root 権限で動くので、それで試してみてはということです。
CHERRY

2021/07/30 05:31

フォローありがとうございます。 root ユーザーのコマンドラインで動かないものは、ExecStart に指定しても動かないので、root ユーザーのコマンドラインから問題なく実行できますか? という意味でした。
Uka

2021/07/30 09:01 編集

hoshi-takanoriさん、CHERRYさん ご回答ありがとうございます。 アドバイスを勘違いしており、大変失礼いたしました。 改めて、ラズパイのコマンドラインから直接以下のコマンドを実行してみたところ、同じようにgeventが見つからない、というエラーメッセージがでました。 sudo /usr/bin/python3 /home/pi/final_program/trial/app.py 一方でsudo をつけないで実行した場合は問題ありません(エラーはなく、ブラウザ画面に表示されます) ちなみに、本題とは別にmjpg-streamerを自動起動させるpythonプログラムも実行させていますが、こちらはserviceプロブラムでsudoをつけないでも問題なくブラウザ画面から閲覧できています。
hoshi-takanori

2021/07/30 16:12

まず、gevent のありかを調べましょう。 /usr/bin/python3 -c 'import gevent; print(gevent.__file__)' 次に、python がモジュールを探す場所を確認します。 /usr/bin/python3 -c 'import sys; print(sys.path)' sudo /usr/bin/python3 -c 'import sys; print(sys.path)' sudo をつけた場合とつけてない場合の違いをご確認ください。たぶん、gevent のある場所が sudo をつけた場合には出てこないと思われます。ので、それを追加する必要がありますが、方法は環境変数と、スクリプトの中に直接書き込む方法があります。 https://note.nkmk.me/python-import-module-search-path/
Uka

2021/07/31 05:41 編集

hoshi-takanoriさん ご返信ありがとうございます。 アドバイスいただいたとおりに確認しましたところ、sudoのときにgeventがある場所に探しにいっていないことがわかりました。geventがあるパスを追加してあらためてserviceの自動起動を実行し、動作確認したところ、所望のブラウザ画面が表示できるようになりました。はじめにご教示いただいた「/etc/systemd/system に登録したプログラムはスーパーユーザーである root で実行されます。」の意味がよくわかりました。大変勉強になりました。本当にありがとうございました。
guest

回答1

0

自己解決

hoshi-takanoriさんのアドバイスにしたがい、解決することができました。

serviceに登録しているpythonプログラムにimportしているモジュールが見つからないために自動起動が正常に動作しないことがわかりました。hoshi-takanoriさんからご教示いただいたとおり、「/etc/systemd/system に登録したプログラムはスーパーユーザーである root で実行され」ます。確認方法として、まずエラーがでているモジュールの居場所を確認し、sudoでプログラムを実行した際にモジュールを探しにいく場所と合致しているかどうかを確認します。今回はエラーになっているモジュールがsudoの探索パスに入っていなかったため、そのパスを追加することにより自動起動させることができるようになりました。
https://note.nkmk.me/python-import-module-search-path/
「Pythonでimportの対象ディレクトリのパスを確認・追加(sys.pathなど)」

投稿2021/08/02 14:09

Uka

総合スコア28

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問