Categories

Follow

BME680 environment sensor and ESP8266 example

In this article we will connect a BME680 sensor to an ESP8266 – as usual we will use a Wemos Mini

BME680 is an integrated environmental sensor developed specifically for mobile applications and wearables where size and low power consumption are key requirements. Expanding Bosch Sensortec’s existing family of environmental sensors, the BME680 integrates for the first time high-linearity and high-accuracy gas, pressure, humidity and temperature sensors. The gas sensor within the BME680 can detect a broad range of gases to measure air quality for personal well being.

This was the particular sensor that I used – there are a couple of different modules available

Gases that can be detected by the BME680 include Volatile Organic Compounds (VOC) from paints (such as formaldehyde), lacquers, paint strippers, cleaning supplies, furnishings, office equipment, glues, adhesives and alcohol.

Parameter Technical data
Package dimensions 8-Pin LGA with metal
3.0 x 3.0 x 0.93 mm³
Operation range (full accuracy) Pressure: 300…1100 hPa
Humidity 0…100%
Temperature: -40…85°C
Supply voltage VDDIO
Supply voltage VDD
1.2 … 3.6 V
1.71 … 3.6 V
Interface I²C and SPI
Average current consumption
(1Hz data refresh rate)
2.1 µA at 1 Hz humidity and temperature
3.1 µA at 1 Hz pressure and temperature
3.7 µA at 1 Hz humidity, pressure and temperature 0.09‒12 mA for p/h/T/gas depending on operation mode
Average current consumption in sleep mode 0.15 μA
Gas sensor
Response time (τ 33-63%)
Sensor-to-sensor deviation
Power consumption
Output data processing
< 1 s (for new sensors)
+/- 15% +/- 15
< 0.1 mA in ultra-low power mode
direct output of IAQ: Index for Air Quality
Humidity sensor
Response time (τ0-63%)
Accuracy tolerance
Hysteresis
8 s
± 3 % relative humidity
≤ 1.5 % relative humidity
Pressure sensor
RMS Noise
Sensitivity Error
Temperature coefficient offset
0.12 Pa (equiv. to 1.7 cm)
± 0.25 % (equiv. to 1 m at 400 m height change)
±1.3 Pa/K (equiv. to ±10.9 cm at 1°C temperature change)

 

Parts List

Name Link
Wemos Mini D1 mini – Mini NodeMcu 4M bytes Lua WIFI Internet of Things development board based ESP8266 by WeMos
BME680 BME680 Sensor Module Temperature and Humidity Air Pressure Air Quality IAQ MCU680 Module
Connecting wire Free shipping Dupont line 120pcs 20cm male to male + male to female and female to female jumper wire

Schematic

We use the I2C connection for the sensor

esp8266 and bme680

esp8266 and bme680

 

Code

You will need to import the adafruit sensor and bme680 libraries – you can add these using the library manager

My particular sensor used address 0x76, the default is 0x77 so you may have to change this line from if (!bme.begin(0x76)) to if (!bme.begin())

 

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
 
 
#define SEALEVELPRESSURE_HPA (1013.25)
 
Adafruit_BME680 bme; // I2C
 
void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println(F("BME680 test"));
 
  if (!bme.begin(0x76)) 
  {
    Serial.println("Could not find a valid BME680 sensor, check wiring!");
    while (1);
  }
 
  // Set up oversampling and filter initialization
  bme.setTemperatureOversampling(BME680_OS_8X);
  bme.setHumidityOversampling(BME680_OS_2X);
  bme.setPressureOversampling(BME680_OS_4X);
  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
  bme.setGasHeater(320, 150); // 320*C for 150 ms
}
 
void loop() 
{
  if (! bme.performReading()) 
  {
    Serial.println("Failed to perform reading :(");
    return;
  }
  Serial.print("Temperature = ");
  Serial.print(bme.temperature);
  Serial.println(" *C");
 
  Serial.print("Pressure = ");
  Serial.print(bme.pressure / 100.0);
  Serial.println(" hPa");
 
  Serial.print("Humidity = ");
  Serial.print(bme.humidity);
  Serial.println(" %");
 
  Serial.print("Gas = ");
  Serial.print(bme.gas_resistance / 1000.0);
  Serial.println(" KOhms");
 
  Serial.print("Approx. Altitude = ");
  Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
  Serial.println(" m");
 
  Serial.println();
  delay(2000);
}

 

Output

Open the serial monitor and you will see something like this

Temperature = 23.89 *C
Pressure = 973.94 hPa
Humidity = 41.07 %
Gas = 143.28 KOhms
Approx. Altitude = 332.55 m

Temperature = 24.05 *C
Pressure = 973.88 hPa
Humidity = 40.96 %
Gas = 146.54 KOhms
Approx. Altitude = 332.72 m

Temperature = 24.04 *C
Pressure = 973.94 hPa
Humidity = 40.83 %
Gas = 151.31 KOhms
Approx. Altitude = 332.37 m

Wemos and Barometric Pressure Shield example

In this article we look at a relatively new shield for the Wemos/Lolin products – this is a Barometric Pressure shield based on a HP303B. Here is some info about the sensor

The HP303B is a miniaturized Digital Barometric Air Pressure Sensor with a high accuracy and a low current consumption, capable of measuring both pressure and temperature.
The pressure sensor element is based on a capacitive sensing principle which guarantees high precision during temperature changes. The small package makes the HP303B ideal for mobile applications and wearable devices.

The internal signal processor converts the output from the pressure and temperature sensor elements to 24 bit results. Each unit is individually calibrated, the calibration coeicients calculated during this process are stored in the calibration registers. The coeicients are used in the application to convert the measurement results to high accuracy pressure and temperature values.

The result FIFO can store up to 32 measurement results, allowing for a reduced host processor polling rate. Sensor measurements and calibration coeicients are available through the serial I2C or SPI interface. The measurement status is indicated by status bits or interrupts on the SDO pin.

Features

• Operation range: Pressure: 300 –1200 hPa. Temperature: -40 – 85 °C.
• Pressure sensor precision: ± 0.005 hPa (or ±0.05 m) (high precision mode).
• Relative accuracy: ± 0.06 hPa (or ±0.5 m)
• Absolute accuracy: ± 1 hPa (or ±8 m)
• Temperature accuracy: ± 0.5°C.
• Pressure temperature sensitivity: 0.5Pa/K
• Measurement time: Typical: 27.6 ms for standard mode (16x). Minimum: 3.6 ms for low precision mode.
• Average current consumption: 1.7 µA for Pressure Measurement, 1.5uA for Temperature measurement @1Hz sampling rate, Standby: 0.5 µA.
• Supply voltage: VDDIO: 1.2 – 3.6 V, VDD: 1.7 – 3.6 V.
• Operating modes: Command (manual), Background (automatic), and Standby.
• Calibration: Individually calibrated with coeicients for measurement correction.
• FIFO: Stores up to 32 pressure or temperature measurements.
• Interface: I2C and SPI (both with optional interrupt)

This is the Wemos shield

Code

The example requires the https://github.com/wemos/LOLIN_HP303B_Library

This examples works OK

#include <LOLIN_HP303B.h>
 
// HP303B Opject
LOLIN_HP303B HP303BPressureSensor;
 
 
void setup()
{
  Serial.begin(115200);
  while (!Serial);
  HP303BPressureSensor.begin();
  Serial.println("Init complete!");
}
 
 
void loop()
{
  int32_t temperature;
  int32_t pressure;
  int16_t oversampling = 7;
  int16_t ret;
  Serial.println();
 
  ret = HP303BPressureSensor.measureTempOnce(temperature, oversampling);
 
  if (ret != 0)
  {
    //Something went wrong.
    //Look at the library code for more information about return codes
    Serial.print("FAIL! ret = ");
    Serial.println(ret);
  }
  else
  {
    Serial.print("Temperature: ");
    Serial.print(temperature);
    Serial.println(" degrees of Celsius");
  }
 
  //Pressure measurement behaves like temperature measurement
  //ret = HP303BPressureSensor.measurePressureOnce(pressure);
  ret = HP303BPressureSensor.measurePressureOnce(pressure, oversampling);
  if (ret != 0)
  {
    //Something went wrong.
    //Look at the library code for more information about return codes
    Serial.print("FAIL! ret = ");
    Serial.println(ret);
  }
  else
  {
    Serial.print("Pressure: ");
    Serial.print(pressure);
    Serial.println(" Pascal");
  }
 
  //Wait some time
  delay(500);
}

 

Output

Open the serial monitor and you should see something like this

Temperature: 31 degrees of Celsius
Pressure: 100469 Pascal

Temperature: 31 degrees of Celsius
Pressure: 100471 Pascal

Temperature: 31 degrees of Celsius
Pressure: 100470 Pascal

Temperature: 31 degrees of Celsius
Pressure: 100470 Pascal

 

Links

https://cdn.sos.sk/productdata/59/18/835e5d50/hp303b.pdf

A quick look at the Wemos TFT 2.4 Touch Shield

This is a 2.4 inch TFT shield for a Wemos, its a large shield thats more than twice the size of a D1 mini but its an excellent little TFT screen and there are a couple of example to let you get up and running quick unlike some of the Arduino TFT shields which I have had trouble with in the past

This is a picture of the shield

Features

  • 2.4” diagonal LCD TFT display
  • 320×240 pixels
  • TFT Driver IC: ILI9341
  • Touch Screen controller IC: XPT2046

 

Code

You need to install various libraries – Adafruit_GFXAdafruit_ILI9341 and XPT2046_Touchscreen Library

Touchscreen example

#include <SPI.h>
#include <XPT2046_Touchscreen.h>
 
#define TS_CS D3 //for D1 mini or TFT I2C Connector Shield (V1.1.0 or later)
// #define TS_CS  12 //for D32 Pro
 
XPT2046_Touchscreen ts(TS_CS);
 
void setup()
{
  Serial.begin(115200);
  ts.begin();
  ts.setRotation(1);
  while (!Serial && (millis() <= 1000))
    ;
}
 
void loop()
{
  if (ts.touched())
  {
    TS_Point p = ts.getPoint();
    Serial.print("Pressure = ");
    Serial.print(p.z);
    Serial.print(", x = ");
    Serial.print(p.x);
    Serial.print(", y = ");
    Serial.print(p.y);
    delay(30);
    Serial.println();
  }
}

 

Default graphics example

 

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
 
#define TFT_CS D0  //for D1 mini or TFT I2C Connector Shield (V1.1.0 or later)
#define TFT_DC D8  //for D1 mini or TFT I2C Connector Shield (V1.1.0 or later)
#define TFT_RST -1 //for D1 mini or TFT I2C Connector Shield (V1.1.0 or later)
#define TS_CS D3   //for D1 mini or TFT I2C Connector Shield (V1.1.0 or later)
 
// #define TFT_CS 14  //for D32 Pro
// #define TFT_DC 27  //for D32 Pro
// #define TFT_RST 33 //for D32 Pro
// #define TS_CS  12 //for D32 Pro
 
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
 
void setup()
{
  Serial.begin(115200);
  Serial.println("ILI9341 Test!");
 
  tft.begin();
 
  // read diagnostics (optional but can help debug problems)
  uint8_t x = tft.readcommand8(ILI9341_RDMODE);
  Serial.print("Display Power Mode: 0x");
  Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDMADCTL);
  Serial.print("MADCTL Mode: 0x");
  Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDPIXFMT);
  Serial.print("Pixel Format: 0x");
  Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDIMGFMT);
  Serial.print("Image Format: 0x");
  Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDSELFDIAG);
  Serial.print("Self Diagnostic: 0x");
  Serial.println(x, HEX);
 
  Serial.println(F("Benchmark                Time (microseconds)"));
  delay(10);
  Serial.print(F("Screen fill              "));
  Serial.println(testFillScreen());
  delay(500);
 
  Serial.println(F("Done!"));
}
 
void loop(void)
{
  for (uint8_t rotation = 0; rotation < 4; rotation++)
  {
    tft.setRotation(rotation);
    testText();
    delay(1000);
  }
}
 
unsigned long testFillScreen()
{
  unsigned long start = micros();
  tft.fillScreen(ILI9341_BLACK);
  yield();
  tft.fillScreen(ILI9341_RED);
  yield();
  tft.fillScreen(ILI9341_GREEN);
  yield();
  tft.fillScreen(ILI9341_BLUE);
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
  return micros() - start;
}
 
unsigned long testText()
{
  tft.fillScreen(ILI9341_BLACK);
  unsigned long start = micros();
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(1);
  tft.println("Hello World!");
  tft.setTextColor(ILI9341_YELLOW);
  tft.setTextSize(2);
  tft.println(1234.56);
  tft.setTextColor(ILI9341_RED);
  tft.setTextSize(3);
  tft.println(0xDEADBEEF, HEX);
  tft.println();
  tft.setTextColor(ILI9341_GREEN);
  tft.setTextSize(5);
  tft.println("Groop");
  tft.setTextSize(2);
  tft.println("I implore thee,");
  tft.setTextSize(1);
  tft.println("my foonting turlingdromes.");
  tft.println("And hooptiously drangle me");
  tft.println("with crinkly bindlewurdles,");
  tft.println("Or I will rend thee");
  tft.println("in the gobberwarts");
  tft.println("with my blurglecruncheon,");
  tft.println("see if I don't!");
  return micros() - start;
}
 
unsigned long testLines(uint16_t color)
{
  unsigned long start, t;
  int x1, y1, x2, y2,
      w = tft.width(),
      h = tft.height();
 
  tft.fillScreen(ILI9341_BLACK);
  yield();
 
  x1 = y1 = 0;
  y2 = h - 1;
  start = micros();
  for (x2 = 0; x2 < w; x2 += 6)
    tft.drawLine(x1, y1, x2, y2, color);
  x2 = w - 1;
  for (y2 = 0; y2 < h; y2 += 6)
    tft.drawLine(x1, y1, x2, y2, color);
  t = micros() - start; // fillScreen doesn't count against timing
 
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
 
  x1 = w - 1;
  y1 = 0;
  y2 = h - 1;
  start = micros();
  for (x2 = 0; x2 < w; x2 += 6)
    tft.drawLine(x1, y1, x2, y2, color);
  x2 = 0;
  for (y2 = 0; y2 < h; y2 += 6)
    tft.drawLine(x1, y1, x2, y2, color);
  t += micros() - start;
 
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
 
  x1 = 0;
  y1 = h - 1;
  y2 = 0;
  start = micros();
  for (x2 = 0; x2 < w; x2 += 6)
    tft.drawLine(x1, y1, x2, y2, color);
  x2 = w - 1;
  for (y2 = 0; y2 < h; y2 += 6)
    tft.drawLine(x1, y1, x2, y2, color);
  t += micros() - start;
 
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
 
  x1 = w - 1;
  y1 = h - 1;
  y2 = 0;
  start = micros();
  for (x2 = 0; x2 < w; x2 += 6)
    tft.drawLine(x1, y1, x2, y2, color);
  x2 = 0;
  for (y2 = 0; y2 < h; y2 += 6)
    tft.drawLine(x1, y1, x2, y2, color);
 
  yield();
  return micros() - start;
}
 
unsigned long testFastLines(uint16_t color1, uint16_t color2)
{
  unsigned long start;
  int x, y, w = tft.width(), h = tft.height();
 
  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for (y = 0; y < h; y += 5)
    tft.drawFastHLine(0, y, w, color1);
  for (x = 0; x < w; x += 5)
    tft.drawFastVLine(x, 0, h, color2);
 
  return micros() - start;
}
 
unsigned long testRects(uint16_t color)
{
  unsigned long start;
  int n, i, i2,
      cx = tft.width() / 2,
      cy = tft.height() / 2;
 
  tft.fillScreen(ILI9341_BLACK);
  n = min(tft.width(), tft.height());
  start = micros();
  for (i = 2; i < n; i += 6)
  {
    i2 = i / 2;
    tft.drawRect(cx - i2, cy - i2, i, i, color);
  }
 
  return micros() - start;
}
 
unsigned long testFilledRects(uint16_t color1, uint16_t color2)
{
  unsigned long start, t = 0;
  int n, i, i2,
      cx = tft.width() / 2 - 1,
      cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  n = min(tft.width(), tft.height());
  for (i = n; i > 0; i -= 6)
  {
    i2 = i / 2;
    start = micros();
    tft.fillRect(cx - i2, cy - i2, i, i, color1);
    t += micros() - start;
    // Outlines are not included in timing results
    tft.drawRect(cx - i2, cy - i2, i, i, color2);
    yield();
  }
 
  return t;
}
 
unsigned long testFilledCircles(uint8_t radius, uint16_t color)
{
  unsigned long start;
  int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;
 
  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for (x = radius; x < w; x += r2)
  {
    for (y = radius; y < h; y += r2)
    {
      tft.fillCircle(x, y, radius, color);
    }
  }
 
  return micros() - start;
}
 
unsigned long testCircles(uint8_t radius, uint16_t color)
{
  unsigned long start;
  int x, y, r2 = radius * 2,
            w = tft.width() + radius,
            h = tft.height() + radius;
 
  // Screen is not cleared for this one -- this is
  // intentional and does not affect the reported time.
  start = micros();
  for (x = 0; x < w; x += r2)
  {
    for (y = 0; y < h; y += r2)
    {
      tft.drawCircle(x, y, radius, color);
    }
  }
 
  return micros() - start;
}
 
unsigned long testTriangles()
{
  unsigned long start;
  int n, i, cx = tft.width() / 2 - 1,
            cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  n = min(cx, cy);
  start = micros();
  for (i = 0; i < n; i += 5)
  {
    tft.drawTriangle(
        cx, cy - i,     // peak
        cx - i, cy + i, // bottom left
        cx + i, cy + i, // bottom right
        tft.color565(i, i, i));
  }
 
  return micros() - start;
}
 
unsigned long testFilledTriangles()
{
  unsigned long start, t = 0;
  int i, cx = tft.width() / 2 - 1,
         cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for (i = min(cx, cy); i > 10; i -= 5)
  {
    start = micros();
    tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
                     tft.color565(0, i * 10, i * 10));
    t += micros() - start;
    tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
                     tft.color565(i * 10, i * 10, 0));
    yield();
  }
 
  return t;
}
 
unsigned long testRoundRects()
{
  unsigned long start;
  int w, i, i2,
      cx = tft.width() / 2 - 1,
      cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  w = min(tft.width(), tft.height());
  start = micros();
  for (i = 0; i < w; i += 6)
  {
    i2 = i / 2;
    tft.drawRoundRect(cx - i2, cy - i2, i, i, i / 8, tft.color565(i, 0, 0));
  }
 
  return micros() - start;
}
 
unsigned long testFilledRoundRects()
{
  unsigned long start;
  int i, i2,
      cx = tft.width() / 2 - 1,
      cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for (i = min(tft.width(), tft.height()); i > 20; i -= 6)
  {
    i2 = i / 2;
    tft.fillRoundRect(cx - i2, cy - i2, i, i, i / 8, tft.color565(0, i, 0));
    yield();
  }
 
  return micros() - start;
}

 

CCS811 digital gas sensor and ESP8266 example

CCS811 is a low-power digital gas sensor solution, which integrates a gas sensor solution for detecting low levels of VOCs typically found indoors, with a microcontroller unit (MCU) and an Analog-to-Digital converter to monitor the local environment and provide an indication of the indoor air quality via an equivalent CO2 or TVOC output over a standard I2C digital interface.

Features

Integrated MCU
On-board processing
Standard digital interface
Optimised low power modes
IAQ threshold alarms
Programmable baseline
2.7mm x 4.0mm LGA package
Low component count
Proven technology platform

Specs

Interface I²C
Supply Voltage [V] 1.8 to 3.6
Power Consumption [mW] 1.2 to 46
Dimension [mm] 2.7 x 4.0 x 1.1 LGA
Ambient Temperature Range [°C] -40 to 85
Ambient Humidity Range [% r.h.] 10 to 95

Parts List

 

Amount Part Type
1 CJMCU-811 CCS811 Air Quality Gas Sensor
1 Wemos D1 mini V2

 

Schematics/Layout

Remember and connect WAKE to gnd

esp8266 and ccs811

esp8266 and ccs811

 

Code

Again we use a library –

And this ios the out of the box example

#include "Adafruit_CCS811.h"
Adafruit_CCS811 ccs;
void setup() {
Serial.begin(9600);
Serial.println("CCS811 test");
if(!ccs.begin()){
Serial.println("Failed to start sensor! Please check your wiring.");
while(1);
}
//calibrate temperature sensor
while(!ccs.available());
float temp = ccs.calculateTemperature();
ccs.setTempOffset(temp - 25.0);
}
void loop() {
if(ccs.available()){
float temp = ccs.calculateTemperature();
if(!ccs.readData()){
Serial.print("CO2: ");
Serial.print(ccs.geteCO2());
Serial.print("ppm, TVOC: ");
Serial.print(ccs.getTVOC());
Serial.print("ppb Temp:");
Serial.println(temp);
}
else{
Serial.println("ERROR!");
while(1);
}
}
delay(500);
}

 

Output

Open the serial monitor – this is what I saw. The higher CO2 level was when I breathed on the sensor

CO2: 400ppm, TVOC: 0ppb Temp:35.34
CO2: 400ppm, TVOC: 0ppb Temp:34.42
CO2: 400ppm, TVOC: 0ppb Temp:34.04
CO2: 770ppm, TVOC: 56ppb Temp:32.90
CO2: 400ppm, TVOC: 0ppb Temp:32.53
CO2: 400ppm, TVOC: 0ppb Temp:31.67
CO2: 672ppm, TVOC: 41ppb Temp:30.59
CO2: 476ppm, TVOC: 11ppb Temp:27.43
CO2: 588ppm, TVOC: 28ppb Temp:29.09
CO2: 400ppm, TVOC: 0ppb Temp:30.95
CO2: 400ppm, TVOC: 0ppb Temp:31.67

 

Links

ccs811 datasheet

CJMCU-811 CCS811 Air Quality Gas Sensor