ラズベリーパイ3で『温度が上がったらエアコンのスイッチを押すやつ』を作る【DHT11で温度測定編】

テクノロジー

やりたいこと

部屋の温度が上がったらエアコンのスイッチを押す装置の製作

夏のある時期には、研究室のエアコンが3時間くらいで自動で切れてしまう。室温が上がりすぎると研究室にあるサーバーに影響が出てしまうので、自動でエアコンが切れても自動で付け直す装置をラズベリーパイで作ることで、サーバーを熱から守る。

手順

①温度センサー(DHT11)で部屋の温度を測定

②室温がある温度以上になったらサーボモータ(SG90)を回してエアコンのスイッチを押して室温を下げる

※このとき、すでについているエアコンを押して消してしまう事がないように、温度測定(もしくはサーボモータ起動)は温度上昇に合わせて一定間隔で行う。

今回の作業内容

今回は、温度センサーモジュールDHT11を用いた室温測定を行います。

基本的には、以下の記事を参考にさせていただきました。

ラズパイでDHT11温湿度センサーを作動する « osoyoo.com
RaspberryPiでDHT11センサーから温湿度データを取得 - Qiita
#**目的** RaspbeeryPiで温湿度データを取得する #**使用したもの** ・Raspberry Pi 3 MODEL B ・DHT11(温湿度センサー)。 ・ジャンプワイヤー×3本 <img src=&quot...

使用機器

・OSをインストールしたラズパイ(前回の記事で完了)

・DHT11(温度センサーモジュール)

created by Rinker
¥304 (2019/12/15 04:19:14時点 楽天市場調べ-詳細)

・DHT11とラズパイをつなぐジャンパーピン

・その他(ケーブル、マウス、ディスプレイなど)

ラズパイとDHT11を接続

DHT11のピンの番号を表向き左から1,2,3とすると、DHT11の1をラズパイの8番ピン(DPIO14)に、DHT11の2をラズパイの2番ピン(5V)に、DHT11の3をラズパイの14番ピン(GND)に接続する。

ラズパイのピン配置は以下を参考。

Raspberry Pi 2/3 B ピン配置 (40ピン) - 基礎からの IoT 入門
IoT に初めて取り組む人向けの超簡単な電子工作入門サイト。電子工作の基礎から Arduino を利用したプログラミング等をわかりやすく解説

DHT11にもいろいろ種類があるので、DHTのピンの順番は要確認。基本的には、3つのピンはデータ用、電力用、グランド(GND)。テスターか何かで確認しよう。

ソースコード

ラズパイでDHT11温湿度センサーを作動する « osoyoo.com

を参考に、以下のコードdht11-test.pyを書きました。

メインコード

# _____ _____ _____ __ __ _____ _____ 
#|     |   __|     |  |  |     |     |
#|  |  |__   |  |  |_   _|  |  |  |  |
#|_____|_____|_____| |_| |_____|_____|
#
# Use Raspberry Pi to get temperature/humidity from DHT11 sensor
#  
import time
import dht11
import RPi.GPIO as GPIO

#define GPIO 14 as DHT11 data pin
Temp_sensor=14
def main():
  # Main program block
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)       # Use BCM GPIO numbers
  # Initialise display
#  lcd_init()
    instance = dht11.DHT11(pin = Temp_sensor)

    while True:
        #get DHT11 sensor value
        result = instance.read()
        print('Temperature = ',result.temperature,'C','Humidity = ',result.humidity,'%')


        time.sleep(1)

if __name__ == '__main__':

    try:
      main()
    except KeyboardInterrupt:
      pass
#  finally:
#    lcd_byte(0x01, LCD_CMD)

ソースコードで14番ピンを指定しているので、DHT11とラズパイの14番ピンが接続されていることを確認してください。

また、DHT11を動かすには次のコードdht11.pyを同じディレクトリに置いておく必要があります。

DHT11を動かすためのコード

import time
import RPi.GPIO as GPIO

class DHT11Result:
	'DHT11 sensor result returned by DHT11.read() method'

	ERR_NO_ERROR = 0
	ERR_MISSING_DATA = 1
	ERR_CRC = 2

	error_code = ERR_NO_ERROR
	temperature = -1
	humidity = -1

	def __init__(self, error_code, temperature, humidity):
		self.error_code = error_code
		self.temperature = temperature
		self.humidity = humidity
		
	def is_valid(self):
		return self.error_code == DHT11Result.ERR_NO_ERROR

class DHT11:
	'DHT11 sensor reader class for Raspberry'
		
	__pin = 0

	def __init__(self, pin):
		self.__pin = pin
		
	def read(self):
		GPIO.setup(self.__pin, GPIO.OUT)

		# send initial high
		self.__send_and_sleep(GPIO.HIGH, 0.05)

		# pull down to low
		self.__send_and_sleep(GPIO.LOW, 0.02)

		# change to input using pull up
		GPIO.setup(self.__pin, GPIO.IN, 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):
		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 = 100 

		last = -1
		data = []
		while True:
			current = 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:
					break
		
		return 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 = 5

		state = STATE_INIT_PULL_DOWN

		lengths = [] # will contain the lengths of data pull up periods
		current_length = 0 # will contain the length of the previous period

		for i in range(len(data)):
			
			current = data[i]
			current_length += 1
				
			if state == STATE_INIT_PULL_DOWN:
				if current == 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 == 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 == 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 == 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 == 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:
					continue
					
		return lengths
		
	def __calculate_bits(self, pull_up_lengths):

		# find shortest and longest period
		shortest_pull_up = 1000
		longest_pull_up = 0
		
		for 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 = 0
		
		for 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 = 0
				
		return the_bytes
		
	def __calculate_checksum(self, the_bytes):
		return the_bytes[0] + the_bytes[1] + the_bytes[2] + the_bytes[3] & 255		

これで、実行すれば以下のように温度が表示されると思います。

実行

python3 dht11-test.py

ターミナルに次のように表示される

Temperature = 22 C Humidity = 54 %
Temperature = 0 C Humidity = 0 %
Temperature = 22 C Humidity = 53 %
Temperature = 0 C Humidity = 0 %
Temperature = 22 C Humidity = 53 %
Temperature = 0 C Humidity = 0 %
Temperature = 0 C Humidity = 0 %
Temperature = 0 C Humidity = 0 %
Temperature = 22 C Humidity = 53 %
Temperature = 0 C Humidity = 0 %
Temperature = 22 C Humidity = 53 %
Temperature = 0 C Humidity = 0 %
Temperature = 0 C Humidity = 0 %
Temperature = 0 C Humidity = 0 %
Temperature = 22 C Humidity = 53 %
Temperature = 0 C Humidity = 0 %
Temperature = 22 C Humidity = 53 %
Temperature = 0 C Humidity = 0 %
Temperature = 0 C Humidity = 0 %
Temperature = 0 C Humidity = 0 %

0度、0%が表示されることがよくありますが、データ取得周期がなんとかかんとかだった気がします。あまり問題にはならないので、とりあえずこのままで。

ちなみに、僕はLINE notifyを使って、ラインに温度の通知が来るようにしました。LINE notifyの使い方は、以下を参照(もちろん、上のコードは書き直す必要があります)。

PythonでLINEにメッセージを送る - Qiita
## はじめに 何番煎じかわかりませんが,Python x LINE NotifyでLINEにメッセージを送れるボットを作ったので,その備忘録です。 深層学習モデルの学習など,時間がかかる処理を回しているときに,その場を離れても進...

次回

DHT11を使って温度を習得できたので、次回はSG90(サーボモータ)の動作確認をします。

コメント

タイトルとURLをコピーしました