Siddhant Kumar
Project 046 · Environment

Earthquake Vibration Sensor.

A community seismic node that recognises the first faint tremor of an earthquake and triggers a fast local shake alert — buying seconds before the strong shaking arrives.

Advanced 12–20 hours 32 min read AccelAlertsSafety
Jump to source Bill of materials
Earthquake Vibration Sensor — reference build illustration MCU VCC · GND · SIG · NC
Difficulty
Advanced
Build time
12–20 hours
Indicative cost
₹2,500 – ₹4,500
Platform
ESP32 DevKit V1 (ESP-WROOM-32)
Category
Environment
Last updated
28 July 2026
Contents — 26 sections

Project Overview

A community seismic node that recognises the first faint tremor of an earthquake and triggers a fast local shake alert — buying seconds before the strong shaking arrives.

Earthquake early warning is a race against a wave. When a fault ruptures, it sends out two kinds of seismic waves: a fast, weak P-wave that arrives first and does little damage, and a slower, violent S-wave (and surface waves) that arrive seconds to tens of seconds later and cause the destruction. If a sensor near the source detects the P-wave and immediately shouts a warning that travels at the speed of electronics — far faster than the S-wave travels through rock — places further away can get a few seconds to a minute of notice before the strong shaking hits. Those seconds are enough to stop trains, halt surgeries, open elevator doors, shut gas valves, and let people drop, cover and hold. This project builds one node of a community network that plays that game.

The heart of it is an accelerometer watching the ground constantly and an algorithm that can tell a genuine seismic P-wave from the endless background of a truck rumbling past, a door slamming, or someone bumping the bench. The classic method is STA/LTA — comparing a short-term average of the vibration energy to a long-term average — which fires when the signal suddenly jumps above its recent background, the signature of a wave arriving. On a P-wave detection the node instantly emits an alert; when many nodes are networked, agreement between several nearby nodes confirms a real earthquake (not one person's washing machine) and the network estimates where and how strong it is, issuing warnings outward ahead of the damaging waves.

A single hobby node is not a seismograph and cannot, alone, warn anyone reliably — false alarms from local noise would make it useless. Its value is entirely in the network and the honesty of the trigger: cheap MEMS accelerometers, densely deployed and cross-confirmed, can genuinely contribute to early warning, as community seismic projects have shown. So this node is designed to be a good citizen of such a network — a clean, well-characterised trigger with a sensible noise floor, accurate timing, and immediate local action (a loud shake alert) combined with networked confirmation. It is explicit that reliable warning is a system property, not a single-device one, and that it complements rather than replaces national seismic networks — but as a node you can build and run, it turns the abstract idea of earthquake early warning into something concrete on your own bench.

A city skyline at night
A dense community array of nodes cross-confirms real earthquakes and warns the wider area. Photograph sourced from Wikimedia Commons — Smart city.jpg. Reused under the licence stated on that page; please check it before republishing.

What this project does

  • Continuously monitors ground vibration with a MEMS accelerometer
  • Detects a seismic P-wave arrival with an STA/LTA trigger
  • Rejects everyday noise (traffic, footsteps, bumps) below the trigger
  • Emits an immediate local shake alert on detection
  • Contributes to networked confirmation and location by many nodes
  • Timestamps events accurately for cross-node correlation
  • Complements, does not replace, official seismic networks

Real-World Applications

SettingHow it is used
Community earthquake early warningDense citizen networks in seismic regions contributing detections that, cross-confirmed, deliver seconds of warning to a wider area.
Schools, hospitals and officesA local node that sounds a drop-cover-hold alert and can trigger automatic safety actions the moment shaking is detected.
Critical infrastructure triggersFast local shut-off signals for gas, elevators or machinery on confirmed strong shaking.
Education and researchA hands-on platform for teaching seismology, detection algorithms and the physics of earthquake early warning.

Deployment contexts where a build of this kind earns its keep.

Features & Capabilities

  • STA/LTA P-wave trigger — the classic seismic detection method
  • Noise-floor characterisation so local bumps do not false-trigger
  • Immediate local drop-cover-hold alert on detection
  • Networked cross-confirmation to reject single-node false alarms
  • Accurate timing for multi-node location and magnitude estimation
  • Honest framing: warning is a network property, not one device
  • Cheap, dense, community-deployable seismic node

Difficulty, Time & Required Skills

AttributeValue
Difficulty levelAdvanced
Estimated completion time12–20 hours
Indicative build cost₹2,500 – ₹4,500
Primary disciplineEnvironment
Reference platformESP32 DevKit V1 (ESP-WROOM-32)

Skills you should have (or will pick up)

  • Reading a MEMS accelerometer at a steady sample rate
  • Implementing the STA/LTA detection algorithm and setting its parameters
  • Characterising and rejecting environmental noise
  • Accurate timekeeping and networked event correlation
  • Designing immediate local alerts and safe automatic actions

Bill of Materials

Every part below is commonly available from Indian and international hobby-electronics suppliers. Prices are indicative 2026 retail figures in Indian rupees and will drift — treat them as a budgeting guide, not a quotation.

ComponentKey specificationQtyApprox. cost
ESP32 DevKit V1 (ESP-WROOM-32)
Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly.
Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC1₹450
MPU-6050 6-axis IMU
Gyro bias drifts with temperature — re-zero at boot while the device is still.
3-axis gyro ±250–2000 °/s, 3-axis accel ±2–16 g, 16-bit ADC, on-chip DMP1₹190
ADXL345 3-axis accelerometer
Built-in activity/free-fall interrupts let the MCU deep-sleep until something moves.
±2/4/8/16 g, 13-bit, 0.004 g/LSB, tap and free-fall interrupts, 3200 Hz1₹220
Active piezo buzzer 5 V
Active buzzers make tone on DC; passive ones need a PWM carrier.
85 dB at 10 cm, 2.3 kHz resonance, 12 mm diameter1₹25
0.96″ SSD1306 OLED display
Static images burn in — invert or scroll the screen periodically.
128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C1₹250
DS3231 precision RTC + CR2032 backup
Vastly better than DS1307; some boards trickle-charge a non-rechargeable cell — cut that resistor.
±2 ppm (±1 min/year), temperature-compensated crystal, alarms, 32 kHz out1₹180
5 V 3 A regulated SMPS adapter
Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A.
100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection1₹350
High-sensitivity accelerometer
Lower noise floor = smaller detectable quakes; upgrade for real use
MPU-6050/ADXL345 for a starter; a low-noise MEMS (e.g. ADXL355-class) for real sensitivity1₹400
Rigid mounting plate + fixings
A firm coupling to the ground is essential
Bolts the sensor solidly to a floor slab or structural wall1₹150
GPS time module (optional)
Or discipline the RTC from NTP; timing accuracy drives location
For sub-second synchronised timestamps across nodes1₹500
Loud alert + strobeAudible/visual drop-cover-hold alert for the room1₹300

Estimated total: ₹3,015, excluding tools, shipping and consumables.

Tools and consumables

  • Soldering iron (temperature controlled, 350 °C) with 0.8 mm 60/40 or lead-free solder
  • Digital multimeter — continuity, DC volts and current ranges
  • Wire strippers, flush cutters and a small set of precision screwdrivers
  • Heat-shrink tubing and a heat gun (or a lighter, carefully)
  • A laptop with a USB port and the toolchain listed above

Hardware Specifications

PartSpecificationSupplyInterfaceReference
ESP32 DevKit V1 (ESP-WROOM-32)Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC3.3 V logic / 5 V USBUART, SPI, I²C, I²S, CAN, PWMDatasheet
MPU-6050 6-axis IMU3-axis gyro ±250–2000 °/s, 3-axis accel ±2–16 g, 16-bit ADC, on-chip DMP2.375–3.46 V (module 5 V tolerant)I²C (0x68/0x69)Datasheet
ADXL345 3-axis accelerometer±2/4/8/16 g, 13-bit, 0.004 g/LSB, tap and free-fall interrupts, 3200 Hz2.0–3.6 VI²C / SPIDatasheet
Active piezo buzzer 5 V85 dB at 10 cm, 2.3 kHz resonance, 12 mm diameter3–5 VDigital / PWMDatasheet
0.96″ SSD1306 OLED display128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C3.3–5 VI²C (0x3C)Datasheet
DS3231 precision RTC + CR2032 backup±2 ppm (±1 min/year), temperature-compensated crystal, alarms, 32 kHz out2.3–5.5 VI²C (0x68)Datasheet
5 V 3 A regulated SMPS adapter100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection5 VDC barrel / USBDatasheet

Consolidated electrical and interface specifications for every active part in the build.

Power Budget & Supply Sizing

Add up the typical active current of every part, then size the supply with at least 50 % headroom so transmit bursts and motor inrush never brown out the controller.

LoadSupply railTypical current (mA)Notes
ESP32 DevKit V1 (ESP-WROOM-32)3.3 V logic / 5 V USB160Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly.
MPU-6050 6-axis IMU2.375–3.46 V (module 5 V tolerant)3.9Gyro bias drifts with temperature — re-zero at boot while the device is still.
ADXL345 3-axis accelerometer2.0–3.6 V0.14Built-in activity/free-fall interrupts let the MCU deep-sleep until something moves.
Active piezo buzzer 5 V3–5 V30Active buzzers make tone on DC; passive ones need a PWM carrier.
0.96″ SSD1306 OLED display3.3–5 V20Static images burn in — invert or scroll the screen periodically.
DS3231 precision RTC + CR2032 backup2.3–5.5 V0.2Vastly better than DS1307; some boards trickle-charge a non-rechargeable cell — cut that resistor.
5 V 3 A regulated SMPS adapter5 V3000Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A.

Summed typical draw is 3214.24 mA. With a 1.5× design margin the supply should deliver at least 4900 mA continuously at the stated rail voltage.

Software Requirements & Development Environment

Reference toolchain: Arduino IDE 2.3.x with the ESP32 board package 3.x (or PlatformIO on VS Code). Anything newer normally works; anything older may lack the board definitions used here.

  • Install the Arduino IDE 2.3.x (or PlatformIO if you prefer a real editor and dependency locking).
  • Add https://espressif.github.io/arduino-esp32/package_esp32_index.json under File → Preferences → Additional Board Manager URLs, then install esp32 from the Boards Manager.
  • Set the correct port under Tools → Port. On Linux add yourself to the dialout group: sudo usermod -aG dialout $USER and log out and back in.
  • Open the Serial Monitor at 115200 baud — every sketch here logs its state there.
  • Keep File → Preferences → Show verbose output during: compilation switched on while you are debugging build errors.

Required libraries

LibraryWhy it is neededInstall
WiFi (ESP32 core) bundledStation/AP connection management for the ESP32.Bundled with the ESP32 Arduino core
PubSubClient 2.8Lightweight MQTT 3.1.1 client for constrained devices.Library Manager → "PubSubClient" by Nick O'Leary
MPU6050_light / Adafruit MPU6050 1.3.xIMU register access, calibration and complementary-filter angles.Library Manager → "MPU6050_light" by rfetick
Adafruit SSD1306 + GFX 2.5.xFramebuffer and text/graphics primitives for the OLED.Library Manager → "Adafruit SSD1306"
NTPClient / configTime bundledWall-clock time from an NTP server for timestamping.Bundled (`configTime()` on ESP32)
ArduinoJson 7.xZero-allocation JSON serialisation and parsing.Library Manager → "ArduinoJson" by Benoit Blanchon
Preferences (NVS) bundledWear-levelled key/value storage in ESP32 flash for settings.Bundled with the ESP32 core

Block Diagram

The block diagram shows the functional decomposition of the system — what senses, what decides, what acts, and where the data ends up.

Earthquake Vibration Sensor — system block diagramFunctional block diagram of the Earthquake Vibration Sensor system. Sense motionAccelerometertriaxial, 100 HzTimeGPS/NTP RTCDetectESP32STA/LTA triggerNoise rejectbackground floorAct + reportLocal alertdrop-cover-holdNetworkdetection reportConfirmServermulti-node quakeWarningto wider arearightrightnone
Earthquake Vibration Sensor — system block diagram

Circuit Diagram & Wiring

Every signal line in the build is shown below, followed by a pin-by-pin connection table you can work through with a multimeter in hand.

Earthquake Vibration Sensor — wiring schematicConnection schematic showing which controller pin drives each peripheral. Sensors / InputsControllerActuators / OutputsESP32 DevKit V1(ESP-WROOM-32)3.3 V logic / 5 V USBAccelerometerGPIO 21/22Triaxial groundmotion (I²C)AccelerometerGPIO 34Data-ready interruptDS3231 RTC / GPSGPIO 21-22 / 16-17Accurate timestampsBuzzer + strobeGPIO 13Local shake alertOLEDGPIO 21/22Status/liveseismogramWi-FiNetworked detectionreporting5V supply3V3 regMains-powered (fixedinstall)
Earthquake Vibration Sensor — wiring schematic
PeripheralPeripheral pinController pinSignal
AccelerometerSDA/SCLGPIO 21/22Triaxial ground motion (I²C)
AccelerometerINTGPIO 34Data-ready interrupt
DS3231 RTC / GPSSDA/SCL / UARTGPIO 21-22 / 16-17Accurate timestamps
Buzzer + strobeINGPIO 13Local shake alert
OLEDSDA/SCLGPIO 21/22Status/live seismogram
Wi-Fion-chipNetworked detection reporting
5V supply+/–3V3 regMains-powered (fixed install)

Wire one row at a time and tick it off — most "it does not work" reports trace back to a single swapped pair.

Wiring explanation

  • Bolt the accelerometer rigidly to a structural floor or wall so it moves with the building; a sensor on a wobbly bench measures the bench, not the earthquake.
  • Sample the accelerometer at a steady, known rate (e.g. 100 Hz) using its data-ready interrupt so the STA/LTA windows are correctly timed.
  • Give the node accurate time — GPS-disciplined or NTP-disciplined RTC — because multi-node location depends on precise arrival timestamps.
  • Keep the sensor away from local vibration sources (HVAC, machinery, foot traffic) that would raise its noise floor and cause false triggers.
  • Wire the alert loud and unmissable; on a confirmed strong event it must reliably prompt drop-cover-hold.
An ESP32 development board with the ESP-WROOM-32 module and USB connector
ESP32 module running the STA/LTA detector on continuous accelerometer data. Photograph sourced from Wikimedia Commons — ESP32 Espressif ESP-WROOM-32 Dev Board.jpg. Reused under the licence stated on that page; please check it before republishing.

System Architecture

Read the stack from the bottom up: physical hardware, the firmware that drives it, the transport that moves data off the device, and the software a human actually looks at.

Earthquake Vibration Sensor — architecture stackLayered architecture from hardware to user interface. Hardware layerESP32 DevKit V1 (ESP-WROOM-32) · MPU-6050 6-axis IMUDriver layerwifi · pubsub · mpu · ssd1306Application logicsampling loop · filtering · thresholds · state machineTransport layerWi-Fi + MQTT → confirmation server → area warning · TLS · retry andbackoffPresentation layerdashboard · mobile notifications · historical charts
Earthquake Vibration Sensor — architecture stack

Working Principle

Earthquake early warning exploits the gap between two waves and the gap between rock and radio. A rupture emits a fast, low-amplitude P-wave (compressional, ~6–8 km/s) ahead of the slower, destructive S-wave and surface waves (~3–4 km/s). A sensor close to the epicentre feels the P-wave first; if it instantly sends an alert electronically, that alert outruns the still-travelling S-wave to more distant places. The warning time is essentially the difference in travel times — small near the epicentre, larger far from it — which is why dense networks and fast triggers matter: every fraction of a second shaved off detection is added to someone's warning.

The detection algorithm at the core is STA/LTA, the workhorse of seismology. It maintains a Short-Term Average of the signal's energy (over, say, the last second) and a Long-Term Average (over the last tens of seconds), and computes their ratio. In quiet times the two are similar and the ratio hovers near one; when a wave arrives, the short-term energy jumps while the long-term average still reflects the quiet background, so the ratio spikes. A trigger fires when the ratio crosses a threshold, and de-triggers when it falls back. The beauty of the method is that it is self-scaling: it responds to a sudden change relative to recent background, so it works whether the site is inherently quiet or a bit noisy, and it adapts as conditions drift.

The hard part on a cheap node is rejecting the non-earthquake world. A passing truck, a slammed door, footsteps, or someone knocking the desk all produce transients that can spike STA/LTA just like a P-wave. Several things help: characterising the site's noise floor and setting the threshold above it; requiring the trigger to persist and to show up across all three axes in a way consistent with ground motion rather than a single-axis tap; and, decisively, networked cross-confirmation. A real earthquake shakes many nearby nodes within a physically-consistent time pattern; one person's washing machine shakes exactly one node. So the network treats a lone detection as suspect and a coincident cluster of detections, arriving in a pattern consistent with a wave sweeping across the array, as a confirmed event — which also lets it estimate the epicentre (from the relative arrival times) and a rough magnitude (from the amplitudes).

This is why the design insists that reliable warning is a property of the network, not the node. A single low-cost accelerometer, however cleverly triggered, will occasionally false-alarm on local noise, and cannot by itself distinguish a nearby small quake from a distant large one. But cheap MEMS sensors, deployed densely and cross-confirmed with accurate timestamps, genuinely contribute — community seismic networks have demonstrated that a crowd of humble sensors can detect and locate earthquakes and shave seconds off warnings for everyone. So the node does two honest things well: it acts immediately and locally (a loud drop-cover-hold alert the instant it triggers, because your own trigger on a real quake is real ground motion under you), and it reports a clean, well-timed detection into a network that does the confirmation and warning. It complements official seismic networks rather than replacing them, and it never pretends a single bench-top box is an authoritative earthquake alarm.

The maths behind it

STA/LTA trigger

plainSTA/LTA trigger
On the vibration signal x[n] (e.g. |acceleration| or an axis):

  STA = mean of x^2 over a SHORT window (e.g. 1 s)
  LTA = mean of x^2 over a LONG window (e.g. 30 s)
  ratio = STA / LTA

  trigger  when ratio > R_on  (e.g. 4–8)
  de-trigger when ratio < R_off (e.g. 2)

The LTA tracks background; a sudden arrival makes STA jump
while LTA lags → the ratio spikes.

Warning time from wave speeds

plainWarning time from wave speeds
For a site at distance D from the epicentre:

  t_P = D / v_P,   t_S = D / v_S   (v_P ~ 6–8, v_S ~ 3–4 km/s)

  warning ≈ t_S − t_P − t_detect − t_comms

Detect on the P-wave, alert electronically; the S-wave still
has to travel. Warning grows with D but is zero in the
"blind zone" very near the epicentre.

Networked confirmation and location

plainNetworked confirmation and location
A real quake triggers many nodes with consistent timing.

  confirmed if ≥ K nodes trigger within a plausible window
  epicentre from relative arrival times (t_i) across nodes
  (grid-search / triangulation on the array geometry)
  magnitude proxy from peak amplitudes vs distance.

One node triggering alone → treated as local noise, not a quake.

Program Flowchart

The firmware is a single cooperative loop. Nothing blocks for long, so networking, sensing and the user interface all stay responsive.

Earthquake Vibration Sensor — firmware flowchartControl flow through the main program loop. Sample acceleration (100 Hz)Update STA and LTA energySTA/LTA ratio overtrigger?P-wave detected: alert + reportKeep monitoringKeep monitoringP-wave detected: alert +reportLocal shake alert(drop-cover-hold)Send timestamped detection tonetworkDe-trigger when ratio falls
Earthquake Vibration Sensor — firmware flowchart

Assembly Instructions

Build on a breadboard first and only commit to solder once the whole system has run for an hour without a fault.

  1. Couple the sensor to the structure

    Bolt the accelerometer rigidly to a structural floor slab or wall via a mounting plate, low in the building, so it faithfully moves with the ground.

    Keep it away from local vibration sources (HVAC, lifts, foot traffic) that raise the noise floor.

  2. Set up steady sampling and time

    Sample the accelerometer at a fixed rate (e.g. 100 Hz) using its data-ready interrupt, and discipline the clock from GPS or NTP so timestamps are accurate to well under a second.

  3. Wire alert, display and network

    Connect a loud buzzer/strobe for the local drop-cover-hold alert, an OLED for status/live seismogram, and Wi-Fi for reporting detections to the confirmation server.

Step-by-Step Implementation Guide

Work through these in order. Each step ends in something you can observe, so a failure is always localised to the step you just finished.

  1. Implement the STA/LTA detector

    Maintain short- and long-term energy averages of the vibration signal, compute their ratio each sample, and trigger when it crosses R_on, de-triggering below R_off.

    cppstalta.ino
    // Running STA/LTA on the acceleration magnitude (100 Hz).
    float sta = 0, lta = 0;
    const float A_STA = 1.0f/100.0f;    // ~1 s short window (as an EMA)
    const float A_LTA = 1.0f/3000.0f;   // ~30 s long window
    const float R_ON = 6.0f, R_OFF = 2.0f;
    bool triggered = false;
    
    // Call once per sample with the (gravity-removed) accel magnitude.
    bool detect(float accMag) {
      float e = accMag * accMag;                 // signal energy
      sta += A_STA * (e - sta);                  // fast average
      // Freeze LTA while triggered so the event doesn't inflate the background.
      if (!triggered) lta += A_LTA * (e - lta);
      float ratio = (lta > 1e-9f) ? sta / lta : 0;
    
      if (!triggered && ratio > R_ON)  { triggered = true;  return true; }  // onset
      if ( triggered && ratio < R_OFF) { triggered = false; }                // end
      return false;
    }
    sta += A_STA * (e - sta)Implements the short-term average as an exponential moving average of the signal energy, cheap to run every sample and responsive to a sudden arrival.
    if (!triggered) lta += A_LTAThe long-term background average is frozen while an event is in progress, so the earthquake's own energy does not inflate the baseline and suppress the trigger.
    if (!triggered && ratio > R_ON)A detection fires when the short-term energy jumps well above the recent background — the STA/LTA signature of a wave arriving.
    if ( triggered && ratio < R_OFF)Separate on and off thresholds give hysteresis, so the trigger latches through the event and releases cleanly when the shaking subsides.
  2. Act locally and report to the network

    On a trigger, immediately sound the local alert and send a timestamped detection (with peak amplitude and location) to the confirmation server, which decides if a cluster constitutes a real quake.

Complete Source Code

The listing below is complete and compiles as written — there are no elided sections. Read the annotations under each block before you upload it.

cppearthquake-node.ino
/* ═══════════════════════════════════════════════════════════════
   Earthquake Vibration Sensor — ESP32 + accelerometer, STA/LTA

   Continuously samples ground motion, detects a P-wave with STA/LTA,
   sounds an immediate local drop-cover-hold alert, and reports a
   timestamped detection to a network that cross-confirms real quakes.
   ══════════════════════════════════════════════════════════════════ */

#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <MPU6050.h>
#include <time.h>
#include <math.h>

#define PIN_ALERT 13
#define FS        100        // 100 Hz sampling

MPU6050 accel;
WiFiClient net; PubSubClient mqtt(net);

float sta=0, lta=0, gravity=9.81f;
const float A_STA=1.0f/FS, A_LTA=1.0f/(30*FS);
const float R_ON=6.0f, R_OFF=2.0f;
bool triggered=false;
float peakDuringEvent=0;
uint32_t nextSampleUs=0;

double nowEpochMs() {
  struct timeval tv; gettimeofday(&tv,NULL);
  return tv.tv_sec*1000.0 + tv.tv_usec/1000.0;
}

void reportDetection(float peak) {
  char b[200];
  snprintf(b,sizeof b,
    "{\"node\":1,\"t_ms\":%.0f,\"peak_g\":%.4f,\"lat\":%.5f,"
    "\"lon\":%.5f}", nowEpochMs(), peak/9.81f, NODE_LAT, NODE_LON);
  mqtt.publish("quake/detect", b);           // network confirms clusters
}

void setup() {
  Serial.begin(115200);
  pinMode(PIN_ALERT, OUTPUT);
  Wire.begin(21,22); Wire.setClock(400000);
  accel.initialize();
  accel.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);   // ±2g, fine resolution
  WiFi.begin(WIFI_SSID,WIFI_PASS);
  mqtt.setServer(MQTT_HOST,1883);
  configTime(0,0,"pool.ntp.org");            // discipline the clock
  nextSampleUs = micros();
}

void loop() {
  if(!mqtt.connected()&&WiFi.status()==WL_CONNECTED) mqtt.connect("quake-1");
  mqtt.loop();

  // steady-rate sampling
  if ((int32_t)(micros() - nextSampleUs) < 0) return;
  nextSampleUs += 1000000UL / FS;

  int16_t ax,ay,az;
  accel.getAcceleration(&ax,&ay,&az);
  float g = 9.81f/16384.0f;                  // ±2g scale → m/s^2 per LSB
  float x=ax*g, y=ay*g, z=az*g;
  float mag = sqrtf(x*x+y*y+z*z);
  gravity += 0.001f*(mag-gravity);           // slow-track gravity
  float motion = fabsf(mag - gravity);       // ground motion, gravity removed

  float e = motion*motion;
  sta += A_STA*(e-sta);
  if(!triggered) lta += A_LTA*(e-lta);
  float ratio = (lta>1e-9f)? sta/lta : 0;

  if (triggered && motion > peakDuringEvent) peakDuringEvent = motion;

  if (!triggered && ratio > R_ON) {
    triggered = true; peakDuringEvent = motion;
    digitalWrite(PIN_ALERT, HIGH);           // IMMEDIATE local alert
    reportDetection(peakDuringEvent);        // report onset to network
  } else if (triggered && ratio < R_OFF) {
    triggered = false;
    digitalWrite(PIN_ALERT, LOW);
  }
}
if ((int32_t)(micros() - nextSampleUs) < 0) returnEnforces a steady 100 Hz sample rate, which the STA/LTA window lengths assume — jittery sampling would distort the ratio and the timing.
float motion = fabsf(mag - gravity)Removes the constant 1g of gravity by slow-tracking it, leaving the actual ground motion the detector should act on.
if(!triggered) lta += A_LTA*(e-lta)Freezes the long-term background while triggered so the quake's energy does not raise the baseline and prematurely end the detection.
digitalWrite(PIN_ALERT, HIGH); // IMMEDIATE local alertA local trigger means real motion under this node, so the drop-cover-hold alert fires instantly rather than waiting for network confirmation.
reportDetection(peakDuringEvent)Sends a timestamped, located detection to the network, which cross-confirms clusters into real earthquakes and warns the wider area — the part a single node cannot do.

Configuration & Calibration

Configuration steps

  • Set the sample rate and the STA/LTA window lengths and R_on/R_off thresholds to your accelerometer and site noise.
  • Set the node's location for network location/magnitude estimation, and discipline the clock (GPS/NTP).
  • Characterise the site noise floor and set the trigger above it.
  • Configure the network reporting (MQTT topic/server) and the local alert behaviour.

Calibration procedure

An uncalibrated sensor produces confident, precise, wrong numbers. Do this once per physical unit and record the constants.

  1. Noise floor

    Record the STA/LTA ratio over quiet and busy periods; set R_on comfortably above the busiest normal ratio so routine activity does not trigger.

  2. Timing

    Verify the clock is disciplined and timestamps are accurate to well under a second by comparing against a reference; multi-node location depends on it.

  3. Response check

    Induce a controlled tap/shake and confirm the trigger fires and de-triggers cleanly, and that the local alert activates immediately.

Network Architecture & Connectivity

Earthquake Vibration Sensor — network topologyPath taken by telemetry from field node to end user. Edge nodesGatewayCloudClientsSeismic nodeESP32 + accelOther nodesdense arrayWi-Fi 2.4 GHzRouterlow-latencyMQTT 1883Confirmation servercluster + locateWarning systemarea alertsLocal alertsdrop-cover-hold
Earthquake Vibration Sensor — network topology

Communication protocol

Each node reports a timestamped, located detection the instant it triggers — latency is everything in early warning. The server correlates detections into confirmed quakes and issues warnings outward faster than the S-wave travels.

Topic / endpointDirectionPayload
quake/detectnode → servertimestamp, peak amplitude, node location
quake/confirmedserver → clientsepicentre, magnitude proxy, ETA of shaking
quake/node/healthnode → servernoise floor, clock status, uptime

Message contract between the device and the broker.

Cloud platform configuration

A confirmation server clusters coincident detections, rejects lone (noise) triggers, estimates epicentre and magnitude from arrival times and amplitudes, and pushes warnings with a shaking-ETA countdown to areas the destructive waves have not yet reached.

Dashboard setup

A live map of node detections and confirmed events, showing the estimated epicentre, the expanding S-wave front, and per-area warning countdowns.

Mobile app integration

On a confirmed event, an immediate warning with the seconds-until-shaking countdown, and triggers for automatic safety actions.

Security considerations

  • Authenticate node detections so false quakes cannot be injected to cause panic.
  • Prioritise latency and integrity end-to-end — a warning is only useful if it arrives before the shaking.
  • Weight nodes by reliability so noisy or spoofed nodes cannot dominate the confirmation.

Testing Procedure & Expected Output

Test from the bottom up. Confirm power, then each sensor in isolation, then the integrated loop — the first failing step tells you exactly where to look.

TestWhat you should see
Tap the mounting near the sensorSTA/LTA spikes and triggers; de-triggers as it settles
Run a nearby noise source (fan, footsteps)Ratio stays below R_on if the floor is set correctly
Simulate a P-wave-like transientImmediate local alert; timestamped detection reported
Trigger one node onlyNetwork treats it as noise (no cluster) — no wider warning
Trigger several nodes coincidently (test harness)Network confirms a quake and estimates location
Check clock disciplineTimestamps accurate enough for cross-node correlation

Bench-test checklist. If a row fails, stop and fix it before moving on.

Expected output

The node shows a live seismogram and status; the network dashboard shows detections, and on a confirmed cluster, an estimated epicentre, magnitude proxy, and the outgoing warning with countdown to shaking for surrounding areas.

jsonquake-detect.json
{
  "node": 1,
  "t_ms": 1785312045678,
  "peak_g": 0.031,
  "lat": 28.61390,
  "lon": 77.20900
}

A single detection like this is only a candidate; when several nodes report coincident, physically-consistent detections, the server confirms an earthquake, locates it from the relative arrival times, and warns areas the S-wave has not yet reached.

A Grafana time-series dashboard
A dashboard clusters coincident detections into a located event and a shaking-ETA warning. Photograph sourced from Wikimedia Commons — Grafana dashboard.png. Reused under the licence stated on that page; please check it before republishing.

Troubleshooting: Common Errors & Fixes

Frequent false triggers

Likely cause. Noise floor too close to R_on, or loose mount

Fix. Mount rigidly away from vibration sources; raise R_on above the busy-period ratio; require multi-axis consistency

Misses small events

Likely cause. Noisy site or insensitive accelerometer

Fix. Use a lower-noise MEMS sensor; quieter mounting location; rely on the network's many nodes

Network never confirms real events

Likely cause. Poor time sync or too few nodes

Fix. Discipline clocks (GPS/NTP); increase node density; check the confirmation window

Trigger latches on and never releases

Likely cause. LTA inflated during the event

Fix. Freeze LTA while triggered (as implemented); ensure R_off is set sensibly

Locations are wrong

Likely cause. Inaccurate node positions or timestamps

Fix. Set precise node lat/lon; verify timing accuracy; more nodes improve the solution

The sketch will not upload — "Failed to connect" or "avrdude: stk500_recv()"

Likely cause. The bootloader is not being reached: wrong port, wrong board, a serial monitor holding the port open, or a USB cable that only carries power.

Fix. Close every serial monitor, confirm Tools → Board and Port, and swap to a known data-capable USB cable. On an ESP32 hold BOOT while the IDE prints "Connecting…", then release. If a peripheral is wired to the UART pins (GPIO 1/3 on ESP32, D0/D1 on Uno) unplug it — it fights the programmer.

The board resets in a loop, or the serial monitor prints "Brownout detector was triggered"

Likely cause. The supply cannot deliver peak current. Wi-Fi transmit bursts, relay coils and servos all pull far more than their average draw.

Fix. Power peripherals from a separate regulated supply with a common ground rather than from the board 5 V pin. Add a 470–1000 µF electrolytic capacitor across the supply near the load, and use a real power adapter rather than a laptop USB port.

Serial monitor shows garbage characters

Likely cause. Baud rate mismatch between Serial.begin() and the monitor, or a floating/shared UART line.

Fix. Set the monitor to 115200 to match the sketch. If it still garbles, the crystal or the USB bridge is being confused by noise — shorten the cable and keep motor wiring away from the USB lead.

An I²C device is not detected

Likely cause. Wrong address, missing pull-ups, swapped SDA/SCL, or a bus too long for the pull-up value.

Fix. Run an I²C scanner sketch first — it should print the device address. Most breakout boards include 4.7 kΩ pull-ups, but if you have chained four of them the parallel resistance is too low; remove the pull-ups from all but one board. Keep the bus under 30 cm at 100 kHz.

Wi-Fi connects but MQTT never does (state -2)

Likely cause. Wrong broker address or port, a firewall in the way, or the broker requiring credentials the sketch is not sending.

Fix. Test from a laptop on the same network first: mosquitto_sub -h <broker> -t "#" -v. If that works, the problem is on the device — check the IP literal, port 1883 (or 8883 for TLS), and that client.setServer() runs before connect(). PubSubClient state codes are documented in its header.

Readings arrive for a while and then stop

Likely cause. The Wi-Fi or MQTT session dropped and the sketch never reconnects, or the broker dropped the client on keep-alive timeout.

Fix. Never assume the link stays up. Check WiFi.status() and client.connected() at the top of every loop and reconnect with exponential backoff. Add a watchdog so a wedged network stack reboots the device instead of going silent.

Performance Optimisation

  • Sample at a steady rate and keep the STA/LTA update to a few operations per sample so 100 Hz is comfortable.
  • Minimise end-to-end latency: detect, alert and report with as little delay as possible — seconds decide the warning's value.
  • Discipline the clock continuously; timing accuracy is as important as detection accuracy for the network.
  • Freeze the LTA during events and use hysteresis so the detector behaves cleanly without extra computation.
  • Replace every delay() with a millis() comparison — blocking delays are the single most common cause of dropped readings.
  • Sample sensors on a fixed cadence and publish on a slower one; you almost never need to transmit at the sampling rate.
  • Move networking into its own FreeRTOS task so a slow DNS lookup cannot stall the control loop.
  • Use uint8_t / uint16_t where the range allows; on an 8-bit AVR a 32-bit add costs four times as much.
  • Batch several samples into one MQTT publish. Radio time, not CPU time, dominates the energy budget.
  • Set the MQTT keep-alive to a value that matches your reporting interval so the broker does not churn reconnections.
  • For battery builds use deep sleep between samples: an ESP32 drops from ~160 mA awake to about 10 µA asleep, which is the difference between days and months of runtime.

Safety Precautions

  • Warning is a network property — never present a single node as an authoritative earthquake alarm.
  • This complements, and does not replace, official seismic networks and public warning systems.
  • Ensure any automatic safety actions (gas shut-off, lift control) triggered on confirmation are fail-safe and reviewed by qualified engineers.
  • Make the local drop-cover-hold alert unmistakable and test it regularly.
  • Wear eye protection when soldering or cutting, and solder in a ventilated space — rosin flux fumes are a respiratory irritant.
  • Power the circuit through a bench supply with a current limit while you are testing. A 300 mA limit turns a wiring mistake into a beep instead of a dead board.
  • Disconnect power before changing any wiring. Hot-plugging a sensor onto a live bus is the fastest way to lose a controller.

Maintenance

  • Periodically re-characterise the noise floor as the building's use changes.
  • Verify clock discipline and node position accuracy.
  • Check the mounting remains rigid and the sensor free of new local vibration sources.
  • Test the local alert and the network reporting path regularly.
  • Re-check every screw terminal and header after the first week — thermal cycling loosens connections that felt tight on day one.
  • Keep the broker and dashboard containers patched, and rotate device credentials at least once a year.
  • Recalibrate at the interval given in the calibration section, and keep the constants in a text file next to the firmware — not only in flash.
  • Keep a short logbook of firmware versions and what changed. Six months later you will not remember why that constant is 1.083.

Future Improvements & Upgrades

A working v1 is a platform, not a finish line. These are the upgrades that add the most capability for the least rework.

  • Upgrade to a low-noise MEMS (ADXL355-class) accelerometer for sensitivity closer to research nodes.
  • Add on-device magnitude estimation from P-wave characteristics for faster warnings.
  • Contribute to an existing community seismic network protocol for real cross-confirmation.
  • Add battery backup so detection survives the power loss an earthquake can cause.
  • Design a proper PCB. Once the breadboard version has run for a month, moving to a two-layer board removes the intermittent-contact failures that dominate prototype faults.
  • Add over-the-air firmware updates so you never have to physically reach a deployed node again.
  • Add persistent local storage (microSD or the on-chip flash) so a network outage does not create a hole in your data.
  • Move configuration out of the source: a captive-portal setup page or a JSON config file makes the build reusable without a recompile.
  • Add a battery and solar option so the unit survives a power cut and can be sited away from a socket.
  • Write a small test harness that feeds synthetic sensor values through the decision logic, so you can validate thresholds without physically triggering the event.

Frequently Asked Questions

How can a sensor warn before the earthquake?

It detects the fast, weak P-wave that arrives first and sends an electronic alert that outruns the slower, destructive S-wave to more distant places — giving them seconds of warning before the strong shaking.

Won't a truck or a slammed door set it off?

A single node sometimes will — which is exactly why warning depends on the network. A real quake shakes many nodes in a consistent pattern; local noise shakes one. The server confirms clusters and ignores lone triggers.

What is STA/LTA?

A short-term average of vibration energy divided by a long-term average. When a wave arrives, the short-term energy jumps above the recent background and the ratio spikes, triggering detection. It is the classic seismic method.

Is one node useful on its own?

It gives you an immediate local shake alert (your own trigger is real motion under you) and can drive local safety actions, but reliable early warning for an area is a network property, not a single-device one.

Does this replace the official earthquake warning?

No — it complements national seismic networks. Community nodes add density and can genuinely contribute, but they are not a substitute for authoritative systems.

References & Learning Resources

These are the primary sources worth reading in full. Manufacturer datasheets always outrank forum posts when the two disagree.

  1. Earthquake early warning — how it worksReference
  2. STA/LTA detection algorithm — seismologyReference
  3. P-waves and S-wavesReference
  4. Community seismic networks (e.g. MyShake / QCN)Reference
  5. MEMS accelerometers for seismologyReference