Raspberry Pi2を使って温度、湿度についてDHT11センサーによりpython3でグラフ化しモニタ
この記事は少し古いので、ソースコードにあるplt.draw()をplt.pause(.01)に変更する必要があります。詳細は「GrovePi+の温湿度センサー(DHT22)からのデータをmatplotlibでリアルタイムグラフ化」を見てください。
題名のとおりで結構簡単そうに思えますが、これがなかなかに難しかったのです。
一応、備忘録として書いておこうと思います。
まず、DHT11センサーをWebページ「簡単にRaspberryPi+DHT11で気温と湿度を通知するTweetBotを作る。」によりRaspberry Piに繋げます。写真を載せておきます。中央下水色がDHT11です。ソースを読めば解りますが4番ピンに繋げています。
まず、DHT11センサーの読み取りは同WebページにPython2.7.3のソースが紹介されています。当方はdht11.pyを、Python3.4.2で動作させました。Python3としてソフト上のエラーは出ませんが、dht11.pyは多分タイミングの関係でエラーが多くて0表示になり実用には耐えません。出来ればC言語でRaspberry Piにデーター化してPythonでグラフ化してモニタしたかったのですが当方の腕ではWebに紹介されている組み込み手法も理解できず、今のところこの方法は放置しています。
以下、dht11.pyのソースです。dht11.pyは次に示すdht11_monitor3.pyと同じフォルダー(ディレクトリ)に入れれば作動するようです。
import time
import RPiclass DHT11Result:
'DHT11 sensor result returned by DHT11.read() method'ERR_NO_ERROR = 0
ERR_MISSING_DATA = 1
ERR_CRC = 2error_code = ERR_NO_ERROR
temperature = -1
humidity = -1def __init__(self, error_code, temperature, humidity):
self.error_code = error_code
self.temperature = temperature
self.humidity = humiditydef is_valid(self):
return self.error_code == DHT11Result.ERR_NO_ERRORclass DHT11:
'DHT11 sensor reader class for Raspberry'__pin = 0
def __init__(self, pin):
self.__pin = pindef read(self):
RPi.GPIO.setup(self.__pin, RPi.GPIO.OUT)# send initial high
self.__send_and_sleep(RPi.GPIO.HIGH, 0.05)# pull down to low
self.__send_and_sleep(RPi.GPIO.LOW, 0.02)# change to input using pull up
RPi.GPIO.setup(self.__pin, RPi.GPIO.IN, RPi.GPIO.PUD_UP)# collect data into an array
data = self.__collect_input()# parse lengths of all data pull up periods
pull_up_lengths = self.__parse_data_pull_up_lengths(data)# if bit count mismatch, return error (4 byte data + 1 byte checksum)
if len(pull_up_lengths) != 40:
return DHT11Result(DHT11Result.ERR_MISSING_DATA, 0, 0)# calculate bits from lengths of the pull up periods
bits = self.__calculate_bits(pull_up_lengths)# we have the bits, calculate bytes
the_bytes = self.__bits_to_bytes(bits)# calculate checksum and check
checksum = self.__calculate_checksum(the_bytes)
if the_bytes[4] != checksum:
return DHT11Result(DHT11Result.ERR_CRC, 0, 0)# ok, we have valid data, return it
return DHT11Result(DHT11Result.ERR_NO_ERROR, the_bytes[2], the_bytes[0])def __send_and_sleep(self, output, sleep):
RPi.GPIO.output(self.__pin, output)
time.sleep(sleep)def __collect_input(self):
# collect the data while unchanged found
unchanged_count = 0# this is used to determine where is the end of the data
max_unchanged_count = 100last = -1
data = []
while True:
current = RPi.GPIO.input(self.__pin)
data.append(current)
if last != current:
unchanged_count = 0
last = current
else:
unchanged_count += 1
if unchanged_count > max_unchanged_count:
breakreturn data
def __parse_data_pull_up_lengths(self, data):
STATE_INIT_PULL_DOWN = 1
STATE_INIT_PULL_UP = 2
STATE_DATA_FIRST_PULL_DOWN = 3
STATE_DATA_PULL_UP = 4
STATE_DATA_PULL_DOWN = 5state = STATE_INIT_PULL_DOWN
lengths = [] # will contain the lengths of data pull up periods
current_length = 0 # will contain the length of the previous periodfor i in range(len(data)):
current = data[i]
current_length += 1if state == STATE_INIT_PULL_DOWN:
if current == RPi.GPIO.LOW:
# ok, we got the initial pull down
state = STATE_INIT_PULL_UP
continue
else:
continue
if state == STATE_INIT_PULL_UP:
if current == RPi.GPIO.HIGH:
# ok, we got the initial pull up
state = STATE_DATA_FIRST_PULL_DOWN
continue
else:
continue
if state == STATE_DATA_FIRST_PULL_DOWN:
if current == RPi.GPIO.LOW:
# we have the initial pull down, the next will be the data pull up
state = STATE_DATA_PULL_UP
continue
else:
continue
if state == STATE_DATA_PULL_UP:
if current == RPi.GPIO.HIGH:
# data pulled up, the length of this pull up will determine whether it is 0 or 1
current_length = 0
state = STATE_DATA_PULL_DOWN
continue
else:
continue
if state == STATE_DATA_PULL_DOWN:
if current == RPi.GPIO.LOW:
# pulled down, we store the length of the previous pull up period
lengths.append(current_length)
state = STATE_DATA_PULL_UP
continue
else:
continuereturn lengths
def __calculate_bits(self, pull_up_lengths):
# find shortest and longest period
shortest_pull_up = 1000
longest_pull_up = 0for i in range(0, len(pull_up_lengths)):
length = pull_up_lengths[i]
if length < shortest_pull_up:
shortest_pull_up = length
if length > longest_pull_up:
longest_pull_up = length# use the halfway to determine whether the period it is long or short
halfway = shortest_pull_up + (longest_pull_up - shortest_pull_up) / 2
bits = []for i in range(0, len(pull_up_lengths)):
bit = False
if pull_up_lengths[i] > halfway:
bit = True
bits.append(bit)return bits
def __bits_to_bytes(self, bits):
the_bytes = []
byte = 0for i in range(0, len(bits)):
byte = byte << 1
if (bits[i]):
byte = byte | 1
else:
byte = byte | 0
if ((i + 1) % 8 == 0):
the_bytes.append(byte)
byte = 0return the_bytes
def __calculate_checksum(self, the_bytes):
return the_bytes[0] + the_bytes[1] + the_bytes[2] + the_bytes[3] & 255
あと、matplotlibはPythonでグラフを描画するときなどに使われる標準的なライブラリで「りんごがでている」に入門の説明が載っています。しかし、参考にしたのは「電子工作速報>Arduino>【Python】Arduinoで測定した温度をグラフ化」です。日本語化についてはURLをひかえていなかったので載せられません申し訳ないところです。「Add/Remove Software」からVL-Gothicを導入してmatplotlibには反映させています。
最終的にはy軸を2軸化して読み取りをC言語化したいところですが、とりあえず気温と湿度が示せる形で備忘録としたいと思います。
以下は、dht11_monitor3.pyのソースです。
# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
import pygame
from pygame.locals import *
import serial
import sys
import time
import datetime
import RPi.GPIO as GPIO
import dht11
from matplotlib.font_manager import FontProperties#日本語化に必要
# initialize GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.cleanup()
# read data using pin 4
instance = dht11.DHT11(pin=4)font_path = '/usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf'#日本語化
font_prop = FontProperties(fname=font_path)
plt.rcParams['font.family'] = font_prop.get_name()def main():
temps = [0]*100 # 気温格納
humis = [0]*100 # 湿度格納
t = np.arange(0,100,1)
plt.ion()
pygame.init() # Pygameを初期化
screen = pygame.display.set_mode((300, 100)) # 画面作成(横300×100)
pygame.display.set_caption("傾斜角度") # タイトルバー
font = pygame.font.Font(None, 50) # 文字の設定while True:
screen.fill((0,0,0)) # 画面のクリア
result = instance.read() # DHT11インスタンスの作成
temp = str(result.temperature) # 気温を文字列にする
humi = str(result.humidity) # 湿度を文字列にする
text = font.render(temp + "[℃]" + humi+"[%]", False, (255,255,255)) # 表示する文字の設定
screen.blit(text, (10, 10)) # レンダ,表示位置
pygame.display.flip() # 画面を更新して、変更を反映
# 温度データのリスト更新
temps.pop(99)
humis.pop(99)
temps.insert(0,float(temp)) # 文字列にしたデータを少数を含む数値に変換
humis.insert(0,float(humi))
# グラフ表示設定
line1, = plt.plot(t*2.25+1.125, temps, 'r-',label="気温[℃]") # X軸を2秒になるように調整、Y軸更新
line1.set_ydata(temps)
line2, = plt.plot(t*2.25+1.125, humis, 'b-',label="湿度[%]") # X軸を2秒になるように調整、Y軸更新
line2.set_ydata(humis)
plt.title("Real-time 気温 湿度")
plt.xlabel("Time [s]")
plt.ylabel("気温 [℃] 湿度[%]")
plt.legend()
plt.grid()
plt.xlim([1,200])
plt.ylim([0,100])
plt.draw()
plt.clf()
for event in pygame.event.get():
# 終了ボタンが押されたら終了処理
if event.type == QUIT:
pygame.quit()
plt.close()
sys.exit()if __name__ == '__main__':
main()
各ソースには必要のないimportも含まれているかもしれませんがそこはご勘弁を願います。
<当ブログの関係記事>
Raspberry Piを使って温度、湿度についてDHT11センサーによりリアルタイムグラフ化(三軸)(その2)
Raspberry Piを使ってMCP3208によりAD変換しリアルタイムグラフ化
« 「日本の武器で滅びる中華人民共和国」兵頭 二十八著を読んで | トップページ | 北朝鮮のミサイル発射に全漁連が陳情したことに思う »
「パソコン・インターネット」カテゴリの記事
- logicool M720 Triathlon マルチデバイスマウスが故障(2022.08.20)
- UbuntuのFirefoxだと雑音が入る(未解決)(2022.02.13)
- イントロンのブログが60,000カウントを達成(2022.01.13)
- GrovePi+をRaspberry Pi 4に導入してみた(上手くゆかなかった)(2021.12.26)
- Raspberry Pi 4でVLCメディアプレイヤー起動時にフリーズがなぜか解消(2021.12.20)
« 「日本の武器で滅びる中華人民共和国」兵頭 二十八著を読んで | トップページ | 北朝鮮のミサイル発射に全漁連が陳情したことに思う »


コメント