[수경재배기 자동 컨트롤러 제작] 6-3. 온도 및 습도 센서(DHT22, DS18B20)를 이용하여 GUI폼에 나타내기(ft. 현재 시간)

생활/수경재배|2022. 5. 9. 23:55

라즈베리파이 제로에 온도 및 습도 센서인 DHT22와

방수형 온도 센서인 DS18B20을 가지고

실내 온 습도 및 양액 온도를 체크하여 GUI폼에 나타나도록 함.

 

DHT22센서 인 경우는

2초마다 데이터를 읽어 들이는

엄청 느린 온 습도 센서임.

 

DTH11 같은 경우는 정밀도가 떨어진다고 하길래

가격 차이도 별로 안 나는 거 같아서 

그냥 DHT22 적용.

 

양액온도는 방수형인 DS18B20을 사용.

이거 말고 다른 방수형 온도센서를 봤는데

생각이 안 나네..

그 센서는 정밀도는 좋으나

아날로그 입출력만 지원이 되어서

패스하고 DS18B20으로 결정

 

그리고 귀차니즘 땜에

DHT22 케이스 있는 센서로 구입.

 

 

 

아두이노 라즈베리파이 DHT22 AAM2302B 온습도 모듈 : 송파 메이커스페이스

아두이노 라즈베리파이 DHT22 AAM2302B 온습도 모듈

smartstore.naver.com

터미널 모듈까지 같이 있으면 더 편했을련만.

 

DS18B20 같은 건 터미널 모듈도 같이 팔고 있어서 그걸로 구입.

 

 

DS18B20 방수형 온도센서 모듈 (연결용 터미널블럭모듈 포함) [SEN050007]

Temperature range: -50 ℃ - + 125 ℃ Applicable sensors: Waterproof DS18B20 temperature sensor Port: DAT (18B20 data) VCC (18B20 positive) GND (18B20 negative ) Platform: Arduino Raspberry Pi

www.devicemart.co.kr

 

둘다 전원은 라즈베리 내 전원 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 배치는 다 된 것으로 보임.