BME680 support

Moderator: leecollings

Post Reply
User avatar
profeta64
Posts: 8
Joined: Saturday 11 February 2017 17:48
Target OS: Raspberry Pi / ODroid
Domoticz version: 2020.2
Location: Bayern
Contact:

BME680 support

Post by profeta64 »

Hello,

someone has already got successfully a BME680 connected to the Domoticz i2c interface on Raspberry Pi 3+?

Thanks for the help in advance :)
Last edited by profeta64 on Friday 12 April 2019 23:03, edited 1 time in total.
User avatar
profeta64
Posts: 8
Joined: Saturday 11 February 2017 17:48
Target OS: Raspberry Pi / ODroid
Domoticz version: 2020.2
Location: Bayern
Contact:

Re: BME680 any support?

Post by profeta64 »

I found here the official library https://github.com/BoschSensortec/BME680_driver

Moreover already Pimoroni developed a sample software in Python: https://learn.pimoroni.com/tutorial/san ... 0-breakout
Last edited by profeta64 on Friday 12 April 2019 22:32, edited 1 time in total.
User avatar
profeta64
Posts: 8
Joined: Saturday 11 February 2017 17:48
Target OS: Raspberry Pi / ODroid
Domoticz version: 2020.2
Location: Bayern
Contact:

Re: BME680 any support?

Post by profeta64 »

My giving away for this project...
I solved the issue creating a Virtual Sensor, with input as Percentage.

Then, I used the Pimoroni library, and json interface to communicate directly with Domoticz.
The script follow the Piromoni 5min warm-up phase, then a value is transfered to Domoticz every minute, as average value.

Use the following pyhton code:

Code: Select all

#!/usr/bin/env python
import bme680
import time
import urllib2

idx_bme680 = IDX_Created_in_Domoticz
domoticz1_url = "http://domoticz-ip:port"

try:
    sensor = bme680.BME680(bme680.I2C_ADDR_PRIMARY)
except IOError:
    sensor = bme680.BME680(bme680.I2C_ADDR_SECONDARY)

# These oversampling settings can be tweaked to
# change the balance between accuracy and noise in
# the data.

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)

# start_time and curr_time ensure that the
# burn_in_time (in seconds) is kept track of.

start_time = time.time()
curr_time = time.time()
burn_in_time = 300

burn_in_data = []
average = 60
average_value = 0

try:
    # Collect gas resistance burn-in values, then use the average
    # of the last 50 values to set the upper limit for calculating
    # gas_baseline.
    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))
            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

    while True:
        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
			
			average_value = average_value + air_quality_score
			average = average - 1
			if average < 1:
			
				url_data1 = '/json.htm?type=command&param=udevice&idx='
				url_data2 = '&nvalue=0&svalue='+str(average_value/60)
				url1 = domoticz1_url+url_data1+str(idx_bme680)+url_data2
				req1 = urllib2.Request(url1)
				response1 = urllib2.urlopen(req1)
				print(response1)
				    				
				average = 60
				average_value = 0

            time.sleep(1)

except KeyboardInterrupt, e:
    logging.info("Stopping...")
    pass
Last edited by profeta64 on Tuesday 30 April 2019 19:15, edited 4 times in total.
User avatar
profeta64
Posts: 8
Joined: Saturday 11 February 2017 17:48
Target OS: Raspberry Pi / ODroid
Domoticz version: 2020.2
Location: Bayern
Contact:

Re: BME680 any support?

Post by profeta64 »

A second step, let's make it a service, starting automatically on boot.
You a service definition file, inside: /lib/systemd/system/

File: /lib/systemd/system/BME680_AIQ.service

Code: Select all

[Unit]
Description=BME680 Air Quality Service
After=multi-user.target
 
[Service]
Type=simple
ExecStart=/usr/bin/python /home/pi/BME680_AIQ.py
Restart=on-abort
 
[Install]
WantedBy=multi-user.target
To enable it, on the terminal:

Code: Select all

sudo chmod 644 /lib/systemd/system/BME680_AIQ.service
chmod +x /home/pi/BME680_AIQ.py
sudo systemctl daemon-reload
sudo systemctl enable BME680_AIQ.service
sudo systemctl start BME680_AIQ.service
To verify if everything is working, again in terminal:

Code: Select all

sudo service BME680_AIQ start
sudo service BME680_AIQ status
sudo journalctl -f -u BME680_AIQ
User avatar
profeta64
Posts: 8
Joined: Saturday 11 February 2017 17:48
Target OS: Raspberry Pi / ODroid
Domoticz version: 2020.2
Location: Bayern
Contact:

Re: BME680 support

Post by profeta64 »

Small update, trying to have an error handling

Code: Select all

#!/usr/bin/env python
import bme680
import time
import urllib2
import logging

idx_bme680 = IDX_Created_in_Domoticz
domoticz1_url = "http://domoticz-ip:port"

try:
    sensor = bme680.BME680(bme680.I2C_ADDR_PRIMARY)
except IOError:
    sensor = bme680.BME680(bme680.I2C_ADDR_SECONDARY)

# These oversampling settings can be tweaked to change the balance between accuracy and noise in the data.
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)

# start_time and curr_time ensure that the burn_in_time (in seconds) is kept track of.
start_time = time.time()
curr_time = time.time()
burn_in_time = 300
burn_in_data = []
average = 60
average_value = 0
try:
    # Collect gas resistance burn-in values, then use the average of the last 50 values to set the upper limit for
    # calculating gas_baseline.
    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))
            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
    while True:
        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
            average_value = average_value + air_quality_score
            average = average - 1
            if average < 1:
                url_data1 = '/json.htm?type=command&param=udevice&idx='
                url_data2 = '&nvalue=0&svalue='+str(average_value/60)
                url1 = domoticz1_url+url_data1+str(idx_bme680)+url_data2
                try:
                    req1 = urllib2.Request(url1)
                    response1 = urllib2.urlopen(req1)
                    print(response1)
                except:
                    logging.info("Socket error.")
                    pass
                average = 60
                average_value = 0
            time.sleep(1)
except KeyboardInterrupt, e:
    logging.info("Stopping...")
    pass
User avatar
profeta64
Posts: 8
Joined: Saturday 11 February 2017 17:48
Target OS: Raspberry Pi / ODroid
Domoticz version: 2020.2
Location: Bayern
Contact:

Re: BME680 support

Post by profeta64 »

Dear all,

I follow with my sharing of the solution.
Now I found a way to use the official BSEL library, thus have a better control of the BME680 chip.

Compile the bsec_bme680_python software:

Code: Select all

pip install statistics
git clone https://github.com/rstoermer/bsec_bme680_python
cd bsec_bme680_python/
./make.sh
You can verify if the software is running through:

Code: Select all

python bsec_bme680.py
Then I modified the Python software (bsec_bme680.py) to user the JSON instead of the MTTQ protocol:

Code: Select all

#!/usr/bin/env python
import subprocess
from statistics import median
import urllib2
import json
import logging

idx_bme680_IAQ = 1
idx_bme680_THB = 2
domoticz_url = 'http://raspberrypi:8080'
url_data_base = '/json.htm?type=command&param=udevice&idx='
url_data1 = '&nvalue='
url_data2 = '&nvalue=0&svalue='

#Open C File
proc = subprocess.Popen(['/home/pi/bsec_bme680_python/bsec_bme680'], shell=True, stdout=subprocess.PIPE)

listIAQ_Accuracy = []
listPressure = []
listGas = []
listTemperature = []
listIAQ = []
listHumidity  = []
listStatus = []

for line in iter(proc.stdout.readline, ''):
    lineJSON = json.loads(line.decode("utf-8")) # process line-by-line
    lineDict = dict(lineJSON)

    #Avoid to collect the valies with low IAQ score (IAQ score from 0=low to 3=high)
    if int(lineDict['IAQ_Accuracy']) > 1:

        listIAQ_Accuracy.append(int(lineDict['IAQ_Accuracy']))
        listPressure.append(float(lineDict['Pressure']))
        listGas.append(int(lineDict['Gas']))
        listTemperature.append(float(lineDict['Temperature']))
        listIAQ.append(float(lineDict['IAQ']))
        listHumidity.append(float(lineDict['Humidity']))
        listStatus.append(int(lineDict['Status']))

        if len(listIAQ_Accuracy) == 20:
            #generate the median for each value
            IAQ_Accuracy = median(listIAQ_Accuracy)
            Pressure = median(listPressure)
            Gas = median(listGas)
            Temperature = median(listTemperature)
            IAQ = median(listIAQ)
            Humidity = median(listHumidity)
            Status = median(listStatus)

            #clear lists
            del listIAQ_Accuracy[:]
            del listPressure[:]
            del listGas[:]
            del listTemperature[:]
            del listIAQ[:]
            del listHumidity[:]
            del listStatus[:]


            #Temperature Offset
            Temperature = Temperature + 2

            if Humidity < 40:
               HUM_STAT = '2'
            elif Humidity < 60:
               HUM_STAT = '1'
            else:
               HUM_STAT = '3'

            url1 = domoticz_url+url_data_base+str(idx_bme680_IAQ)+url_data2+str(round(IAQ, 0))
            url2 = domoticz_url+url_data_base+str(idx_bme680_THB)+url_data2+str(round(Temperature, 1))+";"+str(round(Humidity, 1))+";"+HUM_STAT+";"+str(round(Pressure, 1))+";0"
            try:
                logging.info("Transmitting.")
                print("Transmitting.")
                print(url1)
                print(url2)
                req1 = urllib2.Request(url1)
                response1 = urllib2.urlopen(req1)
                logging.info(url1)
                logging.info(response1)
                req2 = urllib2.Request(url2)
                response2 = urllib2.urlopen(req2)
                logging.info(url2)
                logging.info(response2)

            except:
                logging.info("Socket error.")
                pass
and then used it through the service like before.
File: /lib/systemd/system/BME680_AIQ.service

Code: Select all

[Unit]
Description=BME680 Air Quality Service
After=multi-user.target

[Service]
Type=simple
ExecStart=/usr/bin/python bsec_bme680.py
WorkingDirectory=/home/pi/bsec_bme680_python

Restart=on-abort

[Install]
WantedBy=multi-user.target

To get the values you need a Custom device for the AQI value, and a Temp+Hum+Baro for the other values.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest