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

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

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

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

Python

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

1回答

839閲覧

累算結果をhtmlでwebブラウザに出力する方法

dyrobin

総合スコア13

Raspberry Pi

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

Python

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

2クリップ

投稿2021/06/05 00:58

ラズパイのGPIOに接続したタクトスイッチが押された回数をカウントし、
その入力回数をwebブラウザに出力するプログラムを書こうとしています。

しかし、下記エラーが出力されます。
TypeError: _count() takes exactly 1 argument (0 given)

countup4.py

1# -*- encoding:utf-8 -*- 2from flask import Flask, render_template 3import RPi.GPIO as GPIO 4import time 5import signal 6import sys 7 8app = Flask(__name__) 9 10GPIO.setmode(GPIO.BCM) 11GPIO.setup(27, GPIO.IN, GPIO.PUD_DOWN) 12 13count=0 14 15def main(): 16 try: 17 while True: 18 time.sleep(0.1) 19 except KeyboardInterrupt: 20 GPIO.cleanup() 21 22@app.route("/") 23def _count(hoge): 24 if GPIO.input(27): 25 global count 26 count += 1 27 return render_template("index1.html", testcount = count) 28 29GPIO.add_event_detect(27, GPIO.RISING, callback=_count, bouncetime=100) 30 31if __name__=='__main__': 32 main() 33 34def sigint_handler(signal, frame): 35 app.logger.debug("Closing") 36 GPIO.cleanup() 37 app.logger.debug("Closed") 38 sys.exit(0) 39 40signal.signal(signal.SIGINT, sigint_handler) 41app.run("0.0.0.0", debug=True)

index1.html

1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 2<html> 3<head> 4<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 5<title></title> 6</head> 7<body> 8Ch0 :{{ testcount }}<br> 9<br> 10<input type="button" value="reload" onclick="location.reload()"> 11</body> 12</html>

他には、webブラウザに出力するための関数と回数をカウントするための関数を分けて出力することも試みました。
以下コードです。

countup4.py

1# -*- encoding:utf-8 -*- 2 3from flask import Flask, render_template 4import RPi.GPIO as GPIO 5import time 6import signal 7import sys 8 9app = Flask(__name__) 10 11GPIO.setmode(GPIO.BCM) 12GPIO.setup(27, GPIO.IN, GPIO.PUD_DOWN) 13 14count=0 15 16def main(): 17 try: 18 while True: 19 time.sleep(0.1) 20 except KeyboardInterrupt: 21 GPIO.cleanup() 22 23 24def _count(hoge): 25 if GPIO.input(27): 26 global count 27 count += 1 28 print(str(count)+"回目") 29 time.sleep(0.2) 30 31 32@app.route("/") 33def index(): 34 return render_template("index1.html", testcount = count) 35 36GPIO.add_event_detect(27, GPIO.RISING, callback=_count, bouncetime=100) 37 38if __name__=='__main__': 39 main() 40 41def sigint_handler(signal, frame): 42 app.logger.debug("Closing") 43 GPIO.cleanup() 44 app.logger.debug("Closed") 45 sys.exit(0) 46 47signal.signal(signal.SIGINT, sigint_handler) 48app.run("0.0.0.0", debug=True) 49

webブラウザでの出力結果として、0が出力されます。
def indexのtestcount=countに、関数外で定義したcount=0が代入されているようです。

累算結果をwebブラウザに出力するための方法や考え方、修正点などをご教示頂けないでしょうか。

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

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

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

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

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

guest

回答1

0

ベストアンサー

TypeError: _count() takes exactly 1 argument (0 given)

というのは 「_count() という関数は 1つの引数を取るんだよ! (0 個が与えられました)」 みたいな意味です。

おそらく

GPIO.add_event_detect(27, GPIO.RISING, callback=_count, bouncetime=100)

の callback では _count が 引数無しで呼ばれるのでしょう。

なので、 2つ目の書き方で

def _count(): ...

と引数無しで関数を定義しておけば、ひとまずはクリアできるのではないかと思います。

ただし、Webページをリロードしないと count の値は反映されないとは思いますので、
もしリアルタイムに反映したければ、もうひと工夫必要かと思います。

投稿2021/06/05 03:29

mokemokechicken

総合スコア948

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

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

dyrobin

2021/06/05 04:02

ご回答ありがとうございます。 下記のようにコードを変更すればということでしょうか。 def _count(hoge)をdef _count()に修正しました。 しかしながら、TypeError: _count() takes no arguments (1 given)が出力されました。 def _countで計算した値を、def index関数に渡すことで解決しないでしょうか? その方法を教えて頂けないでしょうか。 def _count(): if GPIO.input(27): global count count += 1 print(str(count)+"回目") time.sleep(0.2) @app.route("/") def index(): return render_template("index1.html", testcount = count)
mokemokechicken

2021/06/05 06:26

> 下記のようにコードを変更すればということでしょうか。 > def _count(hoge)をdef _count()に修正しました。 そうですね、そういう意図で書きました。 > しかしながら、TypeError: _count() takes no arguments (1 given)が出力されました。 んー、見せてもらっているコードの中には 1箇所しか _count() が呼ばれるところはなさそうですが、 どこから呼ばれているんでしょうか。 そのエラーの前後にstack traceが出てないでしょうか? ... と書いていて、 https://tomosoft.jp/design/?p=8685 このサンプルコードを見てみると、callback関数 (`event_callback`) は1つの引数を取るのが正しそうですね。 ※ 2つ目のコードでも TypeError が出たのかと勘違いしていました。すみません。 ということは、 `def _count(hoge):` はそのままで良いですね。 2つ目の書き方での問題は > webブラウザでの出力結果として、0が出力されます。 ということなのですね。(今更、すみません)。 たぶんですが、最初は0が表示されて、 タクトスイッチ?を押してから、ブラウザをリロードすると1が表示されるんじゃないかと思いますが、 そうはならないでしょうか。 ※ callback が正しく呼ばれていれば、そういう挙動になると思います。 > def _countで計算した値を、def index関数に渡すことで解決しないでしょうか? > その方法を教えて頂けないでしょうか。 今は、global変数の count を経由して、そういう状態にはなっていると思います。 ただし、「WebServerを再起動するとcount=0に戻る」「WebServerが起動中じゃないとcountがUPしない」「ブラウザをリロードしないと、Webの表示が更新されない」という状況なのではないかと。
dyrobin

2021/06/05 08:21 編集

ご回答ありがとうございます。 たぶんですが、最初は0が表示されて、 タクトスイッチ?を押してから、ブラウザをリロードすると1が表示されるんじゃないかと思いますが、 そうはならないでしょうか。 → 残念ながら、その挙動すら動作できておりません。 0が表示され、タクトスイッチを押してリロードかけても値は変わりません。 どうも、10行目くらいのcount=0がwebブラウザ上に表示されているようです。 その証拠に、count=1に変更するど、 webブラウザ上も1が表示されるようになるからです。 タクトスイッチを押した際の出力も、 2回目、3回目…とカウントされます。 やはり、def indexがdef _countの値を拾えてないようです。 def countのプリント関数を削除し、returnで計算結果を戻り値で返すようなことで、def indexに値を渡すことができるのか?と考えましたが、うまくいきません。 そもそも考え方が間違っているかもしれませんが。。 その他ヒントなど頂けないでしょうか?
mokemokechicken

2021/06/05 08:08

例えば、以下のように print を入れたら、コンソールにどう表示されるか、、というのは気になります。 0のままだとすれば渡し方の問題、 1,2と上がっていくなら、Jinja2のTemplateが何かキャッシュしていたりするのか...? という気がします。 ``` @app.route("/") def index(): print("index(): count=" + str(count)) return render_template("index1.html", testcount = count) ```
mokemokechicken

2021/06/05 08:12 編集

もう一つは、こんな感じにした場合どうなるのか、、、が気になります。 @app.route のデコレータがあるから global 変数の count が キャプチャ(その時点の値でコピー)されているような気もしてきます。 ``` def get_count(): return count @app.route("/") def index(): cnt = get_count() print("index(): count=" + str(cnt)) return render_template("index1.html", testcount = cnt) ```
dyrobin

2021/06/06 00:24 編集

1回目 2回目 3回目 index():count=0 192.168.43.57 - - [06/Jun/2021 09:15:45] "GET / HTTP/1.1" 200 - index():count=0 ``` @app.route("/") def index(): print("index(): count=" + str(count)) return render_template("index1.html", testcount = count) ``` ⇒ 192.168.43.57 - - [06/Jun/2021 09:15:46] "GET / HTTP/1.1" 200 - index():count=0 192.168.43.57 - - [06/Jun/2021 09:15:47] "GET / HTTP/1.1" 200 - 0のままでした。 ``` def get_count(): return count @app.route("/") def index(): cnt = get_count() print("index(): count=" + str(cnt)) return render_template("index1.html", testcount = cnt) `` ⇒ index(): count=0 192.168.43.57 - - [06/Jun/2021 09:19:30] "GET / HTTP/1.1" 200 - index(): count=0 2つめの方法でも、変わらず0のままです。 やはり渡し方に問題があるようです。 その他解決策など頂けないでしょうか。
mokemokechicken

2021/06/06 00:42

例えば、以下のようなFlask App だと、 /up にアクセスした回数だけ、count が upされるんですよね。 ※ これは、そちらの環境でも再現されますか? 再現されるとすれば、今のコードと何が違うのか。 再現されないとすれば、どうしてなのか... というところが疑問になりますかね。 ```app.py # -*- encoding:utf-8 -*- from flask import Flask, render_template import sys app = Flask(__name__) print("reset counter") count=0 @app.route("/") def index(): print("count="+str(count)) return render_template("index.html", testcount = count) @app.route("/up") def up(): global count count += 1 print("count up="+str(count)) return render_template("index.html", testcount = count) app.run("0.0.0.0", debug=True) ``` ```templates/index.html testcount={{testcount}} ```
dyrobin

2021/06/06 03:08 編集

pi@raspberrypi:~/dev/flask/testtest $ python app.py reset counter * Serving Flask app "app" (lazy loading) * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: on * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) * Restarting with stat reset counter * Debugger is active! * Debugger PIN: 167-418-270 count up=1 192.168.43.57 - - [06/Jun/2021 11:40:13] "GET /up HTTP/1.1" 200 - count up=2 192.168.43.57 - - [06/Jun/2021 11:40:15] "GET /up HTTP/1.1" 200 - count up=3 192.168.43.57 - - [06/Jun/2021 11:40:16] "GET /up HTTP/1.1" 200 - count up=4 192.168.43.57 - - [06/Jun/2021 11:40:17] "GET /up HTTP/1.1" 200 - count up=5 192.168.43.57 - - [06/Jun/2021 11:40:41] "GET /up HTTP/1.1" 200 - ^Cpi@raspberrypi:~/dev/flask/testtest $ ⇒ 頂いたコードで、/upにアクセスするごとに回数をカウントすることができました。 上記が出力できました。 どうもプロセスを正しく終了できているかも問題になっているようでした。 socket.error: [Errno 98] Address already in use そのため、killでプロセスを削除をしました。 そして私のもともとのコードを実行したところ、下記出力を得ることができました。 ⇒ pi@raspberrypi:~/dev/flask/countup $ python countup4.py 1回目 2回目 3回目 ^C * Serving Flask app "countup4" (lazy loading) * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: on * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) * Restarting with stat 1回目 2回目 3回目 ^C * Debugger is active! * Debugger PIN: 167-418-270 index(): count=3 pi@raspberrypi:~/dev/flask/countup $ 192.168.43.57 - - [06/Jun/2021 11:31:11] "GET / HTTP/1.1" 200 - index(): count=3 192.168.43.57 - - [06/Jun/2021 11:31:11] "GET / HTTP/1.1" 200 - Error on request: Traceback (most recent call last): File "/usr/lib/python2.7/dist-packages/werkzeug/serving.py", line 270, in run_wsgi execute(self.server.app) File "/usr/lib/python2.7/dist-packages/werkzeug/serving.py", line 261, in execute write(data) File "/usr/lib/python2.7/dist-packages/werkzeug/serving.py", line 227, in write self.send_header(key, value) File "/usr/lib/python2.7/BaseHTTPServer.py", line 412, in send_header self.wfile.write("%s: %s\r\n" % (keyword, value)) IOError: [Errno 32] Broken pipe Error on request: Traceback (most recent call last): File "/usr/lib/python2.7/dist-packages/werkzeug/serving.py", line 270, in run_wsgi execute(self.server.app) File "/usr/lib/python2.7/dist-packages/werkzeug/serving.py", line 261, in execute write(data) File "/usr/lib/python2.7/dist-packages/werkzeug/serving.py", line 227, in write self.send_header(key, value) File "/usr/lib/python2.7/BaseHTTPServer.py", line 412, in send_header self.wfile.write("%s: %s\r\n" % (keyword, value)) IOError: [Errno 32] Broken pipe index(): count=3 192.168.43.57 - - [06/Jun/2021 11:31:33] "GET / HTTP/1.1" 200 - index(): count=3 192.168.43.57 - - [06/Jun/2021 11:31:35] "GET / HTTP/1.1" 200 - index(): count=3 どうにか一度は、回数をカウントできているようです。 webブラウザにも3が出力されました。 しかし、その後はスイッチを押したり更新をかけても、反映されることはありません。 IOError: [Errno 32] Broken pipe こちらのエラーはどのように解決すればよろしいでしょうか。
mokemokechicken

2021/06/06 03:17

あー、少し気になっていたんですが、 CTL+C を押して GPIO をリセットする、みたいなコードが何か影響しているんですかね。。。 1回目のCTL+Cは main() のループを抜けるのに使われていて、 2回目のCTL+Cは sigint_handler で処理されて、 sys.exit() していますよね。 ログでも 2回目の CTL+C で ^C * Debugger is active! * Debugger PIN: 167-418-270 index(): count=3 pi@raspberrypi:~/dev/flask/countup $ ← 親Processは停止している? となっていますしね。 その後、子プロセスはまだ生きていて、WebServerのリクエストを受け付けるけど、親Processが死んでいるから IOError になっているのかもしれません。 例えば、シンプルに GPIO.add_event_detect(27, GPIO.RISING, callback=_count, bouncetime=100) time.sleep(必要なwait秒数) app.run("0.0.0.0", debug=True) とした場合は、どうなるのでしょうか?
dyrobin

2021/06/06 22:27 編集

# -*- encoding:utf-8 -*- from flask import Flask, render_template import RPi.GPIO as GPIO import time import sys app = Flask(__name__) GPIO.setmode(GPIO.BCM) GPIO.setup(27, GPIO.IN, GPIO.PUD_DOWN) count=0 def _count(hoge): if GPIO.input(27): global count count += 1 print(str(count)+"回目") time.sleep(0.2) def get_count(): return count @app.route("/") def index(): print("index(): count=" + str(count)) return render_template("index1.html", testcount = count) GPIO.add_event_detect(27, GPIO.RISING, callback=_count, bouncetime=100) time.sleep(0.2) app.run("0.0.0.0", debug=True) ⇒ 上記実行で下記出力が得られました。 webブラウザでも、更新するごとにカウントした回数が表示できるようになりました。 数日に渡り、ご回答頂きまして、誠にありがとうございました。 ちなみに、 ・なぜ回数表示が2つずつ出力されるのでしょうか。 ・GPIO.cleanupやsys.exit(0)は必要ないのでしょうか。 ・なぜpsでプロセスをkillしなくても連続で実行できるのでしょうか。 もしよしければ、最後に教えて頂けましたら幸いです。 i@raspberrypi:~/dev/flask/countup $ python countup4.py * Serving Flask app "countup4" (lazy loading) * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: on * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 167-418-270 1回目 1回目 2回目 2回目 3回目 3回目 4回目 4回目 index(): count=4 192.168.43.57 - - [07/Jun/2021 07:10:40] "GET / HTTP/1.1" 200 - index(): count=4 192.168.43.57 - - [07/Jun/2021 07:10:41] "GET / HTTP/1.1" 200 - 5回目 5回目 index(): count=5 192.168.43.57 - - [07/Jun/2021 07:10:48] "GET / HTTP/1.1" 200 - index(): count=5 192.168.43.57 - - [07/Jun/2021 07:10:49] "GET / HTTP/1.1" 200 -
mokemokechicken

2021/06/07 00:26

とりあえず、うまくいったようで良かったです。が、私にはまだどうしてそうなったのか、という辺りが釈然とはしていません。。。 一つには GPIO のライブラリの挙動が関係していると思いますが、ソースコード(たぶん、これかなと https://sourceforge.net/p/raspberry-gpio-python/code/ci/default/tree/source/)を見ようとしてもC言語で書かれているのをwrapしている感じで、これまたすぐには読み解けてないです。 > ・GPIO.cleanupやsys.exit(0)は必要ないのでしょうか。 マニュアルをみる感じだと必要だと思います。 機械の状態がResetされないので、次回実行のときに問題が起こるような気がします。 ※ 次回実行の最初に cleanup してもいいかもしれませんが、ちょっとお行儀が悪いやり方かもしれません。 なので、 sigint_handler の辺りは最終的には残した方が良さそうです。 main() 周りは基本的には不要だと思います(が、これはもしかして、前回 cleanup し損ねたときの保険だったのでしょうか)。 > ・なぜ回数表示が2つずつ出力されるのでしょうか。 > ・なぜpsでプロセスをkillしなくても連続で実行できるのでしょうか。 この辺に謎を解く鍵がありそうです。 おそらく裏でプロセス生き残っている、みたいなケースが発生しているんじゃないでしょうか。 shell で ps axuwwwww とかしたら、昔のPython プロセスとか残っていたりしないでしょうか。 とりあえず、デバッグ用のprint に プロセスIDを出力するようなのを付け加えてみると、もしかしたら何かわかるかもしれないなぁ、、と考えていました。 os.getpid() で プロセスIDが取れるので、例えばひたすらそれを加えてみる感じで。 ``` import os ... 中略 print(str(os.getpid()) + ": index(): count=" + str(count)) ``` 別プロセスだと、count の値は共有されないので、今回の現象にも説明がつく気がします。 ※ プロセスが異なると、メモリ空間が異なるので、変数の値などは(プロセスが別れた後は)共有されない。 ※ まあ、そうなると、 sqlite など簡易なDBを経由して値を共有する感じでしょうか
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問