問題は自分の知識不足が原因
どうも、じぇいかわさきです。
昨日の各種センサーによるIoTに挑戦し、出力結果に問題が有ったことに対して、自分なりに調査してみました。
コメントを頂いた内容を元に、試行錯誤した結果、無事解決しました。
自分の知識不足が原因だったようです。
忘れないように備忘録としても残していきたいと思います。
コメントのご指摘はループ処理について
非常にありがたいことに、コードからおかしな部分についてご指摘をいただきました。
自分にとってコメントが頂けることは、最高に嬉しいことですね。しっかり内容を読んでいただいているという事ですから。
ご指摘の内容としては、time.sleep(30)書いてある位置が、whileのループ外になるので、30秒待たないで処理しているとのこと。
確かに、noteに載せたコードではwhileとtime.sleepが同じ位置になっているので、whileのループ外になっていることがわかります。
実は、これ自分がコピーした際に一律左詰めになってしまったので、後で動かしたのですが、その移動量がまちまちだったために、へんなコードになっていたようです。
オリジナルのコードを見ると、ちゃんと問題なくwhileのループ内にtime.sleepはおりました。
ハテ?それでは何が原因なんだろう。
もう一度最初からコードを眺めてみました。
実際のループの流れをチェックするが一番
さて、実際にどのように動いているのかを確認するためには、途中に何か細工をして、ループがどのように動いているのかを確認するのが一番ですね。
そこで、次のように最初のif文の後と、次のif文の後にインクリメント(一つ数が増える)する式を追加しました。
from gpiozero import DigitalInputDevice
import RPi.GPIO as GPIO
import dht11
import time
import datetime
# initialize GPIO
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)
# read data using pin 4,5
instance = dht11.DHT11(pin=4)
d0_input = DigitalInputDevice(5)
z = 1
try:
while True:
result = instance.read()
if result.is_valid():
print("Last valid input: " + str(datetime.datetime.now()))
print("Temperature: %-3.1f C" % result.temperature)
print("Humidity: %-3.1f %%" % result.humidity)
z = z + 1
print (z)
if (not d0_input.value):
print('Ground humidity: enough')
else:
print('Ground humidity: need')
z = z + 1
print(z)
time.sleep(10)
except KeyboardInterrupt:
print("Cleanup")
GPIO.cleanup()
このコードを実行して見えてきたことは、最初のzは1回でも、後のzだけで1つ増えていくことがあるのがわかりました。
つまり、こんな感じになるんです。
3
Ground humidity: enough
4
Ground humidity: enough
5
Ground humidity: enough
6
つまり、何らかの理由で最初の温湿度のデータをDHT11から引き取れなかった場合には、そこを飛ばしてしまうみたいなのです。
しかし、DHT11のデータ読み出しスピードは2秒間隔でなら十分読み出せるので、それが原因とは思えないんですよ。
従って、飛ばしてしまうのではなく、後段のif文が何らかの理由で優先されてしまい、そこでループしてしまうようなんです。
結果は意外な所だった
最初のご指摘内容に戻って、もう一度コードをよく眺めてみたんです。
Pythonのコードの記述ルールとして、有る処理をする場合には段落(インデント)をつける事が基本なんですね。
これは最初にご指摘された、whileとtimeの先頭の位置が同じであると、while内の処理でtimeが行われないことを意味しております。
という事は・・・・ ピンときました!
今回の問題は、if文が2つ並んであるのですが、このif文の先頭位置が同じになっているんです。
という事は、whileのループに入った時に、どちらのif文から処理するのかが不安定状態になっているのではないかと予測されます。
一般的な言語で行けば、最初のif文を処理して次のif文と思いますが、先程述べたように、Pythonは段落(インデント)をつけるのがルールなので、同じような判断が2つ有ると不安定になると自分で判断。
後段のif文を更に1段段落(インデント)を下げてみました。
コードとしては以下のようになります。
from gpiozero import DigitalInputDevice
import RPi.GPIO as GPIO
import dht11
import time
import datetime
# initialize GPIO
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)
# read data using pin 4,5
instance = dht11.DHT11(pin=4)
d0_input = DigitalInputDevice(5)
try:
while True:
result = instance.read()
if result.is_valid():
print("Last valid input: " + str(datetime.datetime.now()))
print("Temperature: %-3.1f C" % result.temperature)
print("Humidity: %-3.1f %%" % result.humidity)
if (not d0_input.value):
print('Ground humidity: enough')
else:
print('Ground humidity: need')
time.sleep(10)
except KeyboardInterrupt:
print("Cleanup")
GPIO.cleanup()
こうすることで、最初のif文を処理してから次のif文に行くように明確に処理順番を書いたのです。
そうしたらなんと!あの変な表示は一切なくなりました。
今回は、たくさん表示してエラー状態を確認しようとし、10秒毎にサンプリングするようにしました。
この状態で1時間連続で動かしてみても、問題なくデータを取り続けることができました。
今回の問題の結論は、自分のPythonに対する知識不足が最大の要因でした。
Pythonのプログラムは、処理の塊ごとに段落(インデント)をつけるという基本ルールを十分理解していなかったことです。
無事、温湿度と土壌湿度を測定することができました。
次は、日射量でも測定できたらやってみようかな。
じぇいかわさきです。生産技術者として35年、今まで培った経験とスキルを元に、ものづくりに関わる世の出来事に対して思ったことをホンネで書いてます。ノウハウやアイデアもありますよ。 また写真も全力で撮っています、気に入った写真があればサポートや感想をぜひお寄せください。