IoT Temperature Monitoring System
Powered by QBFT Blockchain Technology
System Overview
This project implements a decentralized IoT temperature monitoring system using QBFT (Quorum Byzantine Fault Tolerant) blockchain technology. Two ESP32 microcontrollers communicate through a blockchain network to ensure immutable, tamper-proof data storage.
Decentralized Storage
QBFT consensus ensures data integrity across 5 validator nodes
Immutable Records
Temperature data stored permanently on blockchain
Real-time Communication
Instant data transmission between IoT devices
Alert System
Automatic notifications for temperature thresholds
Key Components
- ESP32 Device 1: Simulates and sends temperature data
- ESP32 Device 2: Receives and displays temperature data
- Blockchain Network: 5-node QBFT network for consensus
- Backend Server: Node.js API bridge between devices and blockchain
System Requirements
Minimum Hardware Requirements
| Component | Requirement |
|---|---|
| CPU | 2 cores or more |
| RAM | 4GB minimum, 8GB recommended |
| Storage | 10GB free space |
| ESP32 Boards | 2x ESP32 Development Boards |
Software Prerequisites
1. Node.js & npm
# Install Node.js v22.x
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs
# Verify installation
node --version # Should output: v22.21.0 or later
npm --version # Should output: 10.9.4 or later
2. GoQuorum
# Download GoQuorum v24.4.1
cd ~
# File given in github
# Extract
tar -xvf geth_v24.4.1_linux_amd64.tar.gz
# Install globally
sudo mv geth /usr/local/bin/
sudo mv bootnode /usr/local/bin/
# Verify installation
geth version
3. Arduino IDE & ESP32 Support
# Install Arduino IDE
sudo snap install arduino
https://dl.espressif.com/dl/package_esp32_index.json
Architecture
System Data Flow
ESP32-1
Temperature Sender
Backend API
Node.js Server
QBFT Network
5 Validator Nodes
ESP32-2
Temperature Receiver
Data Flow Process
- Temperature Generation: ESP32-1 simulates temperature (20-30°C)
- HTTP POST: Device sends JSON payload to backend API
- Blockchain Transaction: Backend creates signed transaction
- QBFT Consensus: 5 validator nodes reach consensus
- Block Creation: Transaction included in new block (5s intervals)
- Data Retrieval: ESP32-2 queries backend via HTTP GET
- Display: Temperature displayed with alerts
Installation Guide
Phase 1: Project Files Setup
git clone https://github.com/Arasulingam/QBFT-Quorum.git
cd QBFT-Network
# Verify directory structure
ls -la QBFT-Network/
Phase 2: Backend Dependencies
# Navigate to backend directory
cd ~/QBFT-Network/server/iot-blockchain-backend
# Install Node.js dependencies
npm install
# Verify installation
npm list --depth=0
body-parser@1.20.2, cors@2.8.5, dotenv@16.0.3, express@4.18.2, web3@1.10.0
Network Configuration
| Parameter | Value |
|---|---|
| Chain ID | 1337 |
| Consensus | QBFT (Byzantine Fault Tolerant) |
| Block Period | 5 seconds |
| Validators | 5 nodes |
| Gas Price | 0 (free transactions) |
Running the System
Step 1: Start QBFT Blockchain Network
Terminal 1 - Node 0 (RPC: 22000, P2P: 30300)
cd /home/arasu/QBFT-Network/QBFT-Network/Node-0
export ADDRESS=$(grep -o '"address": *"[^"]*"' ./data/keystore/accountKeystore | grep -o '"[^"]*"$' | sed 's/"//g')
export PRIVATE_CONFIG=ignore
geth --datadir data \
--networkid 1337 --nodiscover --verbosity 5 \
--syncmode full \
--istanbul.blockperiod 5 --mine --miner.threads 1 --miner.gasprice 0 --emitcheckpoints \
--http --http.addr 127.0.0.1 --http.port 22000 --http.corsdomain "*" --http.vhosts "*" \
--ws --ws.addr 127.0.0.1 --ws.port 32000 --ws.origins "*" \
--http.api admin,eth,debug,miner,net,txpool,personal,web3,istanbul \
--ws.api admin,eth,debug,miner,net,txpool,personal,web3,istanbul \
--unlock ${ADDRESS} --allow-insecure-unlock --password ./data/keystore/accountPassword \
--port 30300
Terminal 2 - Node 1 (RPC: 22001, P2P: 30301)
cd /home/arasu/QBFT-Network/QBFT-Network/Node-1
export ADDRESS=$(grep -o '"address": *"[^"]*"' ./data/keystore/accountKeystore | grep -o '"[^"]*"$' | sed 's/"//g')
export PRIVATE_CONFIG=ignore
geth --datadir data \
--networkid 1337 --nodiscover --verbosity 5 \
--syncmode full \
--istanbul.blockperiod 5 --mine --miner.threads 1 --miner.gasprice 0 --emitcheckpoints \
--http --http.addr 127.0.0.1 --http.port 22001 --http.corsdomain "*" --http.vhosts "*" \
--ws --ws.addr 127.0.0.1 --ws.port 32001 --ws.origins "*" \
--http.api admin,eth,debug,miner,net,txpool,personal,web3,istanbul \
--ws.api admin,eth,debug,miner,net,txpool,personal,web3,istanbul \
--unlock ${ADDRESS} --allow-insecure-unlock --password ./data/keystore/accountPassword \
--port 30301
Repeat similar commands for Nodes 2, 3, and 4 with respective port numbers...
- INFO Started P2P networking - Node started successfully
- INFO Looking for peers peercount=4 - Connected to other nodes
- INFO IPC endpoint opened - RPC interface ready
Step 2: Start Backend Server
cd /home/arasu/QBFT-Network/server/iot-blockchain-backend
node server.js
🚀 Server running on port 3000
📡 Connected to blockchain: http://127.0.0.1:22000
📝 Contract address: 0xb5963eaf88065e44cd8f94ebd71b8bd7099c3ec3
Step 3: Verify System Status
# Health check
curl http://localhost:3000/health
# Check registered devices
curl http://localhost:3000/api/devices
ESP32 Configuration
Find Your Server IP Address
hostname -I
# Example output: 192.168.1.150
ESP32 Device 1 (Sender) - Key Configuration
#include
#include
#include
// WiFi credentials
const char* ssid = "";
const char* password = "";
// Backend server configuration
const char* serverUrl = "http://192.168.1.9:3000/api/temperature"; //YOUR IP
// Device configuration
const char* deviceId = "ESP32-TEMP-001";
const char* devicePrivateKey = "0x87123236c30996f3116601ed979e7b4f526e0f7c738e6c8a1ef843602059e05d"; // Get from blockchain account
// Temperature simulation settings
float baseTemperature = 25.0; // Base temperature in Celsius
float currentTemperature = 25.0;
bool simulateAlert = false; // Set true to test alerts
int readingCounter = 0;
// Timing configuration
unsigned long lastSendTime = 0;
const unsigned long sendInterval = 15000; // Send every 15 seconds (faster for demo)
// LED indicator
#define LED_BUILTIN 2
void setup() {
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
// Seed random number generator
randomSeed(analogRead(0));
Serial.println("\n\n=================================");
Serial.println("ESP32 Temperature Sender (SIMULATED)");
Serial.println("=================================\n");
Serial.println("⚠️ SIMULATION MODE - No sensor required");
Serial.println("Generating realistic temperature data...\n");
// Connect to WiFi
connectToWiFi();
Serial.println("\nDevice Configuration:");
Serial.print("Device ID: ");
Serial.println(deviceId);
Serial.print("Server URL: ");
Serial.println(serverUrl);
Serial.print("Base Temperature: ");
Serial.print(baseTemperature);
Serial.println(" °C");
Serial.println("\nStarting temperature monitoring...\n");
// Initial blink
for(int i = 0; i < 3; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(200);
digitalWrite(LED_BUILTIN, LOW);
delay(200);
}
}
void loop() {
// Check WiFi connection
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi disconnected! Reconnecting...");
connectToWiFi();
}
// Check for serial commands
checkSerialCommands();
// Send temperature at regular intervals
if (millis() - lastSendTime >= sendInterval) {
readAndSendTemperature();
lastSendTime = millis();
}
// Heartbeat blink (fast pulse every 2 seconds)
static unsigned long lastBlink = 0;
if (millis() - lastBlink > 2000) {
digitalWrite(LED_BUILTIN, HIGH);
delay(50);
digitalWrite(LED_BUILTIN, LOW);
lastBlink = millis();
}
delay(100);
}
void connectToWiFi() {
Serial.print("Connecting to WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n✓ WiFi Connected!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
Serial.print("Signal Strength: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
} else {
Serial.println("\n✗ WiFi Connection Failed!");
}
}
void readAndSendTemperature() {
Serial.println("\n--- Simulating Temperature Reading ---");
// Simulate realistic temperature with variations
currentTemperature = simulateTemperature();
Serial.print("📊 Reading #");
Serial.println(++readingCounter);
Serial.print("🌡️ Temperature: ");
Serial.print(currentTemperature, 2);
Serial.println(" °C");
// Show status
if (currentTemperature > 35.0) {
Serial.println("⚠️ HIGH TEMPERATURE ALERT!");
} else if (currentTemperature < 10.0) {
Serial.println("⚠️ LOW TEMPERATURE ALERT!");
} else {
Serial.println("✓ Temperature Normal");
}
// Send to blockchain via backend
sendToBlockchain(currentTemperature);
}
void sendToBlockchain(float temperature) {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
Serial.println("\n→ Sending to blockchain...");
// Create JSON payload
StaticJsonDocument<256> doc;
doc["deviceId"] = deviceId;
doc["temperature"] = temperature;
doc["privateKey"] = devicePrivateKey;
String jsonPayload;
serializeJson(doc, jsonPayload);
// Send HTTP POST request
http.begin(serverUrl);
http.addHeader("Content-Type", "application/json");
int httpResponseCode = http.POST(jsonPayload);
if (httpResponseCode > 0) {
String response = http.getString();
Serial.print("✓ HTTP Response code: ");
Serial.println(httpResponseCode);
Serial.println("Response:");
Serial.println(response);
// Parse response
StaticJsonDocument<512> responseDoc;
DeserializationError error = deserializeJson(responseDoc, response);
if (!error) {
if (responseDoc["success"] == true) {
Serial.println("✓ Temperature recorded on blockchain!");
Serial.print("Transaction Hash: ");
Serial.println(responseDoc["transactionHash"].as());
Serial.print("Block Number: ");
Serial.println(responseDoc["blockNumber"].as());
// Blink LED rapidly to indicate success
for (int i = 0; i < 5; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
}
} else {
Serial.println("✗ Blockchain transaction failed!");
}
}
} else {
Serial.print("✗ HTTP Error code: ");
Serial.println(httpResponseCode);
Serial.println(http.errorToString(httpResponseCode).c_str());
}
http.end();
} else {
Serial.println("✗ WiFi not connected!");
}
}
// Simulate realistic temperature with variations
float simulateTemperature() {
static float temp = baseTemperature;
static unsigned long lastChangeTime = 0;
static int alertCycle = 0;
unsigned long currentTime = millis();
// Every 10 readings, trigger an alert for testing
if (readingCounter > 0 && readingCounter % 10 == 0 && simulateAlert) {
alertCycle++;
if (alertCycle % 2 == 0) {
// High temperature alert
temp = 36.0 + random(0, 30) / 10.0; // 36.0 to 39.0°C
Serial.println("🔥 Simulating HIGH temperature spike!");
} else {
// Low temperature alert
temp = 8.0 + random(0, 20) / 10.0; // 8.0 to 10.0°C
Serial.println("❄️ Simulating LOW temperature drop!");
}
lastChangeTime = currentTime;
return temp;
}
// Normal operation: gradual temperature changes
if (currentTime - lastChangeTime > 5000) { // Change every 5 seconds
// Random walk: small changes
float change = (random(-50, 51)) / 100.0; // -0.5 to +0.5°C
temp += change;
// Keep within realistic bounds (15-32°C for normal operation)
if (temp < 18.0) temp = 18.0 + random(0, 20) / 10.0;
if (temp > 30.0) temp = 30.0 - random(0, 20) / 10.0;
lastChangeTime = currentTime;
}
// Add small random noise
float noise = (random(-10, 11)) / 100.0; // ±0.1°C
return temp + noise;
}
// Simulate different temperature patterns
void setSimulationMode(int mode) {
switch(mode) {
case 1: // Normal room temperature
baseTemperature = 22.0;
simulateAlert = false;
Serial.println("Mode: Normal Room (22°C)");
break;
case 2: // Server room
baseTemperature = 25.0;
simulateAlert = false;
Serial.println("Mode: Server Room (25°C)");
break;
case 3: // Hot environment
baseTemperature = 32.0;
simulateAlert = true;
Serial.println("Mode: Hot Environment (32°C + alerts)");
break;
case 4: // Cold environment
baseTemperature = 15.0;
simulateAlert = true;
Serial.println("Mode: Cold Environment (15°C + alerts)");
break;
default:
baseTemperature = 25.0;
simulateAlert = false;
}
currentTemperature = baseTemperature;
}
// Check for serial commands to change simulation
void checkSerialCommands() {
if (Serial.available() > 0) {
char cmd = Serial.read();
switch(cmd) {
case '1':
setSimulationMode(1);
break;
case '2':
setSimulationMode(2);
break;
case '3':
setSimulationMode(3);
break;
case '4':
setSimulationMode(4);
break;
case 'h':
case 'H':
// Force high temperature
currentTemperature = 38.0;
Serial.println("🔥 FORCED HIGH TEMP: 38°C");
break;
case 'l':
case 'L':
// Force low temperature
currentTemperature = 5.0;
Serial.println("❄️ FORCED LOW TEMP: 5°C");
break;
case 'n':
case 'N':
// Reset to normal
currentTemperature = baseTemperature;
Serial.println("✓ Reset to normal");
break;
case '?':
printHelp();
break;
}
}
}
void printHelp() {
Serial.println("\n=== SIMULATION COMMANDS ===");
Serial.println("1 - Normal Room (22°C)");
Serial.println("2 - Server Room (25°C)");
Serial.println("3 - Hot Environment (32°C)");
Serial.println("4 - Cold Environment (15°C)");
Serial.println("H - Force HIGH temp alert (38°C)");
Serial.println("L - Force LOW temp alert (5°C)");
Serial.println("N - Reset to Normal");
Serial.println("? - Show this help");
Serial.println("===========================\n");
}
ESP32 Device 2 (Receiver) - Key Configuration
/*
* ESP32 Temperature Receiver (Device 2 - Receiver/Display) - SIMULATION MODE
* Retrieves temperature data from blockchain via backend API
* Displays on Serial Monitor (no OLED needed!)
*
* Hardware Required:
* - ESP32 Development Board only (no display needed!)
*
* Features:
* - Fetches data from blockchain
* - Displays on Serial Monitor
* - Built-in LED for status/alerts
* - Buzzer optional (can be disabled)
*
* Libraries Required:
* - WiFi (built-in)
* - HTTPClient (built-in)
* - ArduinoJson (install via Library Manager)
*/
#include
#include
#include
// WiFi credentials
const char* ssid = "";
const char* password = "";
// Backend server configuration
const char* serverUrl = "http://192.168.1.9:3000/api/temperature/"; //YOUR_IP
const char* senderDeviceAddress = "0x5c303cef53e62c9ea820bacfc67066362c1daed7"; // Address of Device 1
// Device configuration
const char* deviceId = "ESP32-TEMP-002";
const char* devicePrivateKey = "0x1ada126eca1b7650a33834e7da8135e27df076b726c1339bef5a6743655683be";
// Pin definitions
#define LED_BUILTIN 2
#define BUZZER_PIN 25 // Optional: comment out if no buzzer
#define USE_BUZZER false // Set to true if you have a buzzer connected
// Temperature thresholds
const float HIGH_TEMP_THRESHOLD = 35.0; // °C
const float LOW_TEMP_THRESHOLD = 10.0; // °C
// Timing configuration
unsigned long lastFetchTime = 0;
const unsigned long fetchInterval = 10000; // Fetch every 10 seconds
// Temperature data
float currentTemperature = 0.0;
String lastUpdate = "";
String deviceIdReceived = "";
String location = "";
bool dataAvailable = false;
int fetchCounter = 0;
void setup() {
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
if (USE_BUZZER) {
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
}
Serial.println("\n\n====================================");
Serial.println("ESP32 Temperature Receiver (Display)");
Serial.println("====================================\n");
Serial.println("⚠️ SERIAL MONITOR MODE - No display hardware required");
Serial.println("Temperature data will be shown here\n");
// Connect to WiFi
connectToWiFi();
Serial.println("\n✓ Initialization complete!");
Serial.println("\nDevice Configuration:");
Serial.print("Device ID: ");
Serial.println(deviceId);
Serial.print("Monitoring Device: ");
Serial.println(senderDeviceAddress);
Serial.println("\nStarting data retrieval...");
Serial.println("=====================================\n");
// Initial LED pattern
for(int i = 0; i < 3; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(200);
digitalWrite(LED_BUILTIN, LOW);
delay(200);
}
delay(2000);
}
void loop() {
// Check WiFi connection
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi disconnected! Reconnecting...");
connectToWiFi();
}
// Fetch temperature at regular intervals
if (millis() - lastFetchTime >= fetchInterval) {
fetchTemperatureFromBlockchain();
lastFetchTime = millis();
}
// Heartbeat blink
static unsigned long lastBlink = 0;
if (millis() - lastBlink > 2000) {
digitalWrite(LED_BUILTIN, HIGH);
delay(50);
digitalWrite(LED_BUILTIN, LOW);
lastBlink = millis();
}
delay(100);
}
void connectToWiFi() {
Serial.print("Connecting to WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n✓ WiFi Connected!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
Serial.print("Signal Strength: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
} else {
Serial.println("\n✗ WiFi Connection Failed!");
}
}
void fetchTemperatureFromBlockchain() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
Serial.println("\n╔══════════════════════════════════════╗");
Serial.print("║ Fetch #");
Serial.print(++fetchCounter);
Serial.println(" - Querying Blockchain");
Serial.println("╚══════════════════════════════════════╝");
// Build URL
String url = String(serverUrl) + String(senderDeviceAddress);
http.begin(url);
http.addHeader("Content-Type", "application/json");
int httpResponseCode = http.GET();
if (httpResponseCode > 0) {
String response = http.getString();
// Parse JSON response
StaticJsonDocument<512> doc;
DeserializationError error = deserializeJson(doc, response);
if (!error) {
if (doc["success"] == true) {
currentTemperature = doc["data"]["temperature"];
lastUpdate = doc["data"]["timestamp"].as();
deviceIdReceived = doc["data"]["deviceId"].as();
location = doc["data"]["location"].as();
dataAvailable = true;
// Display in a nice format
displayTemperatureData();
// Check for alerts
checkTemperatureAlerts(currentTemperature);
} else {
Serial.println("✗ No data available");
dataAvailable = false;
}
} else {
Serial.print("✗ JSON parsing failed: ");
Serial.println(error.c_str());
}
} else {
Serial.print("✗ HTTP Error code: ");
Serial.println(httpResponseCode);
dataAvailable = false;
}
http.end();
} else {
Serial.println("✗ WiFi not connected!");
}
}
void displayTemperatureData() {
Serial.println("\n┌─────────────────────────────────────┐");
Serial.println("│ TEMPERATURE DATA RECEIVED │");
Serial.println("├─────────────────────────────────────┤");
Serial.print("│ Device ID : ");
Serial.println(deviceIdReceived);
Serial.print("│ Location : ");
Serial.println(location);
Serial.print("│ Temperature: ");
Serial.print(currentTemperature, 2);
Serial.println(" °C");
// Visual temperature bar
Serial.print("│ ");
int bars = map((int)(currentTemperature * 10), 0, 500, 0, 30);
for (int i = 0; i < bars && i < 30; i++) {
Serial.print("█");
}
Serial.println();
// Status indicator
Serial.print("│ Status : ");
if (currentTemperature > HIGH_TEMP_THRESHOLD) {
Serial.println("🔥 HIGH TEMP ALERT!");
} else if (currentTemperature < LOW_TEMP_THRESHOLD) {
Serial.println("❄️ LOW TEMP ALERT!");
} else {
Serial.println("✓ Normal");
}
Serial.print("│ Updated : ");
if (lastUpdate.length() > 11) {
Serial.println(lastUpdate.substring(11, 19));
} else {
Serial.println(lastUpdate);
}
Serial.print("│ WiFi Signal: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
Serial.println("└─────────────────────────────────────┘\n");
}
void checkTemperatureAlerts(float temperature) {
if (temperature > HIGH_TEMP_THRESHOLD) {
Serial.println("⚠️ HIGH TEMPERATURE ALERT!");
triggerAlert("HIGH", 3);
} else if (temperature < LOW_TEMP_THRESHOLD) {
Serial.println("⚠️ LOW TEMPERATURE ALERT!");
triggerAlert("LOW", 2);
}
}
void triggerAlert(String alertType, int beeps) {
// Beep buzzer
for (int i = 0; i < beeps; i++) {
digitalWrite(BUZZER_PIN, HIGH);
delay(200);
digitalWrite(BUZZER_PIN, LOW);
delay(200);
}
// Flash LED
for (int i = 0; i < 10; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
}
}
// Display historical data (if fetching history)
void displayHistory() {
// Fetch last 5 readings
String historyUrl = "http://192.168.1.9:3000/api/readings/" +
String(senderDeviceAddress) + "?limit=5"; //YOUR_IP
HTTPClient http;
http.begin(historyUrl);
int httpResponseCode = http.GET();
if (httpResponseCode > 0) {
String response = http.getString();
DynamicJsonDocument doc(2048);
DeserializationError error = deserializeJson(doc, response);
if (!error && doc["success"] == true) {
JsonArray data = doc["data"];
Serial.println("\n=== Temperature History ===");
for (JsonObject reading : data) {
Serial.print("Time: ");
Serial.print(reading["timestamp"].as());
Serial.print(" | Temp: ");
Serial.print(reading["temperature"].as());
Serial.println(" °C");
}
}
}
http.end();
}
Upload to ESP32
- Connect ESP32 via USB
- Open Arduino IDE
- Select: Tools → Board → ESP32 Dev Module
- Select: Tools → Port → (Your ESP32 COM port)
- Click: Upload (→ button)
- Open: Serial Monitor (Ctrl+Shift+M)
- Set baud rate to: 115200
ESP32 Temperature Sender (SIMULATED) ✓ WiFi Connected! IP Address: 192.168.1.105 📊 Reading #1 🌡️ Temperature: 25.23 °C ✓ Temperature recorded on blockchain!
API Reference
http://localhost:3000
1. Health Check
GET /health
Response:
{
"status": "OK",
"message": "IoT Blockchain Server is running"
}
2. Register Device
POST /api/register-device
Content-Type: application/json
{
"deviceAddress": "0x5c303cef53e62c9ea820bacfc67066362c1daed7",
"deviceId": "ESP32-TEMP-001",
"location": "Room-101"
}
Response:
{
"success": true,
"transactionHash": "0x4260c8065c765a623c06c5015f13e5fc85ed36b22a6f4d78d1a04bb92f703c5e",
"deviceAddress": "0x5c303cef53e62c9ea820bacfc67066362c1daed7",
"deviceId": "ESP32-TEMP-001",
"location": "Room-101"
}
3. Record Temperature
POST /api/temperature
Content-Type: application/json
{
"deviceId": "ESP32-TEMP-001",
"temperature": 25.5,
"privateKey": "0x87123236c30996f3116601ed979e7b4f526e0f7c738e6c8a1ef843602059e05d"
}
Response:
{
"success": true,
"transactionHash": "0xc366ab4a3e85302c8ac709e2b37d2837b9b36bf013315965981ea03735924d76",
"blockNumber": 531,
"deviceId": "ESP32-TEMP-001",
"temperature": 25.5,
"timestamp": "2025-10-24T12:00:16.033Z"
}
4. Get Latest Reading
GET /api/temperature/:deviceAddress
# Example
curl http://localhost:3000/api/temperature/0x5c303cef53e62c9ea820bacfc67066362c1daed7
Response:
{
"success": true,
"data": {
"timestamp": "2025-10-24T12:00:16.000Z",
"temperature": 25.5,
"deviceId": "ESP32-TEMP-001",
"location": "Room-101"
}
}
5. Get Device Readings History
GET /api/readings/:deviceAddress?limit=10
6. Get All Devices
GET /api/devices
Temperature Thresholds
| Alert Type | Threshold | Description |
|---|---|---|
| HIGH Alert 🔥 | > 35.0°C | Triggers high temperature warning |
| NORMAL ✓ | 10.0°C - 35.0°C | Temperature within safe range |
| LOW Alert ❄️ | < 10.0°C | Triggers low temperature warning |
Port Configuration
| Node | RPC (HTTP) | WebSocket | P2P (DevP2P) |
|---|---|---|---|
| Node-0 | 22000 | 32000 | 30300 |
| Node-1 | 22001 | 32001 | 30301 |
| Node-2 | 22002 | 32002 | 30302 |
| Node-3 | 22003 | 32003 | 30303 |
| Node-4 | 22004 | 32004 | 30304 |
Smart Contract: 0xb5963eaf88065e44cd8f94ebd71b8bd7099c3ec3
Troubleshooting
Issue 1: Port Already in Use
Fatal: Error starting protocol stack: listen tcp :30300: bind: address already in use
Solution:
# Find and kill existing geth processes
ps aux | grep geth
pkill geth
# Or kill specific port
lsof -ti:30300 | xargs kill -9
# Wait 5 seconds and restart node
Issue 2: Permission Denied
Fatal: Failed to create the protocol stack: open .../data/geth/LOCK: permission denied
Solution:
# Fix ownership of all directories
sudo chown -R $USER:$USER ~/QBFT-Network/
Issue 3: Nodes Not Connecting
Looking for peers peercount=0Dial error connection refused
Solution:
# Ensure all 5 nodes are running
ps aux | grep geth | wc -l # Should return 5
# Check static-nodes.json has correct IPs
cat ~/QBFT-Network/QBFT-Network/Node-0/data/static-nodes.json
# Verify ports are not blocked
netstat -tuln | grep -E "30300|30301|30302|30303|30304"
Issue 4: Backend Cannot Connect to Blockchain
Error: connection not open
Solution:
# Verify Node-0 is running and RPC is active
curl http://localhost:22000
# Check .env configuration
cat ~/QBFT-Network/server/iot-blockchain-backend/.env | grep BLOCKCHAIN_RPC
# Restart backend server
cd ~/QBFT-Network/server/iot-blockchain-backend
node server.js
Issue 5: ESP32 WiFi Connection Failed
✗ WiFi Connection Failed!
Solution:
- Verify WiFi credentials are correct
- Ensure using 2.4GHz network (ESP32 doesn't support 5GHz)
- Check WiFi signal strength
- Move ESP32 closer to router
- Verify SSID has no special characters
Issue 6: ESP32 HTTP Request Failed
✗ HTTP Error code: -1
Solution:
# Verify server IP address is correct
# Ping server from another device
ping 192.168.1.150
# Check firewall isn't blocking port 3000
sudo ufw status
sudo ufw allow 3000/tcp
# Ensure backend server is running
curl http://localhost:3000/health
Issue 7: Transaction Reverted
{"error":"Transaction has been reverted by the EVM"}
Solution:
# Check device is registered
curl http://localhost:3000/api/devices
# Verify contract address in .env
cat ~/QBFT-Network/server/iot-blockchain-backend/.env | grep CONTRACT_ADDRESS
Performance Metrics
| Metric | Value | Notes |
|---|---|---|
| Block Time | 5 seconds | Configurable in genesis |
| Transaction Finality | Immediate | QBFT provides instant finality |
| Data Send Interval | 15 seconds | ESP32-1 sends temperature |
| Data Fetch Interval | 10 seconds | ESP32-2 retrieves data |
| Network Latency | < 100ms | Local network |
| Consensus Threshold | 3 of 5 nodes | Byzantine fault tolerance |
| Maximum Downtime | 2 nodes | Network continues with 3+ nodes |
This configuration is for development and testing. For production deployment, implement proper key management, HTTPS, authentication, and firewall rules.
IoT Temperature Monitoring System with QBFT Blockchain
Built with ❤️ using ESP32, Node.js, and GoQuorum