Environmental Sensing Station using ESP8266 and Firebase

Inspiration

For my Film Prop, I built an environment sensing station that detects light, carbon monoxide levels, temperature, humidity, and outputs the data to a live realtime web based interface. The high level concept is the “Hab” that the astronauts live in suffered extreme damage during a Martian sandstorm, and the environment sensing and calibration system has been rendered un-useable. In order for the astronauts to be able to make repairs, they must first be able to get accurate data on the environment to ensure that it is human friendly. Thankfully, they were able to repurpose sensors on their spacesuit into this semi-mobile environmental sensing module and station.


Hardware

Sensors and Modules

Schematic and Wiring

MQ7 Carbon Monoxide Sensor
  • VCC -> Arudino 5V
  • Analog Out -> Arduino A0
  • GND -> Arduino GND
DHT11 Temperature and Humidity Sensor
  • VCC -> Arduino 5V
  • Data out -> Arduino D4
  • GND -> Arduino GND
LDR Sensor module
  • VCC -> Arduino 5V
  • Analog Out -> Arduino A1
  • GND -> Arduino GND
ESP8266
  • 3.3V -> Arduino 3.3V
  • CH_PD -> Arduino 3.3V
  • GND -> Arduino GND
  • RX -> Arduino D3
RGB LED
  • R -> ESP8266 TX
  • GND -> Arduino GND
  • G -> ESP8266 GPIO2

How to upload software to ESP8266

There are many libraries to interface with the ESP8266 using Arduino IDE. This project uses the library based on this tutorial. From what I can tell, this library is now deprecated and should not be used in production. The board and library versions depend on this deprecated library, and updating to a maintained ESP8266 Firebase library will require modifications to the provided code.

A few libraries I recommend using instead:

1. Install ESP866 board Manager

You need to first add a board manager for the ESP8266. This adds the necessary firmware to your Arduino IDE in order to compile and upload code to the ESP8266. Here are the steps to do that here. You should use the link below.

http://arduino.esp8266.com/stable/package_esp8266com_index.json

and the board selected should be:

Generic ESP8266 Module

2. BOOT esp8266 in Flash mode

In order to actually upload code to the ESP8266, you need to boot the module in flash mode. You can read more about it here.

  • GPIO0 must be pulled down to LOW (connect to Arduino GND)
  • CH_PD must be pulled up to HIGH (connect to Arduino 3.3V)

After this step, you should be able to now upload code to the ESP8266 through the Arduino IDE.

3. Code upload

Additionally, you need to pass the upload information to the ESP8266 through the Arduino, you can do this through RX/TX pins.

  • ESP8266 TX -> Arduino TX
  • ESP8266 RX -> Arduino RX

If you run into any errors:

  • Make sure that there is no serial monitor open when uploading code. If you are using the Arduino RX/TX to upload code to the ESP8266, then having a serial monitor open will interfere with the upload.
  • Make sure you have the correct esp8266 board version installed. For this project, it is 2.5.0

Database setup and webapp

1. Install ESP8266 and Firebase Libraries

Download and install the ESP8266 Firebase library here. Follow this tutorial to learn how to get the basic ESP8266 Firebase library working.

  • If you have trouble connecting to Firebase, verify that your hostname and authentication key are correct.
  • You may also need to update your fingerprint. Steps on how to do that are linked here.
2. WEbapp

Source code for the webapp is linked here. It is a React app built with Nextjs and Typescript. You can fork the repo.


Code Overview

WiFi setup code. Upload to ESP8266

#include <ESP8266WiFi.h>
#include <FirebaseArduino.h>
#include <SoftwareSerial.h>

// Secrets
#define FIREBASE_HOST "YOUR_HOST"
#define FIREBASE_AUTH "YOUR_TOKEN"
#define WIFI_SSID "WIFI_SSID"
#define WIFI_PASSWORD "WIFI_PASSWORD"

// Digital Pins
#define RX_PIN 3
#define TX_OR_RED_PIN 1
SoftwareSerial ArduinoSerial (RX_PIN, TX_OR_RED_PIN);

#define GREEN_PIN 2

const bool DEBUG = false;

void setup() 
{ 
  // Init LED
  pinMode(GREEN_PIN, OUTPUT);
  if (!DEBUG)
  {
    pinMode(TX_OR_RED_PIN, OUTPUT);
  }

  // Begin communication with arduino
  ArduinoSerial.begin(9600);

  // Init wifi
  initWifi();

  // Init firebase
  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); 
} 

 
void loop()
{
  if (WiFi.status() == WL_CONNECTED) 
  { //Check WiFi connection status
    sendWifiSuccess();
    readAndSendData();
  } 
  else 
  {
    sendWifiError();
  }
 
  delay(1000);  //Send a request every 1 second
}

void initWifi() {
  // connect to wifi. 
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  if (DEBUG)
  {
    ArduinoSerial.print("connecting"); 
  }
  while (WiFi.status() != WL_CONNECTED) { 
    if (DEBUG)
    {
      ArduinoSerial.print("."); 
    }
    delay(500);
  }
  if (DEBUG)
  {
    ArduinoSerial.println();
    ArduinoSerial.print("connected: ");
    ArduinoSerial.println(WiFi.localIP());
  }
}

void readAndSendData()
{
  while (ArduinoSerial.available() > 0)
  {
    //Create a place to hold the incoming message
    static char message[300];
    static unsigned int message_pos = 0;

    //Read the next available byte in the serial receive buffer
    char inByte = ArduinoSerial.read();

    //Message coming in (check not terminating character) and guard for over message size
    if ( inByte != '\n' && (message_pos < 300 - 1) )
    {
      //Add the incoming byte to our message
      message[message_pos] = inByte;
      message_pos++;
    }
    //Full message received...
    else
    {
      //Add null character to string
      message[message_pos] = '\0';

      // Attmpet construct JSON
      DynamicJsonBuffer jsonBuffer(300);
      static unsigned int jsonPos = 0;
      JsonObject& root = jsonBuffer.parseObject(message);

      // If successfully parsed message into json object
      if (root.success()) 
      {
        // send to firebase
        Firebase.set("data", root);

        // handle error
        if (Firebase.failed()) 
        {
          analogWrite(GREEN_PIN, 0);
          analogWrite(TX_OR_RED_PIN, 255);
          if (DEBUG)
          {
            ArduinoSerial.println("Failed to set data.");  
          }
        } 
        else 
        {
          analogWrite(GREEN_PIN,  255);
          if (DEBUG)
          {
            ArduinoSerial.println("Set data successfully."); 
          }
        }
      }
      // ... it's probably a string
      else 
      {
        if (DEBUG) 
        {
          // send back to arduino
          ArduinoSerial.println(message);
        }
      }
      // reset message position
      message_pos = 0;
    }
  }
}

void sendWifiSuccess() {
  if (DEBUG)
  {
    ArduinoSerial.println("Success: connected to wifi");
  }
  analogWrite(GREEN_PIN, 125);
  analogWrite(TX_OR_RED_PIN, 0);
}

void sendWifiError() {
  if (DEBUG)
  {
    ArduinoSerial.println("Error: could not connect to wifi");
  }
  analogWrite(GREEN_PIN, 0);
  analogWrite(TX_OR_RED_PIN, 125);
}

Sensor setup code. Upload to arduino.

#include <ArduinoJson.h>
#include <SoftwareSerial.h>
#include <DHT.h>

// Digital Pints
#define RX_PIN 2
#define TX_PIN 3
SoftwareSerial ESPSerial(RX_PIN, TX_PIN);

#define DHT_PIN 4
#define DHT_TYPE DHT11
DHT dht(DHT_PIN, DHT_TYPE);

// Analog Pins
#define MQ_PIN 0
#define LDR_PIN 1

const bool DEBUG = true;
const bool ESP_DEBUG = false;

int temperature;
int humidity;
int gas;
int light;

void setup() {
  // Init temperature sensor
  dht.begin();

  // Init serial monitor
  Serial.begin(9600);

  // Init communication with ESP8266
  ESPSerial.begin(9600);
}

void loop() {
  if (ESP_DEBUG)
  {
    readSerial();
  }
  getSensorData();
  sendData();
  delay(1000);
}

void sendData() {
  // construct json object
  StaticJsonBuffer<300> jsonBuffer;
  JsonObject& json = jsonBuffer.createObject();

  // add data
  json["temperature"] = temperature;
  json["humidity"] = humidity;
  json["gas"] = gas;
  json["light"] = light;

  // send to ESP8266
  json.printTo(ESPSerial);
  ESPSerial.println();

  if (DEBUG)
  {
    Serial.print("Sent to ESP: ");
    json.printTo(Serial);
    Serial.println();
  }
}

void readSerial() {
  while (ESPSerial.available() > 0)
  {
    //Create a buffer to hold the incoming message
    static char message[300];
    static unsigned int message_pos = 0;

    //Read the next available byte in the serial receive buffer
    char inByte = ESPSerial.read();

    //Message coming in (check not terminating character) and guard for over message size
    if ( inByte != '\n' && (message_pos < 300 - 1) )
    {
      //Add the incoming byte to our message
      message[message_pos] = inByte;
      message_pos++;
    }
    //Full message received...
    else
    {
      //Add null character to string
      message[message_pos] = '\0';

      //Print the message (or do other things)
      if (DEBUG)
      {
        Serial.println(message);
      }

      //Reset for the next message
      message_pos = 0;
    }
  }
}

void getSensorData() {
  temperature = dht.readTemperature();
  humidity = dht.readHumidity();
  gas = analogRead(MQ_PIN);
  light = analogRead(LDR_PIN);

  if (DEBUG)
  {
    Serial.print("Temperature: ");
    Serial.print(temperature);
    Serial.print(", Humidity: ");
    Serial.print(temperature);   
    Serial.print(", Gas: ");
    Serial.print(gas);
    Serial.print(", Light: ");
    Serial.println(light); 
  }
}

Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *