-
-
Save jamargevicius/93e34964ac77843f27d0d63513cd2f09 to your computer and use it in GitHub Desktop.
FirebaseESP32example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/********* | |
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