Version Overview
Firebase V1
Legacy ImplementationComplete wrapper with callbacks
Contains hardcoded credentials
Firebase V2
RecommendedSimplified service-specific classesReal-time streaming support
Firebase V3
EnterpriseSingleton architectureAdvanced Firestore features
Feature Comparison
| Feature | V1 | V2 | V3 |
|---|---|---|---|
| Realtime Database | ✅ | ✅ | ✅ |
| Firestore CRUD | ✅ | ✅ | ✅ |
| Firestore Advanced* | ❌ | ❌ | ✅ |
| Cloud Storage | ❌ | ✅ | ✅ |
| Cloud Messaging (FCM) | ✅ | ✅ | ✅ |
| Real-time Streaming | ❌ | ✅ | ❌ |
| Batch Operations | ❌ | ❌ | ✅ |
| Database Admin | ❌ | ❌ | ✅ |
| Service Account Auth | ⚠️ | ✅ | ✅ |
| Singleton Pattern | ❌ | ❌ | ✅ |
Dependencies
Add to yourplatformio.ini:
lib_deps =
# For Firebase V1
https://github.com/mobizt/Firebase-ESP-Client.git
# For Firebase V2 and V3
https://github.com/mobizt/FirebaseClient.git
# Common dependencies
bblanchon/ArduinoJson@^6.21.3
Firebase V2 (Recommended)
Simplified, service-specific implementation ideal for most projects.Realtime Database (RTDB)
Enable Module
#define ENABLE_MODULE_FIREBASE_RTDB_V2
#include "Kinematrix.h"
Basic Usage
#include <WiFi.h>
FirebaseV2RTDB rtdb;
WiFiClient client;
void setup() {
Serial.begin(115200);
WiFi.begin("SSID", "password");
while (WiFi.status() != WL_CONNECTED) delay(100);
// Initialize with user authentication
bool success = rtdb.begin(
client,
"https://your-project.firebaseio.com",
"YOUR_API_KEY",
"[email protected]",
"password"
);
if (success && rtdb.ready()) {
Serial.println("Firebase connected!");
}
}
Write Data
// Write different data types
rtdb.set("/sensors/temperature", 25.5);
rtdb.set("/sensors/humidity", 60);
rtdb.set("/status/online", true);
rtdb.set("/device/name", "ESP32-Sensor");
// Write JSON
const char* json = "{\"temp\":25.5,\"hum\":60}";
rtdb.set("/sensors/data", json);
Read Data
float temp = rtdb.getFloat("/sensors/temperature");
int humidity = rtdb.getInt("/sensors/humidity");
bool online = rtdb.getBool("/status/online");
String name = rtdb.getString("/device/name");
String jsonData = rtdb.getJSON("/sensors/data");
Serial.println("Temperature: " + String(temp));
Push Data (Auto-generated Keys)
// Push creates unique key for each entry
String key1 = rtdb.push("/logs", "System started");
String key2 = rtdb.push("/logs", "Sensor reading: 25.5");
Serial.println("Log ID: " + key1);
Update and Delete
// Update multiple fields
const char* updates = "{\"temp\":26.0,\"updated\":1234567890}";
rtdb.update("/sensors", updates);
// Delete path
rtdb.remove("/logs/old_data");
// Check if path exists
if (rtdb.exists("/sensors/temperature")) {
Serial.println("Temperature sensor exists");
}
Real-time Streaming
WiFiClient streamClient;
void setup() {
// ... WiFi and RTDB initialization ...
// Start streaming from path
rtdb.beginStream(streamClient, "/sensors");
}
void loop() {
rtdb.loop();
if (rtdb.hasStreamData()) {
String data = rtdb.getStreamData();
String path = rtdb.getStreamPath();
String event = rtdb.getStreamEvent();
Serial.println("Event: " + event);
Serial.println("Path: " + path);
Serial.println("Data: " + data);
}
if (rtdb.hasError()) {
Serial.println("Error: " + rtdb.getError());
}
}
Firestore Database
Enable Module
#define ENABLE_MODULE_FIREBASE_FIRESTORE_V2
#include "Kinematrix.h"
Basic Usage
FirebaseV2Firestore firestore;
void setup() {
Serial.begin(115200);
WiFi.begin("SSID", "password");
while (WiFi.status() != WL_CONNECTED) delay(100);
// Initialize with user authentication
firestore.begin(
"YOUR_API_KEY",
"[email protected]",
"password",
"your-project-id"
);
// Wait for ready
while (!firestore.isReady()) {
firestore.loop();
delay(100);
}
}
Create Documents
// Firestore requires specific JSON format
String createSensorDoc(float temp, float humidity) {
char json[256];
snprintf(json, sizeof(json),
"{"
"\"fields\": {"
"\"temperature\": {\"doubleValue\": %.2f},"
"\"humidity\": {\"doubleValue\": %.2f},"
"\"timestamp\": {\"integerValue\": %ld}"
"}"
"}",
temp, humidity, time(nullptr)
);
return String(json);
}
void loop() {
firestore.loop();
float temp = 25.5;
float humidity = 60.0;
String data = createSensorDoc(temp, humidity);
// Create document
firestore.createDocument(
"sensors/sensor1", // Document path
data, // JSON data
false // Don't wait for completion
);
// Check result
if (firestore.isResultReady()) {
String result = firestore.getLastPayload();
if (result.indexOf("error") >= 0) {
Serial.println("Error: " + result);
} else {
Serial.println("Document created!");
}
}
}
Read Documents
firestore.getDocument("sensors/sensor1", "", false);
while (!firestore.isResultReady()) {
firestore.loop();
delay(10);
}
String document = firestore.getLastPayload();
Serial.println(document);
Update and Delete
// Update document
String updateData =
"{"
"\"fields\": {"
"\"temperature\": {\"doubleValue\": 26.5}"
"}"
"}";
firestore.updateDocument(
"sensors/sensor1",
updateData,
"temperature", // Update mask (which fields to update)
false
);
// Delete document
firestore.deleteDocument("sensors/old_sensor", false);
List Documents
// List all documents in collection
firestore.listDocuments(
"sensors", // Collection path
10, // Page size
"", // Field mask (empty = all fields)
false
);
while (!firestore.isResultReady()) {
firestore.loop();
delay(10);
}
String documents = firestore.getLastPayload();
Serial.println(documents);
Practical Example: Sensor Logger
#include <WiFi.h>
#define ENABLE_MODULE_FIREBASE_FIRESTORE_V2
#include "Kinematrix.h"
FirebaseV2Firestore firestore;
unsigned long lastUpload = 0;
String deviceId;
void setup() {
Serial.begin(115200);
// Connect WiFi
WiFi.begin("SSID", "password");
while (WiFi.status() != WL_CONNECTED) delay(100);
// Generate device ID from MAC
deviceId = "ESP32_" + WiFi.macAddress();
deviceId.replace(":", "");
// Initialize Firestore
firestore.begin("API_KEY", "[email protected]", "password", "project-id");
while (!firestore.isReady()) {
firestore.loop();
delay(100);
}
Serial.println("Firestore ready!");
}
void loop() {
firestore.loop();
// Upload every 60 seconds
if (millis() - lastUpload >= 60000) {
lastUpload = millis();
// Read sensors
float temp = readTemperature();
float hum = readHumidity();
// Create document
char json[512];
snprintf(json, sizeof(json),
"{"
"\"fields\": {"
"\"temperature\": {\"doubleValue\": %.2f},"
"\"humidity\": {\"doubleValue\": %.2f},"
"\"deviceId\": {\"stringValue\": \"%s\"},"
"\"timestamp\": {\"integerValue\": %ld}"
"}"
"}",
temp, hum, deviceId.c_str(), time(nullptr)
);
String docPath = "sensor_data/" + deviceId + "_" + String(time(nullptr));
firestore.createDocument(docPath, json, false);
Serial.println("Data uploaded: " + String(temp) + "C, " + String(hum) + "%");
}
}
Cloud Storage
Enable Module
#define ENABLE_MODULE_FIREBASE_STORAGE_V2
#include "Kinematrix.h"
Basic Usage
FirebaseV2Storage storage;
void setup() {
Serial.begin(115200);
WiFi.begin("SSID", "password");
while (WiFi.status() != WL_CONNECTED) delay(100);
// Initialize storage
storage.begin(
"API_KEY",
"[email protected]",
"password",
"project-id",
"project-id.appspot.com" // Bucket ID
);
while (!storage.isReady()) {
storage.loop();
delay(100);
}
}
Upload Files
// Upload file from SD card or SPIFFS
storage.uploadFile(
"/data/sensor_log.csv", // Local file
"logs/sensor_log.csv", // Storage path
"text/csv", // MIME type
false // Async upload
);
// Check upload progress
while (!storage.isResultReady()) {
storage.loop();
int progress = storage.getUploadProgress();
Serial.println("Upload: " + String(progress) + "%");
delay(100);
}
Download Files
storage.downloadFile(
"logs/sensor_log.csv", // Storage path
"/data/downloaded.csv", // Local path
false
);
while (!storage.isResultReady()) {
storage.loop();
int progress = storage.getDownloadProgress();
Serial.println("Download: " + String(progress) + "%");
delay(100);
}
File Management
// Get file metadata
String metadata = storage.getFileMetadata("logs/sensor_log.csv", true);
Serial.println(metadata);
// List files with prefix
String fileList = storage.listFiles("logs/", 50, true);
Serial.println(fileList);
// Delete file
storage.deleteFile("logs/old_data.csv", true);
OTA Updates
// Perform OTA update from storage
bool success = storage.performOTA(
"firmware/device_v1.2.bin",
true // Wait for completion
);
if (success) {
Serial.println("OTA successful, restarting...");
ESP.restart();
} else {
Serial.println("OTA failed: " + storage.getLastError());
}
Cloud Messaging (FCM)
Enable Module
#define ENABLE_MODULE_FIREBASE_MESSAGING_V2
#include "Kinematrix.h"
Send to Token
FirebaseV2Messaging messaging;
void setup() {
Serial.begin(115200);
WiFi.begin("SSID", "password");
while (WiFi.status() != WL_CONNECTED) delay(100);
messaging.begin("API_KEY", "[email protected]", "password", "project-id");
while (!messaging.isReady()) {
messaging.loop();
delay(100);
}
}
void sendNotification(String deviceToken) {
messaging.setToken(deviceToken);
messaging.setNotification(
"Sensor Alert",
"Temperature exceeded threshold: 30C"
);
String messageId = messaging.sendMessage(false);
while (!messaging.isResultReady()) {
messaging.loop();
delay(10);
}
String result = messaging.getLastPayload();
Serial.println("Message sent: " + result);
}
Send to Topic
messaging.setTopic("sensor_alerts");
messaging.setNotification(
"System Alert",
"Multiple sensors offline"
);
messaging.sendMessage(false);
Send with Data Payload
messaging.setToken(deviceToken);
messaging.setNotification("Alert", "Check sensor");
// Add custom data
messaging.addData("sensor_id", "temp_01");
messaging.addData("value", "32.5");
messaging.addData("threshold", "30.0");
messaging.sendMessage(false);
Platform-Specific Configuration
// Android settings
messaging.setAndroidPriority(true); // High priority
messaging.setAndroidNotificationPriority(4); // MAX priority (0-4)
// iOS settings
messaging.addApnsHeader("apns-priority", "10");
messaging.sendMessage(false);
Firebase V3 (Enterprise)
Singleton architecture with advanced features for production applications.Architecture
V3 uses a centralizedFirebaseV3Application singleton for authentication, which all services share.
#define ENABLE_MODULE_FIREBASE_APPLICATION_V3
#define ENABLE_MODULE_FIREBASE_FIRESTORE_V3
#include "Kinematrix.h"
Initialize Application
FirebaseV3Application* app = FirebaseV3Application::getInstance();
void setup() {
Serial.begin(115200);
WiFi.begin("SSID", "password");
while (WiFi.status() != WL_CONNECTED) delay(100);
// Initialize with user auth
app->begin(
"API_KEY",
"[email protected]",
"password",
"project-id"
);
while (!app->isReady()) {
app->loop();
delay(100);
}
Serial.println("Firebase V3 ready!");
}
void loop() {
app->loop(); // Keep authentication alive
}
Service Account Authentication
const char* clientEmail = "[email protected]";
const char* privateKey = "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n";
app->begin(
clientEmail,
"project-id",
privateKey
);
Advanced Firestore
Initialize Service
FirebaseV3Application* app = FirebaseV3Application::getInstance();
FirebaseV3Firestore firestore(app); // Pass shared app
void setup() {
// ... initialize app ...
// Firestore automatically uses app's authentication
}
Database Administration
// Create new database
String dbId = firestore.createDatabase(
"production-db",
"us-central",
true // Wait for completion
);
// List all databases
String databases = firestore.listDatabases(true);
Serial.println(databases);
// Update database settings
firestore.updateDatabase(
"production-db",
true, // Enable point-in-time recovery
true
);
// Delete database
firestore.deleteDatabase("old-db", true);
Index Management
// Create index for queries
String indexId = firestore.createDatabaseIndex(
"sensors", // Collection
"timestamp", // Field 1
"temperature", // Field 2
true
);
// List indexes
String indexes = firestore.listDatabaseIndexes(true);
// Delete index
firestore.deleteDatabaseIndex(indexId, true);
Batch Operations
// Create batch write
Writes writes;
// Add multiple operations to batch
firestore.batchWrite(writes, false);
// Batch get multiple documents
firestore.batchGet("sensors/sensor1,sensors/sensor2", "", false);
Advanced Queries
// Run structured query
const char* query =
"{"
"\"structuredQuery\": {"
"\"from\": [{\"collectionId\": \"sensors\"}],"
"\"where\": {"
"\"fieldFilter\": {"
"\"field\": {\"fieldPath\": \"temperature\"},"
"\"op\": \"GREATER_THAN\","
"\"value\": {\"doubleValue\": 25.0}"
"}"
"},"
"\"orderBy\": [{"
"\"field\": {\"fieldPath\": \"timestamp\"},"
"\"direction\": \"DESCENDING\""
"}],"
"\"limit\": 10"
"}"
"}";
firestore.runQuery("sensors", query, false);
Field Transforms
// Increment field value
firestore.incrementFieldValue(
"counters/page_views",
"count",
1, // Increment by 1
false
);
// Set server timestamp
firestore.setServerTimestamp(
"sensors/sensor1",
"last_updated",
false
);
// Append to array
Values::ArrayValue newValues;
firestore.appendArray(
"sensors/sensor1",
"readings",
newValues,
false
);
Import/Export
// Export collection to Cloud Storage
firestore.exportDocuments(
"sensors", // Collection ID
"project-id.appspot.com", // Bucket
"backups/2024-03-03/", // Storage path
true
);
// Import from Cloud Storage
firestore.importDocuments(
"sensors",
"project-id.appspot.com",
"backups/2024-03-03/",
true
);
Authentication Methods
User Email/Password
// V2
rtdb.begin(client, "db-url", "api-key", "[email protected]", "password");
// V3
app->begin("api-key", "[email protected]", "password", "project-id");
Service Account
// V2 Firestore
firestore.begin(
"[email protected]",
"project-id",
"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
);
// V3
app->begin(clientEmail, "project-id", privateKey);
Anonymous
// V2 RTDB only
rtdb.beginAnonymous(client, "https://project.firebaseio.com");
// V3
app->beginAnonymous("project-id");
Best Practices
Never hardcode credentials in production code. Use environment variables or secure storage.
Always call loop() in your main loop to process Firebase events and maintain authentication.
Choose the right version:
- V2 for most projects (recommended)
- V3 for enterprise features (batch, queries, admin)
- Avoid V1 (security risks)
Error Handling
void loop() {
firestore.loop();
if (firestore.isResultReady()) {
String payload = firestore.getLastPayload();
// Check for errors in response
if (payload.indexOf("\"error\":") >= 0) {
Serial.println("Firebase Error: " + payload);
// Parse error for specific handling
if (payload.indexOf("PERMISSION_DENIED") >= 0) {
Serial.println("Check Firestore security rules");
}
} else {
// Success
Serial.println("Operation successful");
}
}
if (firestore.hasError()) {
Serial.println("Connection error: " + firestore.getLastError());
}
}
Migration Guide
V1 to V2
// V1
FirebaseModule firebase;
firebase.addData("value", "/path");
firebase.sendDataAsyncFloat(2000);
// V2
FirebaseV2RTDB rtdb;
rtdb.set("/path", value);
V2 to V3
// V2 - Each service has its own auth
FirebaseV2Firestore firestore;
firestore.begin(apiKey, email, password, projectId);
// V3 - Centralized authentication
FirebaseV3Application* app = FirebaseV3Application::getInstance();
app->begin(apiKey, email, password, projectId);
FirebaseV3Firestore firestore(app);
Next Steps
MQTT Communication
Set up MQTT for real-time device messaging
Cloud Integrations
Connect to Google Sheets, Telegram, WhatsApp