├── HA_view.png ├── LICENSE ├── README.md └── bme680-air-quality-RC.py /HA_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robmarkcole/bme680-mqtt/HEAD/HA_view.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Robin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bme680-mqtt 2 | Modifies example by [Pimoroni](https://github.com/pimoroni/bme680/blob/master/examples/indoor-air-quality.py) to publish [bme680](https://learn.pimoroni.com/tutorial/sandyj/getting-started-with-bme680-breakout) data via MQTT. 3 | 4 | To add the MQTT output to [Home-assistant](https://home-assistant.io/), we use an [MQTT-switch](https://home-assistant.io/components/switch.mqtt/). Assuming you have your Home-assistant [config split](https://home-assistant.io/docs/configuration/splitting_configuration/) into seperate files, in your sensors.yaml file, add the following: 5 | 6 | ```yaml 7 | - platform: mqtt 8 | name: 'bme680-temperature' 9 | state_topic: 'bme680-temperature' 10 | unit_of_measurement: '°C' 11 | - platform: mqtt 12 | name: 'bme680-humidity' 13 | state_topic: 'bme680-humidity' 14 | unit_of_measurement: '%' 15 | - platform: mqtt 16 | name: 'bme680-pressure' 17 | state_topic: 'bme680-pressure' 18 | unit_of_measurement: 'hPa' 19 | - platform: mqtt 20 | name: 'bme680-air_qual' 21 | state_topic: 'bme680-air_qual' 22 | unit_of_measurement: '%' 23 | ``` 24 | 25 | I then created a group, in groups.yaml: 26 | 27 | ```yaml 28 | BME680: 29 | entities: 30 | - sensor.bme680temperature 31 | - sensor.bme680pressure 32 | - sensor.bme680humidity 33 | - sensor.bme680air_qual 34 | ``` 35 | 36 | Finally you may want to [customise](https://home-assistant.io/docs/configuration/customizing-devices/) the look of the sensors in the Home-assistant front end. 37 | 38 | 39 | -------------------------------------------------------------------------------- /bme680-air-quality-RC.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import bme680 4 | import time 5 | 6 | import paho.mqtt.client as mqtt 7 | import paho.mqtt.publish as publish 8 | 9 | print("""Estimate indoor air quality 10 | 11 | Runs the sensor for a burn-in period, then uses a 12 | combination of relative humidity and gas resistance 13 | to estimate indoor air quality as a percentage. 14 | 15 | Press Ctrl+C to exit 16 | 17 | """) 18 | 19 | ### MQTT 20 | broker = '192.168.0.30' 21 | topic ='test' 22 | 23 | client = mqtt.Client() 24 | client.connect(broker) 25 | client.loop_start() 26 | 27 | ### bme680 28 | 29 | sensor = bme680.BME680() 30 | 31 | # These oversampling settings can be tweaked to 32 | # change the balance between accuracy and noise in 33 | # the data. 34 | 35 | sensor.set_humidity_oversample(bme680.OS_2X) 36 | sensor.set_pressure_oversample(bme680.OS_4X) 37 | sensor.set_temperature_oversample(bme680.OS_8X) 38 | sensor.set_filter(bme680.FILTER_SIZE_3) 39 | sensor.set_gas_status(bme680.ENABLE_GAS_MEAS) 40 | 41 | sensor.set_gas_heater_temperature(320) 42 | sensor.set_gas_heater_duration(150) 43 | sensor.select_gas_heater_profile(0) 44 | 45 | # start_time and curr_time ensure that the 46 | # burn_in_time (in seconds) is kept track of. 47 | 48 | start_time = time.time() 49 | curr_time = time.time() 50 | burn_in_time = 1 # burn_in_time (in seconds) is kept track of. 51 | 52 | burn_in_data = [] 53 | 54 | try: 55 | # Collect gas resistance burn-in values, then use the average 56 | # of the last 50 values to set the upper limit for calculating 57 | # gas_baseline. 58 | print("Collecting gas resistance burn-in data for 5 mins\n") 59 | while curr_time - start_time < burn_in_time: 60 | curr_time = time.time() 61 | if sensor.get_sensor_data() and sensor.data.heat_stable: 62 | gas = sensor.data.gas_resistance 63 | burn_in_data.append(gas) 64 | print("Gas: {0} Ohms".format(gas)) 65 | time.sleep(1) 66 | 67 | gas_baseline = sum(burn_in_data[-50:]) / 50.0 68 | 69 | # Set the humidity baseline to 40%, an optimal indoor humidity. 70 | hum_baseline = 40.0 71 | 72 | # This sets the balance between humidity and gas reading in the 73 | # calculation of air_quality_score (25:75, humidity:gas) 74 | hum_weighting = 0.25 75 | 76 | print("Gas baseline: {0} Ohms, humidity baseline: {1:.2f} %RH\n".format(gas_baseline, hum_baseline)) 77 | 78 | while True: 79 | if sensor.get_sensor_data() and sensor.data.heat_stable: 80 | gas = sensor.data.gas_resistance 81 | gas_offset = gas_baseline - gas 82 | 83 | hum = sensor.data.humidity 84 | hum_offset = hum - hum_baseline 85 | 86 | # Calculate hum_score as the distance from the hum_baseline. 87 | if hum_offset > 0: 88 | hum_score = (100 - hum_baseline - hum_offset) / (100 - hum_baseline) * (hum_weighting * 100) 89 | 90 | else: 91 | hum_score = (hum_baseline + hum_offset) / hum_baseline * (hum_weighting * 100) 92 | 93 | # Calculate gas_score as the distance from the gas_baseline. 94 | if gas_offset > 0: 95 | gas_score = (gas / gas_baseline) * (100 - (hum_weighting * 100)) 96 | 97 | else: 98 | gas_score = 100 - (hum_weighting * 100) 99 | 100 | # Calculate air_quality_score. 101 | air_quality_score = hum_score + gas_score 102 | 103 | humidity = str(round(hum, 2)) 104 | temperature = str(round(sensor.data.temperature, 2)) 105 | pressure = str(round(sensor.data.pressure, 2)) 106 | air_qual = str(round(air_quality_score, 2)) 107 | 108 | print("Gas: {0:.2f} Ohms,humidity: {1:.2f} %RH,air quality: {2:.2f}".format(gas, hum, air_quality_score)) 109 | 110 | client.publish('bme680-humidity', humidity) 111 | client.publish('bme680-temperature', temperature) 112 | client.publish('bme680-pressure', pressure) 113 | client.publish('bme680-air_qual', air_qual) 114 | time.sleep(1) 115 | 116 | except KeyboardInterrupt: 117 | pass 118 | --------------------------------------------------------------------------------