[수경재배기 자동 컨트롤러 제작] 6-3. 온도 및 습도 센서(DHT22, DS18B20)를 이용하여 GUI폼에 나타내기(ft. 현재 시간)
라즈베리파이 제로에 온도 및 습도 센서인 DHT22와
방수형 온도 센서인 DS18B20을 가지고
실내 온 습도 및 양액 온도를 체크하여 GUI폼에 나타나도록 함.
DHT22센서 인 경우는
2초마다 데이터를 읽어 들이는
엄청 느린 온 습도 센서임.
DTH11 같은 경우는 정밀도가 떨어진다고 하길래
가격 차이도 별로 안 나는 거 같아서
그냥 DHT22 적용.
양액온도는 방수형인 DS18B20을 사용.
이거 말고 다른 방수형 온도센서를 봤는데
생각이 안 나네..
그 센서는 정밀도는 좋으나
아날로그 입출력만 지원이 되어서
패스하고 DS18B20으로 결정
그리고 귀차니즘 땜에
DHT22 케이스 있는 센서로 구입.
터미널 모듈까지 같이 있으면 더 편했을련만.
DS18B20 같은 건 터미널 모듈도 같이 팔고 있어서 그걸로 구입.
둘다 전원은 라즈베리 내 전원 3.3v포트에 먹임.
신호는
18B20온도센서(1-wire): GPIO 4
DHT22 온도센서: GPIO 17
연결
이제 본격적으로 시작.
그 전에 프로그래밍 하기 전에
Rpi.GPIO 라이브러리가 설치되어 있어야 함.
설치되어 있으면 패스
없으면 apt-get 으로 설치.
sudo apt-get install python-dev
sudo apt-get install python-rpi.gpio
gpiozero 라는 라이브러리도 있는데
이건 생소해서 패스.
사실, 다 생소하지만...
그리고 라즈베리파이 환경설정에서
1-wire 를 활성화 시킴.
/boot/config.txt 파일을 열어서
dtoverlay=w1-gpio 추가후 저장
그리고 modprobe 명령어를 이용하여
w1 관련 모듈 불러옴
sudo modprobe w1-gpio
sudo modprobe w1-therm
/sys/bus/w1/devices/w1_bus_mater1/w1_master_slave_count를
열어보면 현재 센서 연결 갯수를 알 수 있음.
/sys/bus/w1/devices/w1_bus_master1/w1_master_slaves에서
센서 아이디를 알 수 있음.
보통 28-xxxxxx 로 나타남.
혹은
/sys/bus/w1/devices/에서
ls로 목록을 보면 28-xxxxxx디렉토리가 나타남.
이렇게 센서 아이디랑 갯수를 알 수 있음.
일단 저렇게 나타나면, 인식은 제대로 된 것임.
/sys/bus/w1/devices/28-xxxxx/w1_slave를
열어보면 온도를 알 수 있음
9a 01 55 05 7f a5 a5 66 18 : crc=18 YES
9a 01 55 05 7f a5 a5 66 18 t=25625
여기서 두 번째 줄에 보면 t=25625라고 있는데
25.625도 라는 의미임.
그리고 온 습도 출력 센서인 DHT22를
사용하기 위해 adafruit_dht라는
라이브러리 설치
pip3 install adafruit-ciruitpython-dat
sudo apt-get install libgpiod2
암튼,
이제 프로그래밍 시작.
import time
import RPi.GPIO as GPIO
import os
import glob
import subprocess
import board
import adafruit_dht
#import rpi_backlight as bl
A="N/A"
#DS=27 #DS18B20 전원으로 사용할 핀번호(오류 발생시)
GPIO.cleanup() #비정상 종료후 재실행시 GPIO 초기화
#GPIO.setmode(GPIO.BCM)
#GPIO.setup(DS,GPIO.OUT) #DS18B20 전원핀으로 설정
#GPIO.output(DS,GPIO.HIGH) #Ds18B20 전원 활성화 초기값
#b1v=IntVar()
dhtDevice=adafruit_dht.DHT22(board.D17) #DHT22센서 핀 번호 설정
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
base_dir='/sys/bus/w1/devices/'
device_folder=glob.glob(base_dir+'28*')[0]
device_file=device_folder+'/w1_slave'
#tsd='/sys/bus/w1/devices/28-3c01e076d1d3/w1_slave'
#def read_rom():
# name_file=device_folder+'/name'
# f=open(name_file,'r')
# return f.readline()
def read_temp_raw():
# f=open(device_file,'r')
#f=open(tsd,'r')
# lines=f.readlines()
# f.close()
# return lines
catdata = subprocess.Popen(['cat',device_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out,err = catdata.communicate()
out_decode = out.decode('utf-8')
lines = out_decode.split('\n')
return lines
def read_temp():
lines=read_temp_raw()
if lines[0].strip()[-3:]!='YES':
lines=read_temp_raw()
equals_pos=-1 #-1값을 주어 888.8 출력
else:
equals_pos=lines[1].find('t=')
if equals_pos!=-1:
temp_string=lines[1][equals_pos+2:]
temp_c=float(temp_string)/1000.0
#temp_f=temp_c*9.0/5.0+32.0
#return temp_c #temp_f
return temp_c
else:
temp_c=888.8
# GPIO.cleanup(DS)
# GPIO.setmode(GPIO.BCM) #DS18B20 DS핀을 전원으로 사용시 제어
# GPIO.setup(DS,GPIO.OUT)
# GPIO.output(DS,GPIO.LOW)
# time.sleep(1)
# GPIO.output(DS,GPIO.HIGH)
# label2.after(1000, read_temp)
return temp_c
#print('rom'+read_rom())
def nowtemp():
tpc='{0:3.1f}℃'.format(read_temp())
#tpc=DS18B20.get_temperature() #℃출력
#tpf=DS18B20.get_temperature(Unit.DEGREES_F)
#tpc_f=DS18B20.get_temperatures([Unit.DEGREES_C, Unit.DEGREES_F, Unit.KELVIN])
#tpc='{0:3.1f}℃'.format(DS18B20.get_temperature())
label2.configure(text=tpc)
label2.after(1000, nowtemp)
#DHT=D17
def dhttemp():
#dhtDevice=adafruit_dht.DHT22(board.D17,use_pulseio=False)
try:
#dhtDevice.measure()
temperature_c=dhtDevice.temperature
#temperature_f=temperature_c*(9/5)+32
humidity=dhtDevice.humidity
tpc='{0:3.1f}℃'.format(temperature_c)
tph='{0:3.1f}%'.format(humidity)
label1.configure(text=tpc)
label5.configure(text=tph)
label6t.configure(text='')
except RuntimeError as error:
#print(error.args[0])
label6t.configure(text=error.args[0])
#time.sleep(2.0)
#continue
except Exception as error:
dhtDevice.exit()
raise error
label5.after(2000, dhttemp)
def nowtime():
ntime=time.strftime("%H시 %M분")
#ntime1=int(time.strftime('%H%M'))
ntimelabel.configure(text=ntime, font=('DJB Get Digital',35))
ntimelabel.after(200, nowtime)
#온도 측정
label1=ttk.Label(iotwin,text=A,relief='sunken',anchor=E,font=('DJB Get Digital',40))
label1t=ttk.Label(iotwin,text='실내 온도', anchor=CENTER,font=('나눔바른펜OTF',35))
label2=ttk.Label(iotwin,text=A,relief='sunken',anchor=E,font=('DJB Get Digital',40))
label2t=ttk.Label(iotwin,text='양액 온도', anchor=CENTER,font=('나눔바른펜OTF',35))
label3=ttk.Label(iotwin,text=A,relief='sunken',anchor=E,font=('DJB Get Digital',40))
label3t=ttk.Label(iotwin,text='EC', anchor=CENTER,font=('나눔바른펜OTF',35))
label4=ttk.Label(iotwin,text=A,relief='sunken',anchor=E,font=('DJB Get Digital',40))
label4t=ttk.Label(iotwin,text='PH', anchor=CENTER,font=('나눔바른펜OTF',35))
label5t=ttk.Label(iotwin,text='습도', anchor=CENTER,font=('나눔바른펜OTF',35))
label5=ttk.Label(iotwin,text=A,relief='sunken',anchor=E,font=('DJB Get Digital',40))
label6t=ttk.Label(iotwin, text='', anchor=CENTER, font=('나눔바른펜OTF',20))
#b1=ttk.Scale(iotwin,variable=b1v,command=backl,orient='horizontal',from_=0,to =1,length=50)
label1.place(x=50,y=70, width=180, height=70)
label1t.place(x=50,y=0, width=180, height=70)
label2.place(x=260,y=70, width=180, height=70)
label2t.place(x=260,y=0, width=180, height=70)
label3.place(x=50,y=210, width=180, height=70)
label3t.place(x=50,y=140, width=180, height=70)
label4.place(x=260,y=210, width=180, height=70)
label4t.place(x=260,y=140, width=180, height=70)
label5t.place(x=500,y=70, width=90, height=70)
label5.place(x=600, y=70, width=180, height=70)
label6t.place(x=500,y=200, width=500, height=40)
#b1.place(x=500, y=400, width=60, height=30)
#b1.get(1)
nowtime()
nowtemp()
#read_temp()
dhttemp()
간단하게 설명하자면
아까 설치한 Rpi.GPIO와 adafruit_dht, 그리고
adafruit_dht에 딸려있는 board를 import 시킴.
그리고 w1 관련 모듈을 불러오기 위해 OS를 import 시킴.
그리고 DHT22 온 습도계를 위해
board, adafruit_dht를 import 시킴.
import RPi.GPIO as GPIO
import os
import glob
import subprocess
import board
import adafruit_dht
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
base_dir='/sys/bus/w1/devices/'
device_folder=glob.glob(base_dir+'28*')[0]
device_file=device_folder+'/w1_slave'
#tsd='/sys/bus/w1/devices/28-3c01e076d1d3/w1_slave'
DS18b20센서 인식
위에 DS18b20 센서 온도 값을 설명할 때
YES라는 문구가 없을시
데이터를 제대로 읽어들이지 못했다는 의미 이므로
equals_pos 변수에 -1 값을 줘서
888로 출력하게 함.
YES라는 문구 발견시
데이터를 제대로 읽어들였다는 의미로
equals_pos 변수에 t=xxxx값을 줌.
거기서 1000으로 나눠서 ℃ 로 나타냄.
그리고 1초마다 label2로 온도 표시.
DHT22 센서는
2초마다 데이터를 읽도록 함.
만약 데이터를 제대로 못 읽을 시
관련 문구 표시후 다시 시도.
* 생각보다 잘 못읽어들임. *
nottime()함수는
이전 글에 현재 시간 label 작성한 소스에
현재 시간 label 옆에 현재 시간이 나타나게 함.
그리고 실내온도, 양액온도등
위젯 배치등 설명은 생략(이전 게시글 참조)
이것으로 대충 GUI label 배치는 다 된 것으로 보임.
'생활 > 수경재배' 카테고리의 다른 글