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

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

新規登録して質問してみよう
ただいま回答率
85.37%
Raspberry Pi

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

Python

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

Q&A

2回答

6506閲覧

Pythonをデーモン化したい

neko3378

総合スコア8

Raspberry Pi

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

Python

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

0グッド

0クリップ

投稿2020/02/19 01:47

編集2020/02/19 01:50

前提・実現したいこと

シリアル通信で受信したデータをDBに格納する、まではうまくいきましたが
それをデーモン化するところで詰まっています。
参考サイト:pythonスクリプトをdaemonにする
RasberryPiを使用

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

pi@raspberrypi:/etc/systemd/system $ sudo systemctl status dat_ret.service ● dat_ret.service - dat_ret daemon Loaded: loaded (/etc/systemd/system/dat_ret.service; enabled; vendor preset: enabled) Active: failed (Result: exit-code) since Wed 2020-02-19 10:13:03 JST; 1s ago Process: 14257 ExecStart=/home/pi/web/cgi-bin/dat_ret.py (code=exited, status=127) Main PID: 14257 (code=exited, status=127) 2月 19 10:13:03 raspberrypi systemd[1]: dat_ret.service: Service RestartSec=100ms expired, scheduling 2月 19 10:13:03 raspberrypi systemd[1]: dat_ret.service: Scheduled restart job, restart counter is at 2月 19 10:13:03 raspberrypi systemd[1]: Stopped dat_ret daemon. 2月 19 10:13:03 raspberrypi systemd[1]: dat_ret.service: Start request repeated too quickly. 2月 19 10:13:03 raspberrypi systemd[1]: dat_ret.service: Failed with result 'exit-code'. 2月 19 10:13:03 raspberrypi systemd[1]: Failed to start dat_ret daemon.

dat_ret.py

/home/pi/web/cgi-bin/dat_ret.py

Python

1#!/usr/bin/env python3 2 3import serial 4import re 5import MySQLdb 6import time 7 8def main(): 9 connection = MySQLdb.connect( 10 host='127.0.0.1', 11 port=3306, 12 user='root', 13 passwd='pass', 14 db='sensordata') 15 cursor = connection.cursor() 16 17 con=serial.Serial('/dev/ttyAMA0', 115200, timeout=30) 18 line = con.readline() 19 num=re.findall('[0123456789.]+',line.decode('sjis')) 20 21 cursor.execute("""INSERT INTO data (temp, press, hum, light) VALUES (%s, %s, %s, %s)""" ,num) 22 connection.commit() 23 connection.close() 24 25if __name__ == '__main__': 26 while True: 27 main() 28 time.sleep(30)

main()の中単体で動かすことはできてます。

dat_ret.service

[Unit] Description = dat_ret daemon [Service] ExecStart = /home/pi/web/cgi-bin/dat_ret.py Restart = always Type = simple [Install] WantedBy = multi-user.target

試したこと

Failed with result 'exit-code'.の検索

syslogの確認

Feb 19 10:13:03 raspberrypi systemd[1]: Started dat_ret daemon.

Feb 19 10:13:03 raspberrypi dat_ret.py[14257]: /usr/bin/env: `python3\r': そのようなファイルやディレクトリはあり ません
Feb 19 10:13:03 raspberrypi systemd[1]: dat_ret.service: Main process exited, code=exited, status=127/n/a
Feb 19 10:13:03 raspberrypi systemd[1]: dat_ret.service: Failed with result 'exit-code'.
Feb 19 10:13:03 raspberrypi systemd[1]: dat_ret.service: Service RestartSec=100ms expired, scheduling restart.
Feb 19 10:13:03 raspberrypi systemd[1]: dat_ret.service: Scheduled restart job, restart counter is at 5.
Feb 19 10:13:03 raspberrypi systemd[1]: Stopped dat_ret daemon.
Feb 19 10:13:03 raspberrypi systemd[1]: dat_ret.service: Start request repeated too quickly.
Feb 19 10:13:03 raspberrypi systemd[1]: dat_ret.service: Failed with result 'exit-code'.
Feb 19 10:13:03 raspberrypi systemd[1]: Failed to start dat_ret daemon.

ファイルやディレクトリはありません で検索

リンク内容
$ sudo vi dat_ret.py
を見てみると末尾に^Mがたくさんついてました。
いつもTeraPadでかいてるせい?(改行コードはLFになってました)
とりあえず^M全部消して一応全角とかスペースでtabぽくなってたところとかを直してもう一度status見たけど何も変わらず。
$ sudo systemctl daemon-reload
しても変わらず。
???
というところで詰まっています。
知識不足は自覚しておりますがどうぞよろしくお願いいたします。

現在daemon化のためのコマンド等を調べ中です。

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

ここにより詳細な情報を記載してください。

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

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

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

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

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

dodox86

2020/02/19 01:52

envコマンドでpython3を指定しているからだと思います。(それはそれで合っていますが、デーモンとして使う場合は注意が必要) $ which python3 を実行した場合、どう出力されますか?
neko3378

2020/02/19 01:54

ご指摘ありがとうございます。 pi@raspberrypi:/var/log $ which python3 /usr/bin/python3 このように出力されました
dodox86

2020/02/19 02:00

あるいは、末尾の改行コードの問題かな? `python3\r' > /usr/bin/env: `python3\r': そのようなファイルやディレクトリはありません $ /home/pi/web/cgi-bin/dat_ret.py と入力して実行するとどうなりますか?
neko3378

2020/02/19 02:13

何も反応なしです。
dodox86

2020/02/19 02:32

「何も反応なし」とはどういう状態ですか。プロンプト(ターミナルの'$'が表示されている)表示状態にすぐ戻ってしまうということですか。あるいは、python3スクリプトは実は動いているのではないですか? 以下の行で停まっているのでは。 con=serial.Serial('/dev/ttyAMA0', 115200, timeout=30) line = con.readline() ...readlineから戻らずに停まっている。
neko3378

2020/02/19 02:35

$に戻らず改行されたまま何も表示されずの状態がずっと続いてました。 ちょっとしたらこれが表示されました pi@raspberrypi:/etc/systemd/system $ /home/pi/web/cgi-bin/dat_ret.py Traceback (most recent call last): File "/home/pi/web/cgi-bin/dat_ret.py", line 27, in <module> main() File "/home/pi/web/cgi-bin/dat_ret.py", line 19, in main num=re.findall('[0123456789.]+',line.decode('sjis')) UnicodeDecodeError: 'shift_jis' codec can't decode byte 0x81 in position 7: illegal multibyte sequence エラーが出てるところはデーモン化する前はちゃんと動いてたのですが…。
dodox86

2020/02/19 02:41

それはまた本質問とは別の問題ですね。 $ /home/pi/web/cgi-bin/dat_ret.py と、直接手入力実行している場合は「デーモン」ではありません。con.readline()で取り込んだ受信データ中で、シフトJIS("sjis")で扱えないバイナリデータが紛れているので"UnicodeDecodeError: 'shift_jis' codec can't decode byte ..."と例外が起きています。ゴミデータとか読んでしまっているのでは。
neko3378

2020/02/19 02:59

#!/usr/bin/env python3 import serial import re import MySQLdb connection = MySQLdb.connect( host='127.0.0.1', port=3306, user='root', passwd='negi01', db='sensordata') cursor = connection.cursor() con=serial.Serial('/dev/ttyAMA0', 115200, timeout=30) line = con.readline() num=re.findall('[0123456789.]+',line.decode('sjis')) cursor.execute("""INSERT INTO data (temp, press, hum, light) VALUES (%s, %s, %s, %s)""" ,num) connection.commit() connection.close() こういうpythonプログラムを作って $ python3 test.py を実行するとちゃんと動きました。DBに格納もされてました。
dodox86

2020/02/19 03:04

正しいデータを読み出せてる限りはそれで動きますが、 line = con.readline() num=re.findall('[0123456789.]+',line.decode('sjis')) で、readlineでシリアル回線上からゴミや想定していないデータ00や01h, FFh)などを読み出してしまうと、decodeに失敗して例外が起きる、と言うことです。
dodox86

2020/02/19 03:05

「pythonスクリプトをデーモンで使う」とは別の話題です。
neko3378

2020/02/19 03:09

なるほど。 では想定したデータがきたときだけ動作する、みたいな記述を入れたら動きますかね? if()?
guest

回答2

0

Restart=always にして、デーモンが落ちてしまう経験があります。
logを見させていただくと、 start request repeated too quickly for ~ というログが確認できると思います。

マニュアルを調べてみると以下のような記載があって、
Note that service restart is subject to unit start rate limiting configured with StartLimitIntervalSec= and StartLimitBurst=, see systemd.unit(5) for details. A restarted service enters the failed state only after the start limits are reached.

これによると、頻繁にサービスが up/down を繰り返すと、強制的にrestartをやめるようになっているようです。

私の場合は、RestartSec=10s を使用して、restart の間隔を少し長めにして対応することで解決しました。

投稿2020/02/20 00:56

raspypy

総合スコア247

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

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

neko3378

2020/02/20 01:13

ご回答ありがとうございます。 .serviceの記述を変更した後は $ sudo systemctl daemon-reload で更新したらよいのでしょうか?
raspypy

2020/02/20 02:03

はい。 daemon-reloadの後、enable -> start -> statusで動作状況を確認してみてください。
neko3378

2020/02/20 02:33

ありがとうございます。too quicklyは消えました! pi@raspberrypi:/etc/systemd/system $ sudo systemctl status dat_ret.service ● dat_ret.service - dat_ret daemon Loaded: loaded (/etc/systemd/system/dat_ret.service; enabled; vendor preset: enabled) Active: failed (Result: exit-code) since Thu 2020-02-20 11:27:57 JST; 42s ago Process: 8441 ExecStart=/home/pi/web/cgi-bin/dat_ret.py (code=exited, status=1/FAILURE) Main PID: 8441 (code=exited, status=1/FAILURE) 2月 20 11:27:57 raspberrypi systemd[1]: Started dat_ret daemon. 2月 20 11:27:57 raspberrypi dat_ret.py[8441]: Traceback (most recent call last): 2月 20 11:27:57 raspberrypi dat_ret.py[8441]: File "/home/pi/web/cgi-bin/dat_ret.py", line 5, in <modu 2月 20 11:27:57 raspberrypi dat_ret.py[8441]: import MySQLdb 2月 20 11:27:57 raspberrypi dat_ret.py[8441]: ModuleNotFoundError: No module named 'MySQLdb' 2月 20 11:27:57 raspberrypi systemd[1]: dat_ret.service: Main process exited, code=exited, status=1/FAIL 2月 20 11:27:57 raspberrypi systemd[1]: dat_ret.service: Failed with result 'exit-code'.
raspypy

2020/02/20 02:56 編集

確認ですが、 daemon化するプログラム(.py?)単体で動作確認はされているのでしょうか? "ModuleNotFoundError: No module named 'MySQLdb'"と表示されていますが、 serviceファイルから起動するのではなく、プログラムを実行した際に、同じように "ModuleNotFoundError: No module named 'MySQLdb'"と表示されませんか? あと、serviceファイルで動作させるプログラムに、実行権限は付加されていますか? (chmod +x )
neko3378

2020/02/20 04:41

単体での動作は確認済です。そのときにそのエラーは出ません。 以前は単体で動作した時そのエラーが出ていたのですが、python3にMySQLdbが入ってないのが原因で、pip3でインストールしてエラーが出なくなりました。 付加しております。
raspypy

2020/02/20 04:47

[Service] ExecStart = /home/pi/web/cgi-bin/dat_ret.py Restart = on-failure RestartSec=10s としてみたら、どうでしょうか。
neko3378

2020/02/20 05:06

こうなりました pi@raspberrypi:/etc/systemd/system $ sudo systemctl status dat_ret.service ● dat_ret.service - dat_ret daemon Loaded: loaded (/etc/systemd/system/dat_ret.service; enabled; vendor preset: enabled) Active: activating (auto-restart) (Result: exit-code) since Thu 2020-02-20 14:04:52 JST; 4s ago Process: 9706 ExecStart=/home/pi/web/cgi-bin/dat_ret.py (code=exited, status=1/FAILURE) Main PID: 9706 (code=exited, status=1/FAILURE) これはちゃんと動いているのですかね?
raspypy

2020/02/20 05:20

動かしたいプログラムの中身を理解しておらず申し訳ないのですが、 おそらく動いていると思います。 $ sudo systemctl -t service コマンドを実行して、activeと表示されれば、動いていると思いますので、動作を確認なさってください。
guest

0

エラーメッセージが「/usr/bin/env: python3\r: そのようなファイルやディレクトリはあり ません」の部分は、コード1行目の「#!/usr/bin/env python3」の改行コードがCRLF(\r\n)となっているため、python3\r のファイル名でファイルを探してしまい、エラーとなっています。エディターでのファイル保存時にLFのみにし、ファイル転送時にもLFのままとなるようにすれば良いです。

コメント中で述べられていたUnicodeDecodeError例外(エラー)になる件は、con.readline()でシリアル回線上からゴミや想定していないデータを読み出してしまうと、decodeに失敗して当該エラーが起きる、という流れです。とりあえずUnicodeDecodeError例外をexceptで捕捉すればスキップすることができます。その部分だけ修正してみたコード例が以下、です。

Python3

1 2 con = serial.Serial('/dev/ttyAMA0', 115200, timeout=30) 3 line = con.readline() 4 try: 5 # con.readline()での受信データが'sjis'デコードに成功した場合のみ、DBへ保存 6 num = re.findall('[0123456789.]+',line.decode('sjis')) 7 cursor.execute("""INSERT INTO data (temp, press, hum, light) VALUES (%s, %s, %s, %s)""" ,num) 8 connection.commit() 9 except UnicodeDecodeError as e: 10 print(type(e)) 11 print(e) 12 13 connection.close() 14... 15

※質問と直接関係ない部分ですが、以下のコードって、正しくINSERT文が作成されているのでしょうか?「press, hum, light」のカラムデータがセットされていないように見えます。動いているのであれば適当な値が埋められているのかもしれませんが。(動作確認ができないため、指摘のみに留めます)

Python3

1cursor.execute("""INSERT INTO data (temp, press, hum, light) VALUES (%s, %s, %s, %s)""" ,num)

投稿2020/02/19 06:50

dodox86

総合スコア9254

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

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

dodox86

2020/02/19 06:55

たまにしか(数秒~数10秒?)シリアル回線からデータを受信しないのであれば、最初からDBのコネクションをopenしておく必要も無い気がしますが、流れが変わって質問者さんオリジナルのコードを大きく変更してしまいそうなのでそのままにしました。(実際の動きは私の方では分かりませんし)
neko3378

2020/02/19 07:18

ご回答ありがとうございます! dat_ret.pyを書き換えて再起動してみたのですがstatus確認しても変わりません。。。 reloadとかなにかしないといけないのでしょうか? INSERT文の方は正しくできてるようです。 num[0]=temp,num[1]=press,num[2]=hum,num[3]=lightという感じで順番に入ってるようです。
neko3378

2020/02/19 07:20

1分に1度でいいかなと思ってるのですが、1分に1度保存のたびにopenして保存してclose、のほうがスムーズなのでしょうか
dodox86

2020/02/19 07:20

何が変わらないのですか?エラーの状況が変わらないということでしょうか。
dodox86

2020/02/19 07:22

1分に1度など、周期については後の話で、まず現状で要望どおり動くようにするのを優先するので良いと思います。動いてからご自分で検討してみてください。
neko3378

2020/02/19 07:28 編集

statusの結果は変わりませんでした。 syslogはよく分からなかったので見ていただければ幸いです。 Feb 19 16:12:21 raspberrypi systemd[1]: Started dat_ret daemon. Feb 19 16:12:21 raspberrypi dat_ret.py[563]: File "/home/pi/web/cgi-bin/dat_ret.py", line 13 Feb 19 16:12:21 raspberrypi dat_ret.py[563]: SyntaxError: Non-UTF-8 code starting with '\x82' in file /home/pi/web/cgi-bin/dat_ret.py on line 13, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details Feb 19 16:12:21 raspberrypi systemd[1]: dat_ret.service: Main process exited, code=exited, status=1/FAILURE Feb 19 16:12:21 raspberrypi systemd[1]: dat_ret.service: Failed with result 'exit-code'. Feb 19 16:12:21 raspberrypi mysqld[524]: 2020-02-19 16:12:21 0 [Note] /usr/sbin/mysqld (mysqld 10.3.22-MariaDB-0+deb10u1) starting as process 524 ... Feb 19 16:12:22 raspberrypi systemd[1]: dat_ret.service: Service RestartSec=100ms expired, scheduling restart. Feb 19 16:12:22 raspberrypi systemd[1]: dat_ret.service: Scheduled restart job, restart counter is at 5. Feb 19 16:12:22 raspberrypi systemd[1]: Stopped dat_ret daemon. Feb 19 16:12:22 raspberrypi systemd[1]: dat_ret.service: Start request repeated too quickly. Feb 19 16:12:22 raspberrypi systemd[1]: dat_ret.service: Failed with result 'exit-code'. Feb 19 16:12:22 raspberrypi systemd[1]: Failed to start dat_ret daemon.
neko3378

2020/02/19 07:39

コメントのところで引っかかってるようだったのでコメントを消してもう一度動かしてみました。 syslog Feb 19 16:29:40 raspberrypi systemd[1]: dat_ret.service: Main process exited, co de=exited, status=1/FAILURE Feb 19 16:29:40 raspberrypi systemd[1]: dat_ret.service: Failed with result 'exi t-code'. Feb 19 16:29:40 raspberrypi dhcpcd[386]: eth0: soliciting an IPv6 router Feb 19 16:29:40 raspberrypi systemd[1]: Received SIGRTMIN+21 from PID 154 (plymo uthd). Feb 19 16:29:40 raspberrypi systemd[1]: Received SIGRTMIN+21 from PID 154 (plymo uthd). Feb 19 16:29:40 raspberrypi systemd[1]: dat_ret.service: Service RestartSec=100m s expired, scheduling restart. Feb 19 16:29:40 raspberrypi systemd[1]: dat_ret.service: Scheduled restart job, restart counter is at 1. Feb 19 16:29:40 raspberrypi systemd[1]: plymouth-quit-wait.service: Succeeded. Feb 19 16:29:40 raspberrypi systemd[1]: Started Hold until boot process finishes up. Feb 19 16:29:40 raspberrypi systemd[1]: Started Getty on tty1. Feb 19 16:29:40 raspberrypi systemd[1]: Reached target Login Prompts. Feb 19 16:29:40 raspberrypi systemd[1]: Stopped dat_ret daemon. Feb 19 16:29:40 raspberrypi systemd[1]: Started dat_ret daemon. Feb 19 16:29:40 raspberrypi systemd[1]: plymouth-start.service: Succeeded. Feb 19 16:29:40 raspberrypi systemd[1]: Started Light Display Manager. Feb 19 16:29:40 raspberrypi raspi-config[324]: Checking if shift key is held dow n: No. Switching to ondemand scaling governor. Feb 19 16:29:40 raspberrypi systemd[1]: Started LSB: Switch to ondemand cpu gove rnor (unless shift key is pressed). Feb 19 16:29:40 raspberrypi dat_ret.py[506]: Traceback (most recent call last): Feb 19 16:29:40 raspberrypi dat_ret.py[506]: File "/home/pi/web/cgi-bin/dat_re t.py", line 5, in <module> Feb 19 16:29:40 raspberrypi dat_ret.py[506]: import MySQLdb Feb 19 16:29:40 raspberrypi dat_ret.py[506]: ModuleNotFoundError: No module name d 'MySQLdb' Feb 19 16:29:40 raspberrypi systemd[1]: dat_ret.service: Main process exited, co de=exited, status=1/FAILURE Feb 19 16:29:40 raspberrypi systemd[1]: dat_ret.service: Failed with result 'exi t-code'. Feb 19 16:29:40 raspberrypi systemd[1]: Started Disk Manager. Feb 19 16:29:40 raspberrypi systemd[1]: dat_ret.service: Service RestartSec=100m s expired, scheduling restart. Feb 19 16:29:40 raspberrypi systemd[1]: dat_ret.service: Scheduled restart job, restart counter is at 2. Feb 19 16:29:40 raspberrypi udisksd[326]: Acquired the name org.freedesktop.UDis ks2 on the system message bus Feb 19 16:29:40 raspberrypi systemd[1]: Stopped dat_ret daemon. Feb 19 16:29:40 raspberrypi systemd[1]: Started dat_ret daemon. Feb 19 16:29:41 raspberrypi dat_ret.py[531]: Traceback (most recent call last): Feb 19 16:29:41 raspberrypi dat_ret.py[531]: File "/home/pi/web/cgi-bin/dat_re t.py", line 5, in <module> Feb 19 16:29:41 raspberrypi dat_ret.py[531]: import MySQLdb Feb 19 16:29:41 raspberrypi dat_ret.py[531]: ModuleNotFoundError: No module name d 'MySQLdb' Feb 19 16:29:41 raspberrypi systemd[1]: dat_ret.service: Main process exited, co de=exited, status=1/FAILURE Feb 19 16:29:41 raspberrypi systemd[1]: dat_ret.service: Failed with result 'exi t-code'. MySQLdbがないというのは以前も出てましたが、それは解決したはずなのにまた出てきたのはなぜでしょうか… dat_ret.py #!/usr/bin/env python3 import serial import re import MySQLdb import time def main(): connection = MySQLdb.connect(host='127.0.0.1',port=3306,user='root',passwd='negi01',db='sensordata') cursor = connection.cursor() try: num = re.findall('[0123456789.]+',line.decode('sjis')) cursor.execute("""INSERT INTO data (temp, press, hum, light) VALUES (%s, %s, %s, %s)""" ,num) connection.commit() except UnicodeDecodeError as e: print(type(e)) print(e) connection.close() if __name__ == '__main__': while True: main() time.sleep(30)
dodox86

2020/02/19 07:54

> コメントのところで引っかかってるようだったのでコメントを消してもう一度動かしてみました。 今は一般的にはpythonスクリプトはUTF-8エンコードで保存するものです。ですので # SyntaxError: Non-UTF-8 code starting with '\x82' in file /home/pi/web/cgi-bin/dat_ret.py on line 13, but no encoding declared; ... になったのでしょう。コメント削除自体はそれで構いません。 > MySQLdbがないというのは以前も出てましたが、それは解決したはずなのにまた出てきたのはなぜでしょうか… それはまた別の問題ですよね。新しいスクリプトでダメなら、古い(動いたはずの)スクリプトに戻して試してください。それでダメなら元のスクリプトにも潜在的に問題があるということです。
neko3378

2020/02/19 08:11

cgi-bin直下で直接 $ python3 dat_ret.py を実行してDBを確認したところ大体30秒ごとにデータ取得できてました。 ただ、3分くらい時間たつとこの表示が出てそれ以降取得できてません(プログラム止まったので当たり前なのでしょうが) pi@raspberrypi:~/web/cgi-bin $ python3 dat_ret.py (ここに何も表示されずに3,4分ほど経過後下のログが出てプログラム停止) Traceback (most recent call last): File "/home/pi/.local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 204, in execute query = query % args TypeError: not enough arguments for format string During handling of the above exception, another exception occurred: Traceback (most recent call last): File "dat_ret.py", line 26, in <module> main() File "dat_ret.py", line 16, in main cursor.execute("""INSERT INTO data (temp, press, hum, light) VALUES (%s, %s, %s, %s)""" ,num) File "/home/pi/.local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 206, in execute raise ProgrammingError(str(m)) MySQLdb._exceptions.ProgrammingError: not enough arguments for format string なお、さっきはcon=の記述が抜けてました。上記で動かしたものはこちらです。 #!/usr/bin/env python3 import serial import re import MySQLdb import time def main(): connection = MySQLdb.connect(host='127.0.0.1',port=3306,user='root',passwd='negi01',db='sensordata') cursor = connection.cursor() con = serial.Serial('/dev/ttyAMA0', 115200, timeout=30) line = con.readline() try: num = re.findall('[0123456789.]+',line.decode('sjis')) cursor.execute("""INSERT INTO data (temp, press, hum, light) VALUES (%s, %s, %s, %s)""" ,num) connection.commit() except UnicodeDecodeError as e: print(type(e)) print(e) connection.close() if __name__ == '__main__': while True: main() time.sleep(30)
dodox86

2020/02/19 08:16

> なお、さっきはcon=の記述が抜けてました。上記で動かしたものはこちらです。 やっぱりINSERT...のところでエラーが出ているではないですか。 > TypeError: not enough arguments for format string > > During handling of the above exception, another exception occurred: > > Traceback (most recent call last): > File "dat_ret.py", line 26, in <module> > main() > File "dat_ret.py", line 16, in main > cursor.execute("""INSERT INTO data (temp, press, hum, light) VALUES (%s, %s, %s, %s)""" ,num) INSERTの部分を直してください。
neko3378

2020/02/19 08:43 編集

この質問(https://teratail.com/questions/242035)でこういう解決方法を提案されていたのですがそれではだめだったということでしょうか。 num[4]= {(tempデータ), (pressデータ),(humデータ),(lightデータ)} みたいな配列(1次元配列?)をinsertで使っているサイトがみつからず詰まっております。
dodox86

2020/02/19 09:32

> 解決方法を提案されていたのですがそれではだめだったということでしょうか。 いえ、そちら(Q242035)でいただいた回答が、今回の質問に正しく適用されていません。そちらの回答でまず提示されている方法としては、*numが配列だとして、string.formatを使って、 s = "INSERT INTO data (temp, press, hum, light) VALUES ({0}, {1}, {2}, {3})".format(*num) で得られる文字列を使う方法です。 でも、続くコメントで「string.formatで組み立てるのは良くない」として、executemanyを使うのであれば、 cursor.executemany("""INSERT INTO data (temp, press, hum, light)VALUES (%s, %s, %s, %s""", num) で良い、と回答者さんは提案されています。 本質問では、上記executemanyが、executeに変わってしまっています。 それでは回答いただいた方法とは違ってしまうので、ダメなのではないでしょうか。 更に私自身が懸念していることとしては、num = re.findall(...正規表現)... で得られるデータが、正しくnumに展開されているか、と言うことです。確実に展開されていることが保証できるならそれで良いですけど。 何か間違って、4個に満たなかった場合はやはり例外(エラー)になり得ると思います。
bsdfan

2020/02/19 11:01

先の回答をしたものですが、ここではexecuteかexecutemanyかは本質的ではないです。(SQLの文がひとつなのでむしろexecuteをつかった方がいいです。) dodox86さん指摘のとおり、想定外のコードを受信したり、数値が4つない場合などの異常系の処理をちゃんといれたらいいと思います。
neko3378

2020/02/20 00:20

dodox86さん executemanyにするとcursorのところでエラーが出るようです。 pi@raspberrypi:~/web/cgi-bin $ python3 dat_ret.py Traceback (most recent call last): File "dat_ret.py", line 27, in <module> main() File "dat_ret.py", line 17, in main cursor.executemany("""INSERT INTO data (temp, press, hum, light) VALUES (%s, %s, %s, %s)""" ,num) File "/home/pi/.local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 237, in executemany self._get_db().encoding) File "/home/pi/.local/lib/python3.7/site-packages/MySQLdb/cursors.py", line 253, in _do_execute_many v = values % escape(next(args), conn) TypeError: not enough arguments for format string numに正しいデータが入ってるかの確認はprintで確認できてるのですが、毎回確実にできてるとは限らず、確実にできてないときにエラーが起きてるかもしれない、ということですよね? 提案していただいた『UnicodeDecodeError例外をexceptで捕捉すればスキップ』の中に4個に満たなかったときは入らないのでしょうか?
neko3378

2020/02/20 00:21

bsdfanさん ご指摘ありがとうございます。UnicodeDecodeError例外をexceptで捕捉すればスキップ、の処理だけでは足りないということでしょうか?
dodox86

2020/02/20 00:44

> numに正しいデータが入ってるかの確認はprintで確認できてるのですが、毎回確実にできてるとは限らず、確実にできてないときにエラーが起きてるかもしれない、ということですよね? そうです。 > 提案していただいた『UnicodeDecodeError例外をexceptで捕捉すればスキップ』の中に4個に満たなかったときは入らないのでしょうか? 参考にしたコードをちゃんと理解するためにも、今後の為にも、それはご自分で確認してみてください。 > UnicodeDecodeError例外をexceptで捕捉すればスキップ、の処理だけでは足りないということでしょうか? bsdfanさんへのお問い合わせですが、一部回答します。UnicodeDecodeErrorのみならず、本来であればエラーはその他にもいろいろ考えられます。 「DBの接続が突然切れた、シリアル回線が切れた」など。現状のコードでもっとも扱う頻度が高いのがcon.readlineでの受信データ取り込みに続いてのdecodeであり、質問者さんが提示したエラーがたまたまUnicodeDecodeErrorであったので、それをハンドリングするのは最低限必要だろうということで 追加したにすぎません。提案したコードはUnicodeDecodeErrorならスキップしてDBにINSERTしない、と言う程度のものです。必要ならもっと処理を追加、修正しなければならないでしょう。どれほど完全にプログラムを作りこむかにもよります。
neko3378

2020/02/20 01:12

bobox86さん なるほど!ちなみに今はこういうエラーが出ています。 Traceback (most recent call last): File "dat_ret.py", line 27, in <module> main() File "dat_ret.py", line 16, in main cursor.execute("""INSERT INTO data (temp, press, hum, light) VALUES (%s, %s, %s, %s)""" %(num[0], num[ 1], num[2], num[3]) ) IndexError: list index out of range ご指摘通り範囲外のデータが入ってしまってるせいかなと思います。このエラーも expect IndexError as e: の記述でスキップになりますか?
dodox86

2020/02/20 01:28

いや、ご自分で内容を判断して、試してください。エラーが起きるたびに質問する訳にもいきませんよね。 未知のものも含み、エラー(例外)が起きても成すすべが無いなら、(乱暴でコーディングの習慣としてお勧めできませんが)try: ~ except: のみで全ての例外を捕捉してスキップさせる方法もあります。理解した上で使ってください。 pythonですべての例外をキャッチし、詳細を表示させたい。- Stackoverflow 日本版 https://ja.stackoverflow.com/questions/6972/python%E3%81%A7%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E4%BE%8B%E5%A4%96%E3%82%92%E3%82%AD%E3%83%A3%E3%83%83%E3%83%81%E3%81%97-%E8%A9%B3%E7%B4%B0%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%95%E3%81%9B%E3%81%9F%E3%81%84/7008
neko3378

2020/02/20 01:46

expect エラーコード as e: でどのエラーコードにも対応になるのかどうか、ということをお聞きしたかっただけです。一つ一つのエラーは自分で調べて対処します。
dodox86

2020/02/20 01:52

例外・エラーについてリファレンス的に参考にされたいのであれば、pythonドキュメントにあたると良いと思います。 https://docs.python.org/ja/3/library/exceptions.html (ググると、2次、3次情報にあたって埒があかないので)
dodox86

2020/02/20 02:21

データが4個であることが条件なら、if len(num) == 4: ...でのチェックもありだと思います。そうでないと4個より多くてもOK扱いになってしまうので。
neko3378

2020/02/20 02:35

サイトの提示ありがとうございます! さっきから何回も実行してますが止まるエラーがIndexErrorとUnicodeDecodeErrorばかりなので、とりあえずはそのエラー2つに対応を絞ってみます。 そのifの記述を入れて再確認してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問