Search code examples
firebasefirebase-realtime-databasearduinoarduino-idenodemcu

How to upload data to Firebase using Nodemcu?


My sensor is collecting but not pushing the data to Firebase. As expected Firebase.failed returns true but Firebase.error is empty.

I tried changing the fingerprint in FirebaseHttpClient.h file. I also tried changing the Firebase HOST with and without "/".

#include "DHT.h"
#include <FirebaseArduino.h>
#include  <ESP8266WiFi.h>

#define FIREBASE_HOST "your-project.firebaseio.com"
#define FIREBASE_AUTH "69DtX********************"
#define WIFI_SSID "LAPTOP" // Change the name of your WIFI
#define WIFI_PASSWORD "********" // Change the password of your WIFI

#define DHTPIN 14    // Data Pin of DHT 11 , for NodeMCU D5 GPIO no. is 14

#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600);
  WiFi.begin (WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
   delay(500);
    Serial.print(".");
  }
   dht.begin();
  Serial.println ("");
  Serial.println ("WiFi Connected!");
  Firebase.begin(FIREBASE_HOST,FIREBASE_AUTH);
  
}

void loop() {
 
  float h = dht.readHumidity();
  
  float t = dht.readTemperature();  // Reading temperature as Celsius (the default)
  String firehumid = String(h) + String("%");
  String firetemp = String(t) + String("C");
  Serial.println("Humidity = ");
  Serial.println(h);
  Serial.println("Temperature = ");
  Serial.println(t); 
  Firebase.setString("/Humidity",firehumid);
  Firebase.setString("/Temperature",firetemp);
  delay(4000);
  if(Firebase.failed())
  {
    Serial.println("error!");
    Serial.println(Firebase.error());
  }
  
}

Solution

  • I ran into the same problem a few days ago with a sketch that worked about a year ago. Firebase.failed() returned true, but the error was empty.

    As far as I understand, the old way of using the realtime database with a secret is deprecated (as it states, on the database secrets page in your project settings), and there is the Firebase Admin SDK with OAuth 2.0 in the place of it.

    However, as of posting this, as far as I know, there is no Arduino library that supports this authentication for firebase directly, so I wanted to find an other way to make it work.

    I managed to find a workaround, which works for me, and I think is more suitable for these kinds of IOT applications, as it requires fewer resources on the sensors side.

    The solution for me was using Firebase Cloud Functions, with http triggers. Basically instead of using an Arduino library for Firebase, you can define JS functions, that can store or retrieve your data from the database, deploy them to Firebase and call them in your Arduino sketch through simple https and http calls.

    So the relevant part of my arduino sketch look like this:

        #include <ESP8266HTTPClient.h>
        HTTPClient http;
    
        // you will see this url, after you deployed your functions to firebase
        #define FIREBASE_CLOUDFUNCTION_URL "http://<your-function-url>.cloudfunctions.net/add"
    
        ...
    
        // Make sure you are connected to the internet before you call this function
        void uploadMeasurements(float lux, float ctemp, float hum) {
            String url = String(FIREBASE_CLOUDFUNCTION_URL) + "?lux=" + String(lux,2)
                                + "&temp=" + String(ctemp,2) + "&hum=" + String(hum,2); 
    
            http.begin(url);
            int httpCode = http.GET();
    
            // you don't have to handle the response, if you dont need it.
            String payload = http.getString();
            Serial.println(payload);
    
            http.end();
        }
    

    I put the measurements into the query params, but you can send them trought the body of the request as well.

    And my cloud function that stores the data looks like this:

        const functions = require('firebase-functions');
        const admin = require('firebase-admin');
        admin.initializeApp();
    
    
        exports.add = functions.https.onRequest((request, response)=>
        {
            console.log('Called with queries: ', request.query, ' and body: ', request.body);
            var ref = admin.database().ref("any/endpoint/child");
            var childRef = ref.push();
    
            let weatherData = {
                lux: request.query.lux,
                temp: request.query.temp,
                hum: request.query.hum,
                // this automatically fills this value, with the current time
                timestamp : admin.database.ServerValue.TIMESTAMP 
            };
    
            childRef.set(
                weatherData
            );
            response.status(200).send("OK!");
        });
    

    You can initialize a project that stores your cloud functions and can be deployed to Firebase with the Firebase CLI, calling firebase init in your project folder, and than selecting cloudfunctions through the setup process (I selected hosting as well, because I have a frontend to view the collected data.)

    Right now, I have a little sensor that uses this solution, and uploads measurements every minute, and it works without any problem.

    I hope this helped.