Tuesday, March 28, 2017

NodeMCU and Digital Sensors

The goal for the next few tutorials is to read data from a digital sensor, then output that data in various fashions. We will finish this series by discussing the shortcomings common to all of these approaches, and this will set the direction for future work.

The sensor we'll be using is called a BME280, which returns temperature, humidity, and barometric pressure. Using sea level air pressure, the sensor also returns an approximate altitude, too. Adafruit has developed an Arduino library for this sensor, and we'll be using that library.

Instructions for installing the Arduino IDE and the baseline ESP8266 board can be found in the earlier "Getting Started with the NodeMCU ESP8266 Board" tutorial.


Installing the Libraries
First, we install the BME280 library into the Arduino IDE. Well, actually, there are two libraries to install:

  • Adafruit Unified Sensor Driver
  • Adafruit BME280

The Adafruit Unified Sensor Driver library is an abstraction layer that provides a unified interface for numerous types of sensors. One of the ways this interface "unifies" these sensors is that sensor values will always be returned in metric (SI) units. A list of those sensors and an explanation of why an abstraction layer is a good thing can be found at https://github.com/adafruit/Adafruit_Sensor.

The Adafruit BME280 library implements the methods in the first library for the BME280.

To install these libraries, open the Arduino IDE, and choose the menu Sketch | Include Library | Manage Libraries..., and the Library Manager window will open:

Enter "Adafruit Unified Sensor" into the search box, and scroll through the results until you find the row titled "Adafruit Unified Sensor" library. Click the row, and a version drop-down list and an "Install" button will be displayed. Choose the latest version (currently 1.0.5) and click the "Install" button.

Note: once the Adafruit Unified Sensor Driver library is installed, we need not install it again when we use other sensors that depend on it.

Now install the BME280 library itself: in the search box, enter "Adafruit BME280", select the latest version (1.0.5 as of this writing) and click "Install".

Done and done!


Connecting the Sensor Using I2C
The BME280 comes mounted on a number of different breakout boards from different vendors. We will use the (overpriced) version from SparkFun Electronics - other vendors sell far less expensive versions. The SparkFun breakout board includes connection points for both I2C and SPI interfaces, and we will be using the I2C interface, which has the following pins: GND, 3.3V, SDA, and SCL. Connect the sensor to the ESP8266 as follows:

Notice that we used NodeMCU's D2 pin for SDA and NodeMCU's D1 pin for SCL. Those are the default I2C pins for the NodeMCU.


Read From the Sensor
Enter the following sketch:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*
 * BME280
 * 
 * By: Mike Klepper
 * Date: 28 March 2017
 * 
 * The BME280 is a humidity + temperature + barometric pressure sensor.
 * This program reads those values from that sensor, converts the values into various units,
 * then displays the results in the Serial Monitor. It is based upon code found 
 * at learn.adafruit.com.
 *
 * Connections using the SparkFun breakout board:
 * BME280 GND --> NodeMCU GND
 * BME280 3.3V --> NodeMCU 3V3
 * BME280 SDA --> NodeMCU D2
 * BME280 SCL --> NodeMCU D1
 */

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

const float SEA_LEVEL_PRESSURE_HPA = 1013.25;
const int DELAY = 2000;
const int STARTUP_DELAY = 500;

Adafruit_BME280 bme;

void setup() 
{
  Serial.begin(115200);
  Serial.println("BME280 Test");

  if(!bme.begin())
  {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1)
    {
        yield();
        delay(DELAY);
    }
  }
  delay(STARTUP_DELAY);
}

void loop() 
{
    // Temperature    
    float tempC = bme.readTemperature();
    float tempF = 9.0/5.0 * tempC + 32.0;

    Serial.println("Temperature:");
    printValueAndUnits(tempC, "*C");
    printValueAndUnits(tempF, "*F");
    Serial.println("");

    // Barometric pressure
    float pressurePascals = bme.readPressure();
    float pressureHectoPascals = pressurePascals / 100.0;
    float pressureInchesOfMercury = 0.000295299830714 * pressurePascals;

    Serial.println("Pressure:");
    printValueAndUnits(pressurePascals, "Pa");
    printValueAndUnits(pressureHectoPascals, "hPa");
    printValueAndUnits(pressureInchesOfMercury, "inHg");
    Serial.println("");

    // Humidity
    float humidity = bme.readHumidity();
    
    Serial.println("Humidity:");
    printValueAndUnits(humidity, "%");
    Serial.println("");

    // Approximate altitude
    float altitudeMeters = bme.readAltitude(SEA_LEVEL_PRESSURE_HPA);
    float altitudeFeet = 3.28 * altitudeMeters;
    
    Serial.println("Approx. Altitude:");
    printValueAndUnits(altitudeMeters, "m");
    printValueAndUnits(altitudeFeet, "ft");
    Serial.println();

    Serial.println();
    yield();
    delay(DELAY);
}

void printValueAndUnits(float value, String units)
{
    Serial.print("     ");
    Serial.print(value);
    Serial.print(" ");
    Serial.println(units);
}

Again, D2 and D1 are NodeMCU's default pins for SDA and SCL, respectively. Using a different ESP8266 board will entail specifying those pins in the code, as explained on the Adafruit site.

The code is self explanatory, except for the following:

Line 19 - Wire.h is Arduino's default library for communicating with I2C devices, like the BME280.
Line 23 - The value chosen for SEA_LEVEL_PRESSURE_HPA is the average air pressure at sea-level, measured in hectoPascals.

Save it, then choose "NodeMCU 1.0 (ESP-12E Module)" under Tools | Board and choose the right port under Tools | Port. Flash the code to the NodeMCU, and open the serial monitor once it has done uploading:

These results don't exactly match the results returned by the local weatherman, but they were taken while the sensor is in a (rather warm) public library.

3 comments:

  1. Hi Mike,

    This is a great post and I have been trying to recreate your project, however, I my BME280 sensor won't read anything. I am using a generic BME sensor which is got SCL, SDA, CSB & SD0 pins. I am guessing this is a spi module but I can't get anything working. Since what you made is the closest to what I want to achieve, can you please help me.

    ReplyDelete
    Replies
    1. Hi Soubir,

      Yes, it sounds like you do have a SPI module. Try this:

      https://learn.adafruit.com/adafruit-bmp280-barometric-pressure-plus-temperature-sensor-breakout/wiring-and-test#spi-wiring

      Apparently Adafruit's library does support SPI, so that should be a good start.

      Hope this helps,
      Mike K

      Delete
  2. Soubir Paul, I am quiet sure you have a BME sensor with I2C, just because of the SCL/SDA !
    SPI is using leads like MISO and MOSI.

    On your BME CSB is the chip select, you can switch the chip on and off.
    SD0 is the address select. By default, the i2c address is 0x77. If you add a jumper from SDO to GND, the address will change to 0x76.

    ReplyDelete