Skip to content

Instantly share code, notes, and snippets.

@jamargevicius
Last active February 1, 2022 00:42
Show Gist options
  • Save jamargevicius/93e34964ac77843f27d0d63513cd2f09 to your computer and use it in GitHub Desktop.
Save jamargevicius/93e34964ac77843f27d0d63513cd2f09 to your computer and use it in GitHub Desktop.
FirebaseESP32example
/*********
Rui Santos -- main for 3_4_Streaming_Database_ESP32
Complete instructions at https://RandomNerdTutorials.com/firebase-esp32-esp8266-ebook/
educational rewrite by JoeM 1/28/22
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/
#include <Arduino.h>
#include <WiFi.h>
#include <Firebase_ESP_Client.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include "addons/TokenHelper.h" // Provide the token generation process info.
#include "addons/RTDBHelper.h" // Provide the RTDB payload printing info and other helper functions.
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
/*************** constants and variables **************/
#define WIFI_SSID "X" // fill in your info
#define WIFI_PASSWORD "X"
#define WEB_API_KEY "X" // under settings
#define USER_EMAIL "X"
#define USER_PASSWORD "X"
#define DATABASE_URL "X"
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
String uid;
String databasePath;
String tempPath;
String humPath;
String presPath;
String listenerPath;
String message; // Variable to save input message
float temperature; // used for the BME280 sensor
float humidity;
float pressure;
unsigned long sendDataPrevMillis = 0; // Timer variables (send new readings every three minutes)
unsigned long timerDelay = 180000;
int dutyCycle1;
int dutyCycle2;
const int redSliderLED = 25; // aka slider1 pin GPIO-13
const int greenSliderLED = 27; // aka slider2 pin GPIO-14
const int yellowLED = 12; // aka output1 pin GPIO-2
const int blueLED = 13; // aka output2 pin GPIO-12
const int redSliderChannel = 0; // Select PWM channels (16 available)
const int greenSliderChannel = 1;
const int freq = 5000;
const int resolution = 8;
/************* objects ********************/
FirebaseData fbdo; // Define Firebase objects
FirebaseAuth auth;
FirebaseConfig config;
FirebaseData stream;
Adafruit_BME280 bme; // BME & OLED: assigns & uses I2C pins = GPIO 21,22
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
/****************** Misc Modules **************/
void sendFloat(String path, float value){ // Write float values to the database
if (Firebase.RTDB.setFloat(&fbdo, path.c_str(), value)){
Serial.print("Writing value: "); Serial.print (value);
Serial.print(" on the following path: "); Serial.println(path);
Serial.println("PASSED");
Serial.println("PATH: " + fbdo.dataPath());
Serial.println("TYPE: " + fbdo.dataType()); }
else {
Serial.println("FAILED"); Serial.println("REASON: " + fbdo.errorReason()); }}
void displayMessage(String message){ // Display messag on OLED display
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0,0);
display.setTextColor(WHITE);
display.print(message);
display.display();}
void streamCallback(FirebaseStream data){ // Callback function that runs on database changes
// Note: this function is called whenever there is a change in the database
// ... but also called on startup. Checking the path that triggered it will now be done
Serial.printf("stream path, %s\nevent path, %s\ndata type, %s\nevent type, %s\n\n",
data.streamPath().c_str(),data.dataPath().c_str(),data.dataType().c_str(), data.eventType().c_str());
printResult(data); Serial.println(); //see addons/RTDBHelper.h
String streamPath = String(data.dataPath()); // Get the path that triggered the function
Serial.print("just receive a callback. The path is: "); Serial.println(streamPath);
// When it first runs, it is triggered on the root (/) path and returns a JSON with all key and values of that path.
// Start checking the path to see what caused the callback
// on startup it's triggered and the path the whole database; initialize everything
if (data.dataTypeEnum() == fb_esp_rtdb_data_type_json){ // is stream json-like?
Serial.println("just entered the / section - will update all LEDs and the OLED");
FirebaseJson *json = data.to<FirebaseJson *>(); // create a FirebaseJson object
// The ESP Firebase client library has its own integrated json library. This stream must be converted
// to a FirebaseJson object to be able to interrogate it. So create an object that the name json will refer to
FirebaseJsonData result; // create a Firebase object to store parts of the stream json file
if (json->get(result, "/onOffLEDs/yellowLED", false)){ // True is there is an entry ("false = kind of json)
bool state = result.to<bool>();
Serial.print("yellowLED being updated to: "); Serial.println(state);
digitalWrite(yellowLED, state); }
if (json->get(result, "/onOffLEDs/blueLED", false)){ // True is there is an entry
bool state2 = result.to<bool>();
Serial.print("blueLED being updated to: "); Serial.println(state2);
digitalWrite(blueLED, state2); }
if (json->get(result, "/pwmLEDs/redSliderLED", false)){
int pwmValue = result.to<int>();
Serial.print("pwm value for redSliderLED being updated to: "); Serial.println(pwmValue);
ledcWrite(redSliderChannel, map(pwmValue, 0, 100, 0, 255)); }
if (json->get(result, "/pwmLEDs/greenSliderLED", false)){
int pwmValue = result.to<int>();
Serial.print("value of pwmValue for greenSliderLED is: "); Serial.println(pwmValue);
ledcWrite(greenSliderChannel, map(pwmValue, 0, 100, 0, 255)); }
if (json->get(result, "/message", false)){
String message = result.to<String>();
displayMessage(message); } // display on OLED
}
// Is the path of the change in the yellowLED ?
if(streamPath.indexOf("/yellowLED") >= 0){
Serial.println("just caught callback due to yellowLED changing");
if(data.dataType() == "int") { // Get the data published on the stream path (it's the GPIO state)
bool gpioState = data.intData();
Serial.print("yellowLED changed. New value is: "); Serial.println(gpioState);
digitalWrite(yellowLED, gpioState); } //Update GPIO state
Serial.println(); }
if(streamPath.indexOf("/blueLED") >= 0){
Serial.println("just caught callback due to blueLED changing");
if(data.dataType() == "int") { // Get the data published on the stream path (it's the GPIO state)
bool gpioState = data.intData();
Serial.print("blueLED changed. New value is: "); Serial.println(gpioState);
digitalWrite(blueLED, gpioState); } //Update GPIO state
Serial.println(); }
if(streamPath.indexOf("/redSliderLED") >= 0){
Serial.println("just caught callback due to redSliderLED changing");
if(data.dataType() == "int"){
int PWMValue = data.intData(); // Get the PWM Value
Serial.print("redSliderLED changed. New value is: "); Serial.println(PWMValue);
ledcWrite(redSliderChannel, map(PWMValue, 0, 100, 0, 255)); }
Serial.println(); }
if(streamPath.indexOf("/greenSliderLED") >= 0){
Serial.println("just caught callback due to greenSliderLED changing");
if(data.dataType() == "int"){
int PWMValue = data.intData(); // Get the PWM Value
Serial.print("greenSliderLED changed. New value is: "); Serial.println(PWMValue);
ledcWrite(greenSliderChannel, map(PWMValue, 0, 100, 0, 255)); }
Serial.println(); }
// Is the path of change in the message ?
else if (streamPath.indexOf("/message") >= 0){
if (data.dataType() == "string") {
message = data.stringData();
Serial.print("MESSAGE: "); Serial.println(message);
displayMessage(message); } } // Display on OLED
Serial.printf("Received stream payload size: %d (Max. %d)\n\n", data.payloadLength(), data.maxPayloadLength());
}
//This is the size of stream payload received (current and max value)
//Max payload size is the payload size under the stream path since the stream connected
//and read once and will not update until stream reconnection takes place.
void streamTimeoutCallback(bool timeout){
if (timeout)
Serial.println("stream timeout, resuming...\n");
if (!stream.httpConnected())
Serial.printf("error code: %d, reason: %s\n\n", stream.httpCode(), stream.errorReason().c_str());}
/****************** initialization modules **************/
void initBME(){
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1); }}
void initWiFi() {
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000); }
Serial.println(WiFi.localIP());
Serial.println();}
void initOLED(){
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); }
display.clearDisplay();}
void initLEDs(){
pinMode(yellowLED, OUTPUT); // Initialize Outputs
pinMode(blueLED, OUTPUT);
ledcSetup(redSliderChannel, freq, resolution); // configure PWM functionalitites
ledcSetup(greenSliderChannel, freq, resolution);
ledcAttachPin(redSliderLED, redSliderChannel);
ledcAttachPin(greenSliderLED, greenSliderChannel); }
void initFirebaseStuff(){
config.api_key = WEB_API_KEY; // Assign the api key (required)
config.database_url = DATABASE_URL; // Assign the RTDB URL (required)
// when the UID token takes too long to generate, use tokenStatusCallback to know about it
config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h
config.max_token_generation_retry = 5; // Assign the maximum retry of token generation
auth.user.email = USER_EMAIL; // Assign the user sign in credentials
auth.user.password = USER_PASSWORD;
Firebase.reconnectWiFi(true);
fbdo.setResponseSize(4096);
Firebase.begin(&config, &auth); // Initialize the library with the Firebase authen and config
// build datbase path - need User ID to know where data is
Serial.println("Getting User UID"); // Getting the user UID might take a few seconds
while ((auth.token.uid) == "") {Serial.print('.'); delay(1000); }
uid = auth.token.uid.c_str();
Serial.print("User UID: "); Serial.println(uid);
databasePath = "/UsersData/" + uid; // Update database path
tempPath = databasePath + "/BME280_readings/temperature"; // define where data is found
humPath = databasePath + "/BME280_readings/humidity";
presPath = databasePath + "/BME280_readings/pressure";
listenerPath = databasePath + "/LED+Display/"; // Update database path for listening
// Whenever data changes on a path, begin stream on a database path --> UsersData/<user_uid>/LED+Display
if (!Firebase.RTDB.beginStream(&stream, listenerPath.c_str())) // start a listener stream; if not, print error
Serial.printf("stream begin error, %s\n\n", stream.errorReason().c_str());
// Assign a callback function to run when it detects changes on the database
Firebase.RTDB.setStreamCallback(&stream, streamCallback, streamTimeoutCallback);
delay(2000); }
/************** Initialization (setup) *****************/
void setup(){
Serial.begin(115200);
initBME();
initOLED();
initWiFi();
initLEDs();
initFirebaseStuff(); }
/************** main (loop) *********************/
void loop(){
if (Firebase.ready() && (millis() - sendDataPrevMillis > timerDelay || sendDataPrevMillis == 0)){
sendDataPrevMillis = millis(); // mark time
temperature = 1.8 * bme.readTemperature() + 32; // Get latest sensor readings
humidity = bme.readHumidity();
pressure = bme.readPressure() * 0.000009869; // in atmospheres
sendFloat(tempPath, temperature); // Send readings to database:
sendFloat(humPath, humidity);
sendFloat(presPath, pressure); }}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment