RoboQuake Live - ADXL345 Accelerometer Data
Real-time vibration and seismic activity monitoring
LIVE DATA STREAM
📥 ESP32 Configuration
API Endpoint URL:
https://globalwarningnetworks.com/esp32.php?api=receive
Your ESP32 should POST JSON data to this endpoint with device_id, x, y, z, and rms values.
// Complete ESP32 Code with RoboQuake Detection:
#include <WiFi.h>
#include <Wire.h>
#include <Adafruit_ADXL345_U.h>
#include <WebServer.h>
#include <HTTPClient.h>
const char* ssid = "YOUR_WIFI";
const char* password = "YOUR_PASS";
const char* serverUrl = "https://globalwarningnetworks.com/esp32.php?api=receive";
const char* deviceId = "ESP32_001"; // Change for each device
Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);
WebServer server(80);
float STA_SECONDS = 0.15;
float LTA_SECONDS = 3.0;
float TRIGGER_RATIO = 6.0;
float DEBOUNCE_SECONDS = 15;
float rmsBuffer[3200];
int bufPos = 0;
bool triggered = false;
unsigned long triggerTime = 0;
unsigned long lastUpload = 0;
void handleRoot() {
String html = R"rawliteral(
<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>RoboQuake LIVE</title>
<style>
body{font-family:Arial;margin:0;padding:20px;background:#0f172a;color:#fff}
.container{max-width:800px;margin:0 auto}
h1{text-align:center;color:#22c55e;margin-bottom:10px}
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:15px;margin:20px 0}
.stat-box{background:#1e293b;padding:15px;border-radius:8px;text-align:center;border:1px solid #334155}
.stat-value{font-size:24px;font-weight:bold;color:#22c55e}
.stat-label{font-size:12px;color:#94a3b8;margin-top:5px}
canvas{border:2px solid #22c55e;border-radius:8px;background:#000;width:100%;height:400px}
.status{text-align:center;margin:10px 0;padding:10px;background:#1e293b;border-radius:8px}
#alert{display:none;position:fixed;top:0;left:0;width:100%;padding:20px;background:#ef4444;color:#fff;font-size:28px;text-align:center;z-index:999;animation:pulse 1s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.7}}
</style>
</head><body>
<div class="container">
<h1>📡 RoboQuake LIVE DETECTION</h1>
<div id="alert">🚨 EARTHQUAKE DETECTED! <span id="mag"></span></div>
<div id="serverStatus" class="status"><span id="statusText">Checking server...</span></div>
<div class="stats">
<div class="stat-box"><div class="stat-value" id="x-value">0.000</div><div class="stat-label">X-Axis (g)</div></div>
<div class="stat-box"><div class="stat-value" id="y-value">0.000</div><div class="stat-label">Y-Axis (g)</div></div>
<div class="stat-box"><div class="stat-value" id="z-value">0.000</div><div class="stat-label">Z-Axis (g)</div></div>
<div class="stat-box"><div class="stat-value" id="rms-value">0.000</div><div class="stat-label">RMS (g)</div></div>
</div>
<canvas id="waveformCanvas"></canvas>
</div>
<script>
const canvas=document.getElementById('waveformCanvas');
const ctx=canvas.getContext('2d');
canvas.width=canvas.offsetWidth;canvas.height=400;
const dataPoints=canvas.width;
let xData=new Array(dataPoints).fill(0);
let yData=new Array(dataPoints).fill(0);
let zData=new Array(dataPoints).fill(0);
let quakeDetected=false;
function drawWaveform(){
ctx.fillStyle='#000';ctx.fillRect(0,0,canvas.width,canvas.height);
const midY=canvas.height/2,scale=50;
ctx.strokeStyle='#334155';ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(0,midY);ctx.lineTo(canvas.width,midY);ctx.stroke();
ctx.strokeStyle='#ef4444';ctx.lineWidth=2;ctx.beginPath();
for(let i=0;i<dataPoints;i++){if(i===0)ctx.moveTo(i,midY-xData[i]*scale);else ctx.lineTo(i,midY-xData[i]*scale);}ctx.stroke();
ctx.strokeStyle='#3b82f6';ctx.beginPath();
for(let i=0;i<dataPoints;i++){if(i===0)ctx.moveTo(i,midY-yData[i]*scale);else ctx.lineTo(i,midY-yData[i]*scale);}ctx.stroke();
ctx.strokeStyle='#22c55e';ctx.beginPath();
for(let i=0;i<dataPoints;i++){if(i===0)ctx.moveTo(i,midY-zData[i]*scale);else ctx.lineTo(i,midY-zData[i]*scale);}ctx.stroke();
}
async function fetchData(){
try{
const d=await fetch('/data').then(r=>r.json());
document.getElementById('x-value').textContent=d.x.toFixed(3);
document.getElementById('y-value').textContent=d.y.toFixed(3);
document.getElementById('z-value').textContent=d.z.toFixed(3);
document.getElementById('rms-value').textContent=d.rms.toFixed(3);
xData.shift();xData.push(d.x);yData.shift();yData.push(d.y);zData.shift();zData.push(d.z);
drawWaveform();
if(d.triggered==1&&!quakeDetected){
quakeDetected=true;
document.getElementById('alert').style.display='block';
document.getElementById('mag').textContent='Magnitude ~'+d.mag.toFixed(1);
document.getElementById('statusText').innerHTML='🚨 EARTHQUAKE DETECTED & REPORTED!';
setTimeout(()=>{quakeDetected=false;document.getElementById('alert').style.display='none';},10000);
}
}catch(e){console.error(e);}
}
setInterval(fetchData,50);
drawWaveform();
</script></body></html>
)rawliteral";
server.send(200, "text/html", html);
}
void handleData() {
sensors_event_t event;
accel.getEvent(&event);
float x = event.acceleration.x / 1000.0;
float y = event.acceleration.y / 1000.0;
float z = event.acceleration.z / 1000.0;
float rms = sqrt(x*x + y*y + z*z);
rmsBuffer[bufPos] = rms;
bufPos = (bufPos + 1) % 3200;
int staLen = STA_SECONDS * 3200;
int ltaLen = LTA_SECONDS * 3200;
float sta = 0, lta = 0;
for (int i = 0; i < staLen; i++) sta += rmsBuffer[(bufPos + 3200 - i) % 3200];
for (int i = 0; i < ltaLen; i++) lta += rmsBuffer[(bufPos + 3200 - i) % 3200];
sta /= staLen; lta /= ltaLen;
bool nowTriggered = (sta / lta > TRIGGER_RATIO) && (millis() - triggerTime > DEBOUNCE_SECONDS * 1000);
if (nowTriggered && !triggered) {
triggered = true;
triggerTime = millis();
float magnitude = log10(rms * 1000) + 1.5;
Serial.printf("EARTHQUAKE! RMS=%.3f → Mag %.1f\n", rms, magnitude);
// Send to server immediately
if(WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(serverUrl);
http.addHeader("Content-Type", "application/json");
String payload = "{\"x\":" + String(x,4) + ",\"y\":" + String(y,4) +
",\"z\":" + String(z,4) + ",\"rms\":" + String(rms,4) +
",\"device_id\":\"" + String(deviceId) + "\",\"triggered\":true,\"magnitude\":" + String(magnitude,2) + "}";
http.POST(payload);
http.end();
}
}
if (!nowTriggered && (millis() - triggerTime > 3000)) triggered = false;
// Regular upload every 5 seconds
if(millis() - lastUpload > 5000) {
lastUpload = millis();
if(WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(serverUrl);
http.addHeader("Content-Type", "application/json");
String payload = "{\"x\":" + String(x,4) + ",\"y\":" + String(y,4) +
",\"z\":" + String(z,4) + ",\"rms\":" + String(rms,4) +
",\"device_id\":\"" + String(deviceId) + "\"}";
http.POST(payload);
http.end();
}
}
String json = "{\"x\":" + String(x,4) + ",\"y\":" + String(y,4) + ",\"z\":" + String(z,4) +
",\"rms\":" + String(rms,4) + ",\"triggered\":" + String(triggered ? 1 : 0) +
",\"mag\":" + String(log10(rms*1000)+1.5, 2) + "}";
server.send(200, "application/json", json);
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nRoboQuake → http://" + WiFi.localIP().toString());
if (!accel.begin()) { Serial.println("No ADXL345!"); while(1); }
accel.setRange(ADXL345_RANGE_16_G);
accel.setDataRate(ADXL345_DATARATE_3200_HZ);
server.on("/", handleRoot);
server.on("/data", handleData);
server.begin();
Serial.println("EARTHQUAKE DETECTION ACTIVE");
}
void loop() {
server.handleClient();
}
📈 RMS Trend (Last Hour)
🐛 Recent Bug Fixes & Updates
✅
REALTIME Mode Added
Direct ESP32 data streaming with 100ms refresh rate. Latency reduced from 15s to ~0.3s
Nov 27, 2025
✅
Data Upload Frequency Optimized
ESP32 now sends data every 200ms (5x per second) instead of every 15 seconds
Nov 27, 2025
✅
API Proxy Endpoint
New ?api=realtime&ip=[ESP32_IP] endpoint for direct device communication
Nov 27, 2025
🔧
STA/LTA Detection Algorithm
Seismic detection using Short-Term Average (0.15s) vs Long-Term Average (3.0s) with 6.0x trigger ratio
Active
⚡
Performance Enhancement
Automatic fallback to database mode if ESP32 unreachable. Smart refresh intervals (100ms realtime / 1s database)
Active