Maker Pro
ESP8266

BME680 (GY-MCU680V1) Indoor air quality meter

May 06, 2019 by Petr Lukáš
Share
banner

Very simple air quality meter using the GY-MCU680V1 sensor containing the BME680 chip from Bosch Sensortec.

In this video we will introduce how to make a very simple air quality meter in a room. For this purpose, we use the GY-MCU680V1 sensor containing the BME680 chip from Bosch Sensortec. BME680 is a metal oxide-based sensor that detects VOCs by adsorption (and subsequent oxidation/reduction) on its sensitive layer. Thus, BME680 reacts to most volatile compounds polluting indoor air (one exception is for instance CO2). In addition to measuring the VOC content, the sensor can also measure temperature, humidity and air pressure. We use ThingSpeak interface (optional) to record the measured values and a simple OLED shield to display them. Today, the sensor can be purchased at Chinese stores at a relatively friendly price (see links below for current price).

Libraries:

https://github.com/mcauser/Adafruit_SSD1306/tree/esp8266-64x48
https://github.com/plerup/espsoftwareserial/

ThingSpeak data:
https://thingspeak.com/channels/661295

//GY_MCU680 air quality sensor
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 0 // GPIO0
Adafruit_SSD1306 display(OLED_RESET);
#include <SoftwareSerial.h>
#include <ESP8266WiFi.h>
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";
const char* server = "api.thingspeak.com";
const char* api_key = "YOUR_API_KEY";
// Optional - you can define air pressure correction for your altitude
#define ALT_CORRECTION 3144
SoftwareSerial mySerial(D6, D5);
uint16_t temp1=0;
int16_t temp2=0;
unsigned char Re_buf[30],counter=0;
unsigned char sign=0;
int led = 13;
WiFiClient client;
unsigned long prev = millis();
// You need to use modified Adafruit library with support of small displays
// see here: https://github.com/mcauser/Adafruit_SSD1306/tree/esp8266-64x48
#if (SSD1306_LCDHEIGHT != 48)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
void setup()
{
Serial.begin(9600);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
delay(1000);
//---------------------------------
Serial.println("Connecting to wifi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED){
// Blink LED when connecting to wifi
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
delay(150);
digitalWrite(LED_BUILTIN, HIGH);
delay(150);
}
Serial.println("WiFi connected");
//---------------------------------
pinMode(D2, INPUT);
pinMode(D1, OUTPUT);
mySerial.begin(9600);
mySerial.listen();
delay(5000);
mySerial.write(0XA5);
mySerial.write(0X55);
mySerial.write(0X3F);
mySerial.write(0X39);
delay(100);
mySerial.write(0XA5);
mySerial.write(0X56);
mySerial.write(0X02);
mySerial.write(0XFD);
Serial.println("Setup complete");
delay(100);
}
void loop(){
float Temperature ,Humidity;
unsigned char i=0,sum=0;
uint32_t Gas;
uint32_t Pressure;
uint16_t IAQ;
int16_t Altitude;
uint8_t IAQ_accuracy;
//Serial.println("Checking serial...");
while (mySerial.available()) {
//Serial.println("mySerial available");
Re_buf[counter]=(unsigned char)mySerial.read();
if(counter==0&&Re_buf[0]!=0x5A) {
Serial.println("Nothing received");
}
if(counter==1&&Re_buf[1]!=0x5A)
{
counter=0;
return;
};
counter++;
if(counter==20)
{
counter=0;
sign=1;
}
}
if(sign)
{
sign=0;
if(Re_buf[0]==0x5A&&Re_buf[1]==0x5A )
{
for(i=0;i<19;i++)
sum+=Re_buf[i];
if(sum==Re_buf[i] )
{
temp2=(Re_buf[4]<<8|Re_buf[5]);
Temperature=(float)temp2/100;
temp1=(Re_buf[6]<<8|Re_buf[7]);
Humidity=(float)temp1/100;
Pressure=((uint32_t)Re_buf[8]<<16)|((uint16_t)Re_buf[9]<<8)|Re_buf[10];
float altPressure=(float(Pressure)+ALT_CORRECTION)/100;
IAQ_accuracy= (Re_buf[11]&0xf0)>>4;
IAQ=((Re_buf[11]&0x0F)<<8)|Re_buf[12];
Gas=((uint32_t)Re_buf[13]<<24)|((uint32_t)Re_buf[14]<<16)|((uint16_t)Re_buf[15]<<8)|Re_buf[16];
Altitude=(Re_buf[17]<<8)|Re_buf[18];
Serial.print("Temperature:");
Serial.print(Temperature);
Serial.print(" ,Humidity:");
Serial.print(Humidity);
Serial.print(" ,Pressure:");
Serial.print(Pressure);
Serial.print("|");
Serial.print(altPressure);
Serial.print(" ,IAQ:");
Serial.print(IAQ);
Serial.print(" ,Gas:");
Serial.print(Gas);
Serial.print(" ,Altitude:");
Serial.print(Altitude);
Serial.print(" ,IAQ_accuracy:");
Serial.println(IAQ_accuracy);
// Display result on OLED display
dislayResult(IAQ);
if(millis() - prev > 60000){
postData(Temperature,Humidity,altPressure,IAQ,Gas,IAQ_accuracy);
prev = millis();
}
}
delay(1000);
}
}
}
void postData(float temperature, float humidity, float altPressure, int iaq, int gas, int iaq_accuracy){
digitalWrite(LED_BUILTIN, LOW);
// Send data to ThingSpeak
if (client.connect(server,80)) {
Serial.println("Connect to ThingSpeak - OK");
String dataToThingSpeak = "";
dataToThingSpeak+="GET /update?api_key=";
dataToThingSpeak+=api_key;
dataToThingSpeak+="&field1=";
dataToThingSpeak+=String(temperature);
dataToThingSpeak+="&field2=";
dataToThingSpeak+=String(humidity);
dataToThingSpeak+="&field3=";
dataToThingSpeak+=String(altPressure);
dataToThingSpeak+="&field4=";
dataToThingSpeak+=String(iaq);
dataToThingSpeak+="&field5=";
dataToThingSpeak+=String(gas);
dataToThingSpeak+="&field6=";
dataToThingSpeak+=String(iaq_accuracy);
dataToThingSpeak+=" HTTP/1.1\r\nHost: a.c.d\r\nConnection: close\r\n\r\n";
dataToThingSpeak+="";
client.print(dataToThingSpeak);
int timeout = millis() + 5000;
while (client.available() == 0) {
if (timeout - millis() < 0) {
Serial.println("Error: Client Timeout!");
client.stop();
return;
}
}
}
while(client.available()){
String line = client.readStringUntil('\r');
//Serial.print(line);
}
digitalWrite(LED_BUILTIN, HIGH);
}
void dislayResult(int iaq){
String disp;
if(iaq <= 50) disp="GOOD";
else if(iaq > 50 && iaq <= 100) disp = "AVER";
else if(iaq > 100 && iaq <= 150) disp = "L.BAD";
else if(iaq > 150 && iaq <= 200) disp = "BAD";
else if(iaq > 200 && iaq <= 300) disp = "WORSE";
else disp = "V.BAD";
display.setTextColor(WHITE);
display.drawLine(0, 24, 64, 24, WHITE);
display.setCursor(3+(5-disp.length())*8,5);
display.setTextSize(2);
display.fillRect(0, 0, 64, 23, BLACK);
display.println(disp);
display.setCursor(8,30);
display.setTextSize(1);
display.fillRect(0, 25, 64, 20, BLACK);
display.print("IAQ: ");
display.print(iaq);
display.display();
}

Author

Avatar
Petr Lukáš

Application Software Developer, Performance and capacity reporting for IBM zSeries team, experimenting with home automation, sensors, Arduino and ESP

Related Content

Comments


You May Also Like