라즈베리파이 보드 상에서 동작하는 미세먼지 센서 파이썬 코드를 작성하였다
MQTT 프로토콜 관점으로 본다면 publisher의 역할을 수행 한다
미센 먼지 센서 (모델명 PMS 7003)로부터 읽혀진 데이타는 파이썬 스트링으로 변경 후 MQTT 브로커로 송신된다
"""
* PMS7003 데이터 수신 프로그램
* 수정 : 2018. 11. 19
* 제작 : eleparts 부설연구소
* SW ver. 1.0.2
> 관련자료
파이썬 라이브러리
https://docs.python.org/3/library/struct.html
점프 투 파이썬
https://wikidocs.net/book/1
PMS7003 datasheet
http://eleparts.co.kr/data/_gextends/good-pdf/201803/good-pdf-4208690-1.pdf
"""
import paho.mqtt.client as mqtt
import serial
import struct
import time
from datetime import datetime
class PMS7003(object):
# PMS7003 protocol data (HEADER 2byte + 30byte)
PMS_7003_PROTOCOL_SIZE = 32
# PMS7003 data list
HEADER_HIGH = 0 # 0x42
HEADER_LOW = 1 # 0x4d
FRAME_LENGTH = 2 # 2x13+2(data+check bytes)
DUST_PM1_0_CF1 = 3 # PM1.0 concentration unit μ g/m3(CF=1,standard particle)
DUST_PM2_5_CF1 = 4 # PM2.5 concentration unit μ g/m3(CF=1,standard particle)
DUST_PM10_0_CF1 = 5 # PM10 concentration unit μ g/m3(CF=1,standard particle)
DUST_PM1_0_ATM = 6 # PM1.0 concentration unit μ g/m3(under atmospheric environment)
DUST_PM2_5_ATM = 7 # PM2.5 concentration unit μ g/m3(under atmospheric environment)
DUST_PM10_0_ATM = 8 # PM10 concentration unit μ g/m3 (under atmospheric environment)
DUST_AIR_0_3 = 9 # indicates the number of particles with diameter beyond 0.3 um in 0.1 L of air.
DUST_AIR_0_5 = 10 # indicates the number of particles with diameter beyond 0.5 um in 0.1 L of air.
DUST_AIR_1_0 = 11 # indicates the number of particles with diameter beyond 1.0 um in 0.1 L of air.
DUST_AIR_2_5 = 12 # indicates the number of particles with diameter beyond 2.5 um in 0.1 L of air.
DUST_AIR_5_0 = 13 # indicates the number of particles with diameter beyond 5.0 um in 0.1 L of air.
DUST_AIR_10_0 = 14 # indicates the number of particles with diameter beyond 10 um in 0.1 L of air.
RESERVEDF = 15 # Data13 Reserved high 8 bits
RESERVEDB = 16 # Data13 Reserved low 8 bits
CHECKSUM = 17 # Checksum code
# header check
def header_chk(self, buffer):
if (buffer[self.HEADER_HIGH] == 66 and buffer[self.HEADER_LOW] == 77):
return True
else:
return False
# chksum value calculation
def chksum_cal(self, buffer):
buffer = buffer[0:self.PMS_7003_PROTOCOL_SIZE]
# data unpack (Byte -> Tuple (30 x unsigned char <B> + unsigned short <H>))
chksum_data = struct.unpack('!30BH', buffer)
chksum = 0
for i in range(30):
chksum = chksum + chksum_data[i]
return chksum
# checksum check
def chksum_chk(self, buffer):
chk_result = self.chksum_cal(buffer)
chksum_buffer = buffer[30:self.PMS_7003_PROTOCOL_SIZE]
chksum = struct.unpack('!H', chksum_buffer)
if (chk_result == chksum[0]):
return True
else:
return False
# protocol size(small) check
def protocol_size_chk(self, buffer):
if(self.PMS_7003_PROTOCOL_SIZE <= len(buffer)):
return True
else:
return False
# protocol check
def protocol_chk(self, buffer):
if(self.protocol_size_chk(buffer)):
if(self.header_chk(buffer)):
if(self.chksum_chk(buffer)):
return True
else:
print("Chksum err")
else:
print("Header err")
else:
print("Protol err")
return False
# unpack data
# <Tuple (13 x unsigned short <H> + 2 x unsigned char <B> + unsigned short <H>)>
def unpack_data(self, buffer):
buffer = buffer[0:self.PMS_7003_PROTOCOL_SIZE]
# data unpack (Byte -> Tuple (13 x unsigned short <H> + 2 x unsigned char <B> + unsigned short <H>))
data = struct.unpack('!2B13H2BH', buffer)
return data
def print_serial(self, buffer):
chksum = self.chksum_cal(buffer)
data = self.unpack_data(buffer)
print ("============================================================================")
print ("Header : %c %c \t\t | Frame length : %s" % (data[self.HEADER_HIGH], data[self.HEADER_LOW], data[self.FRAME_LENGTH]))
print ("PM 1.0 (CF=1) : %s\t | PM 1.0 : %s" % (data[self.DUST_PM1_0_CF1], data[self.DUST_PM1_0_ATM]))
print ("PM 2.5 (CF=1) : %s\t | PM 2.5 : %s" % (data[self.DUST_PM2_5_CF1], data[self.DUST_PM2_5_ATM]))
print ("PM 10.0 (CF=1) : %s\t | PM 10.0 : %s" % (data[self.DUST_PM10_0_CF1], data[self.DUST_PM10_0_ATM]))
print ("0.3um in 0.1L of air : %s" % (data[self.DUST_AIR_0_3]))
print ("0.5um in 0.1L of air : %s" % (data[self.DUST_AIR_0_5]))
print ("1.0um in 0.1L of air : %s" % (data[self.DUST_AIR_1_0]))
print ("2.5um in 0.1L of air : %s" % (data[self.DUST_AIR_2_5]))
print ("5.0um in 0.1L of air : %s" % (data[self.DUST_AIR_5_0]))
print ("10.0um in 0.1L of air : %s" % (data[self.DUST_AIR_10_0]))
print ("Reserved F : %s | Reserved B : %s" % (data[self.RESERVEDF],data[self.RESERVEDB]))
print ("CHKSUM : %s | read CHKSUM : %s | CHKSUM result : %s" % (chksum, data[self.CHECKSUM], chksum == data[self.CHECKSUM]))
print ("============================================================================")
mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,"python_pub") # puclisher 이름
mqttc.connect("test.mosquitto.org", 1883)
#from PMS7003 import PMS7003
dust = PMS7003()
# Baud Rate
Speed = 9600
# UART / USB Serial
USB0 = '/dev/ttyUSB0'
UART = '/dev/ttyAMA0'
# USE PORT
SERIAL_PORT = USB0
#serial setting
ser = serial.Serial(port = SERIAL_PORT, baudrate = Speed, timeout = 1)
interval = 60 # 60초에 1건씩 데이타 송신
previousTime = 0;
# mqtt data
device_id = 1031
location_id = 1968
device_type_id = 201
protocol_id = 12643
while True:
currentTime = time.time()
if (currentTime - previousTime >= interval) :
previousTime = currentTime;
ser.flushInput()
buffer = ser.read(1024)
if(dust.protocol_chk(buffer)):
data = dust.unpack_data(buffer)
# dust.print_serial(buffer) # all data?
print ("PMS 7003 fine dust data")
fine_dust_struct = {
'device_id' : device_id,
'location_id' : location_id,
'device_type_id' : device_type_id,
'protocol_id' : protocol_id,
'sensor_data' :
{'concentration' :
{
'PM_1.0' : data[dust.DUST_PM1_0_ATM], #concentration (ug/m**3) with diameter 0.3~1.0 micrometer
'PM_2.5' : data[dust.DUST_PM2_5_ATM], #concentration (ug/m**3) with diameter 1.0~2.5 micrometer
'PM_10.0': data[dust.DUST_PM10_0_ATM] #concentration (ug/m**3) with diameter 2.5~10.0 micrometer
},
'number_of_particle' :
{
'DUST_AIR_0_3' : data[dust.DUST_AIR_0_3], # indicates the number of particles with diameter beyond 0.3 um in 0.1 L of air
'DUST_AIR_0_5' : data[dust.DUST_AIR_0_5], # indicates the number of particles with diameter beyond 0.5 um in 0.1 L of air
'DUST_AIR_1_0' : data[dust.DUST_AIR_1_0], # indicates the number of particles with diameter beyond 10 um in 0.1 L of air
'DUST_AIR_2_5' : data[dust.DUST_AIR_2_5], # indicates the number of particles with diameter beyond 25 um in 0.1 L of air
'DUST_AIR_5_0' : data[dust.DUST_AIR_5_0], # indicates the number of particles with diameter beyond 50 um in 0.1 L of air
'DUST_AIR_10_0': data[dust.DUST_AIR_10_0] # indicates the number of particles with diameter beyond 100 um in 0.1 L of air
}
},
'create_date_device' : datetime.now().strftime("%Y:%m:%d %H:%M:%S KST")
}
mqtt_msg = str(fine_dust_struct)
print(mqtt_msg)
mqttc.publish("dpc/data/fine_dust", mqtt_msg) # topic, message
else:
print("DATA read fail...")
ser.close()
'Life Work' 카테고리의 다른 글
[파이썬] 글로벌 변수 vs 로컬 변수 (0) | 2024.07.15 |
---|---|
[IT 서비스] 모스키토 플랫폼 (0) | 2024.07.13 |
[IT 서비스] MQTT 프로토콜 개요 (0) | 2024.07.13 |
[IT 서비스] 아두이노 기반 온도,습도 센서 - 에더넷, 와이파이 통신 활용 (0) | 2024.07.12 |
[IT 서비스] End To End 데이터 파이프 라인 구축 (0) | 2024.06.28 |