324 lines
No EOL
11 KiB
Text
324 lines
No EOL
11 KiB
Text
#
|
|
# based on three things:
|
|
# 1 - CCS811_RPi class usage example
|
|
# by Petr Lukas V1
|
|
# 2 - I2C_LCD_driver
|
|
# Compiled, mashed and generally mutilated 2014-2015 by Denis Pleic
|
|
# 3 - BME680
|
|
# Pimoroni Library, installed via pip https://shop.pimoroni.com/products/bme680
|
|
|
|
from datetime import datetime
|
|
import requests
|
|
import time
|
|
import uuid
|
|
import bme680
|
|
from CCS811_RPi import CCS811_RPi
|
|
import I2C_LCD_driver
|
|
import paho.mqtt.client as paho
|
|
|
|
broker="cosmicpidata.mooo.com"
|
|
port=1883
|
|
mqtt_ok=0
|
|
|
|
url = "http://www.google.com"
|
|
timeout = 600
|
|
|
|
|
|
def on_publish(client,userdata,result):
|
|
print("Data published to MQTT server")
|
|
pass
|
|
|
|
def on_connect(client,userdata,flags,rc):
|
|
if rc==0:
|
|
print("connected ok")
|
|
else:
|
|
print("mqtt connection failed")
|
|
|
|
def on_disconnect(client,userdata,rc):
|
|
print("disconnecting reason " + str(rc))
|
|
|
|
mqttidentstring = str(uuid.getnode())
|
|
client1= paho.Client(mqttidentstring)
|
|
client1.on_publish = on_publish
|
|
client1.username_pw_set(username="cosmicpi",password="MuonsFROMSp8ce")
|
|
client1.on_connect=on_connect #binding call
|
|
|
|
|
|
try:
|
|
request = requests.get(url,timeout=timeout)
|
|
print("internet ok")
|
|
mqtt_ok=1
|
|
except (requests.ConnectionError, requests.Timeout) as exception:
|
|
print("internet fail")
|
|
mqtt_ok=0
|
|
|
|
|
|
mylcd = I2C_LCD_driver.lcd()
|
|
mylcd.lcd_display_string("Warming up...", 1)
|
|
#import urllib2 # comment this line if you don't need ThinkSpeak connection
|
|
#import SDL_Pi_HDC1000 # comment this line if you don't use HDC sensor
|
|
|
|
|
|
try:
|
|
sensor = bme680.BME680(bme680.I2C_ADDR_PRIMARY)
|
|
except IOError:
|
|
sensor = bme680.BME680(bme680.I2C_ADDR_SECONDARY)
|
|
|
|
now = datetime.now() # current date and time
|
|
date_time = now.strftime("%m/%d/%Y")
|
|
date1=(date_time)
|
|
date_time = now.strftime("%H:%M")
|
|
date2=(date_time)
|
|
mylcd.lcd_display_string("Date: "+date1,1)
|
|
mylcd.lcd_display_string("Time: "+date2,2)
|
|
|
|
time.sleep(5)
|
|
ccs811 = CCS811_RPi()
|
|
|
|
# Do you want to preset sensor baseline? If yes set the value here, otherwise set False
|
|
INITIALBASELINE = False
|
|
# Do you want to use integrated temperature meter to compensate temp/RH (CJMCU-8118 board)?
|
|
# If not pre-set sensor compensation temperature is 25 C and RH is 50 %
|
|
# You can compensate manually by method ccs811.setCompensation(temperature,humidity)
|
|
|
|
'''
|
|
MEAS MODE REGISTER AND DRIVE MODE CONFIGURATION
|
|
0b0 Idle (Measurements are disabled in this mode)
|
|
0b10000 Constant power mode, IAQ measurement every second
|
|
0b100000 Pulse heating mode IAQ measurement every 10 seconds
|
|
0b110000 Low power pulse heating mode IAQ measurement every 60
|
|
0b1000000 Constant power mode, sensor measurement every 250ms
|
|
'''
|
|
# Set MEAS_MODE (measurement interval)
|
|
configuration = 0b100000
|
|
|
|
# Set read interval for retriveving last measurement data from the sensor
|
|
pause = 60
|
|
|
|
print('Checking hardware ID...')
|
|
hwid = ccs811.checkHWID()
|
|
if(hwid == hex(129)):
|
|
print('Hardware ID is correct')
|
|
else: print('Incorrect hardware ID ',hwid, ', should be 0x81')
|
|
|
|
#bme680 setup
|
|
sensor.set_humidity_oversample(bme680.OS_2X)
|
|
sensor.set_pressure_oversample(bme680.OS_4X)
|
|
sensor.set_temperature_oversample(bme680.OS_8X)
|
|
sensor.set_filter(bme680.FILTER_SIZE_3)
|
|
sensor.set_gas_status(bme680.ENABLE_GAS_MEAS)
|
|
|
|
sensor.set_gas_heater_temperature(320)
|
|
sensor.set_gas_heater_duration(150)
|
|
sensor.select_gas_heater_profile(0)
|
|
|
|
#run burn-in
|
|
start_time = time.time()
|
|
curr_time = time.time()
|
|
burn_in_time = 300
|
|
|
|
burn_in_data = []
|
|
|
|
# Collect gas resistance burn-in values, then use the average
|
|
# of the last 50 values to set the upper limit for calculating
|
|
# gas_baseline.
|
|
print('Collecting gas resistance burn-in data for 5 mins\n')
|
|
while curr_time - start_time < burn_in_time:
|
|
curr_time = time.time()
|
|
if sensor.get_sensor_data() and sensor.data.heat_stable:
|
|
gas = sensor.data.gas_resistance
|
|
burn_in_data.append(gas)
|
|
print('Gas: {0} Ohms'.format(gas))
|
|
outputwarm ='{0:.2f} Ohms'.format(gas)
|
|
mylcd.lcd_display_string(outputwarm, 2)
|
|
time.sleep(1)
|
|
|
|
gas_baseline = sum(burn_in_data[-50:]) / 50.0
|
|
# Set the humidity baseline to 40%, an optimal indoor humidity.
|
|
hum_baseline = 40.0
|
|
|
|
# This sets the balance between humidity and gas reading in the
|
|
# calculation of air_quality_score (25:75, humidity:gas)
|
|
hum_weighting = 0.25
|
|
|
|
print('Gas baseline: {0} Ohms, humidity baseline: {1:.2f} %RH\n'.format(
|
|
gas_baseline,
|
|
hum_baseline))
|
|
|
|
time.sleep(1)
|
|
|
|
if sensor.get_sensor_data():
|
|
sensor.set_gas_heater_temperature(300)
|
|
sensor.set_gas_heater_duration(100)
|
|
sensor.select_gas_heater_profile(0)
|
|
|
|
|
|
hum = sensor.data.humidity
|
|
temp = sensor.data.temperature
|
|
press = sensor.data.pressure
|
|
|
|
|
|
#print 'MEAS_MODE:',ccs811.readMeasMode()
|
|
ccs811.configureSensor(configuration)
|
|
print('MEAS_MODE:',ccs811.readMeasMode())
|
|
print('STATUS: ',bin(ccs811.readStatus()))
|
|
print('---------------------------------')
|
|
|
|
# Use these lines if you need to pre-set and check sensor baseline value
|
|
if(INITIALBASELINE > 0):
|
|
ccs811.setBaseline(INITIALBASELINE)
|
|
print(ccs811.readBaseline())
|
|
|
|
print("MQTT connection")
|
|
if mqtt_ok==1:
|
|
client1.connect(broker,port)
|
|
client1.loop_start()
|
|
#return 0
|
|
|
|
while(1):
|
|
humidity = hum
|
|
temperature = temp
|
|
ccs811.setCompensation(temperature,humidity)
|
|
statusbyte = ccs811.readStatus()
|
|
print('STATUS: ', bin(statusbyte))
|
|
|
|
error = ccs811.checkError(statusbyte)
|
|
if(error):
|
|
print('ERROR:',ccs811.checkError(statusbyte))
|
|
|
|
if(not ccs811.checkDataReady(statusbyte)):
|
|
#print('No new samples are ready')
|
|
#print('---------------------------------')
|
|
time.sleep(pause)
|
|
continue;
|
|
result = ccs811.readAlg();
|
|
if(not result):
|
|
#print 'Invalid result received'
|
|
time.sleep(pause)
|
|
continue;
|
|
baseline = ccs811.readBaseline()
|
|
outputCO2 = ('eCO2: {}'.format(result['eCO2']) + ' ppm')
|
|
outputVOC = ('TVOC: {}'.format(result['TVOC']) + ' ppb')
|
|
#print ('TVOC: ',result['TVOC'], 'ppb')
|
|
#print ('Status register: ',bin(result['status']))
|
|
#print ('Last error ID: ',result['errorid'])
|
|
#print ('RAW data: ',result['raw'])
|
|
#print ('Baseline: ',baseline)
|
|
#print ('---------------------------------')
|
|
#if sensor.get_sensor_data():
|
|
|
|
#if sensor.data.heat_stable:
|
|
|
|
if sensor.get_sensor_data() and sensor.data.heat_stable:
|
|
gas = sensor.data.gas_resistance
|
|
gas_offset = gas_baseline - gas
|
|
|
|
hum = sensor.data.humidity
|
|
hum_offset = hum - hum_baseline
|
|
|
|
# Calculate hum_score as the distance from the hum_baseline.
|
|
if hum_offset > 0:
|
|
hum_score = (100 - hum_baseline - hum_offset)
|
|
hum_score /= (100 - hum_baseline)
|
|
hum_score *= (hum_weighting * 100)
|
|
|
|
else:
|
|
hum_score = (hum_baseline + hum_offset)
|
|
hum_score /= hum_baseline
|
|
hum_score *= (hum_weighting * 100)
|
|
|
|
# Calculate gas_score as the distance from the gas_baseline.
|
|
if gas_offset > 0:
|
|
gas_score = (gas / gas_baseline)
|
|
gas_score *= (100 - (hum_weighting * 100))
|
|
|
|
else:
|
|
gas_score = 100 - (hum_weighting * 100)
|
|
|
|
# Calculate air_quality_score.
|
|
air_quality_score = hum_score + gas_score
|
|
outputT = '{0:.2f}C'.format(sensor.data.temperature)
|
|
outputP = '{0:.2f}hPa'.format(sensor.data.pressure)
|
|
outputH = '{0:.1f}%RH'.format(sensor.data.humidity)
|
|
outputG = '{0:.0f} Ohms'.format(sensor.data.gas_resistance)
|
|
outputIAQ = 'IAQ:{0:.1f}'.format(air_quality_score)
|
|
#print("IAQ {0:.2f} %".format(air_quality_score))
|
|
|
|
data = []
|
|
data.append("{measurement},id={DeviceID} Temp={temp},Press={press},Hum={hum},Gas={gas},IAQ={iaq},eCO2={eco2},TVOC={tvoc} {timestamp}"
|
|
.format(measurement='IAQ0.1',
|
|
DeviceID=uuid.getnode(),
|
|
temp=sensor.data.temperature,
|
|
press=sensor.data.pressure,
|
|
hum=sensor.data.humidity,
|
|
gas=sensor.data.gas_resistance,
|
|
iaq=air_quality_score,
|
|
eco2=result['eCO2'],
|
|
tvoc=result['TVOC'],
|
|
timestamp=int(time.time())))
|
|
print(data)
|
|
if mqtt_ok==1:
|
|
ret = client1.publish("iaq/0.1",str(data))
|
|
|
|
#outputs to lcd
|
|
#date and time
|
|
mylcd.lcd_clear()
|
|
now = datetime.now() # current date and time
|
|
date_time = now.strftime("%m/%d/%Y")
|
|
date1=(date_time)
|
|
date_time = now.strftime("%H:%M")
|
|
date2=(date_time)
|
|
mylcd.lcd_display_string(date1+" "+ date2,1)
|
|
mylcd.lcd_display_string(outputG,2)
|
|
time.sleep(6)
|
|
mylcd.lcd_clear()
|
|
#TPH and IAQ
|
|
mylcd.lcd_display_string(outputT,1)
|
|
mylcd.lcd_display_string(outputIAQ,2)
|
|
time.sleep(6)
|
|
mylcd.lcd_clear()
|
|
mylcd.lcd_display_string(outputIAQ,1)
|
|
mylcd.lcd_display_string(outputCO2,2)
|
|
time.sleep(6)
|
|
mylcd.lcd_clear()
|
|
mylcd.lcd_display_string(outputCO2,1)
|
|
mylcd.lcd_display_string(outputVOC,2)
|
|
time.sleep(6)
|
|
mylcd.lcd_clear()
|
|
mylcd.lcd_display_string(outputVOC,1)
|
|
mylcd.lcd_display_string(outputP,2)
|
|
time.sleep(5)
|
|
mylcd.lcd_clear()
|
|
mylcd.lcd_display_string(outputP,1)
|
|
mylcd.lcd_display_string(outputH,2)
|
|
time.sleep(5)
|
|
mylcd.lcd_clear()
|
|
now = datetime.now() # current date and time
|
|
date_time = now.strftime("%m/%d/%Y")
|
|
date1=(date_time)
|
|
date_time = now.strftime("%H:%M")
|
|
date2=(date_time)
|
|
mylcd.lcd_display_string(date1+" "+ date2,1)
|
|
mylcd.lcd_display_string(outputG,2)
|
|
time.sleep(4)
|
|
mylcd.lcd_clear()
|
|
#TPH and IAQ
|
|
mylcd.lcd_display_string(outputT,1)
|
|
mylcd.lcd_display_string(outputIAQ,2)
|
|
time.sleep(4)
|
|
mylcd.lcd_clear()
|
|
mylcd.lcd_display_string(outputIAQ,1)
|
|
mylcd.lcd_display_string(outputCO2,2)
|
|
time.sleep(4)
|
|
mylcd.lcd_clear()
|
|
mylcd.lcd_display_string(outputCO2,1)
|
|
mylcd.lcd_display_string(outputVOC,2)
|
|
time.sleep(4)
|
|
mylcd.lcd_clear()
|
|
mylcd.lcd_display_string(outputVOC,1)
|
|
mylcd.lcd_display_string(outputP,2)
|
|
time.sleep(4)
|
|
mylcd.lcd_clear()
|
|
mylcd.lcd_display_string(outputP,1)
|
|
mylcd.lcd_display_string(outputH,2)
|
|
time.sleep(4) |