Home / Projects / ESP32 Projects / ESP32 Earthquake Monitor with USGS API, GPS, LCD, and Web Dashboard
pcbway
ESP32 Earthquake Monitor

ESP32 Earthquake Monitor with USGS API, GPS, LCD, and Web Dashboard

Was that an earthquake, or did I just stand up too fast? If you’ve ever asked that question — then this project’s for you.

We’re building an ESP32 Earthquake Monitor that fetches live data from the USGS Earthquake API, locates your position via NEO-6M GPS, and alerts you through an LCD, buzzer, and RGB LED. It even logs quake data to an SD card and hosts a mini web dashboard for quake history — because if you’re going to feel the earth move, you might as well have the data to prove it.


Project Overview

This project combines IoT, geolocation, and real-time data processing in one neat ESP32 package.

Here’s what happens behind the scenes:

  1. The ESP32 connects to Wi-Fi and syncs its clock with an NTP (Network Time Protocol) server.
  2. Using the current date, it requests the day’s earthquakes in a given location via the USGS Earthquake API.
  3. The NEO-6M GPS module provides your current coordinates.
  4. The ESP32 computes which earthquakes are closest to you.
  5. If a quake is detected within ~200 km:
    • The LCD shows the event.
    • The buzzer sounds an alarm.
    • The RGB LED turns red (otherwise it stays green).
  6. All quake data is logged to the SD card, and you can view it later through the ESP32’s built-in web page.

Components Needed

Component Description
ESP32 Dev Board Main microcontroller with Wi-Fi
NEO-6M GPS Module Provides latitude & longitude
16x2 I²C LCD Displays quake status
Active Buzzer Alarm sound for nearby quakes
RGB LED Visual indicator (green = calm, red = alert)
MicroSD Module Stores quake history
Breadboard + wires For connections

Fetching Data from the USGS Earthquake API

We’ll use this endpoint to get the latest quakes in the Philippines (my country):

https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson
&starttime=2025-10-17
&endtime=2025-10-18
&minmagnitude=4.5
&minlatitude=5.0
&maxlatitude=20.0
&minlongitude=115.0
&maxlongitude=130.0
&orderby=time

But instead of fixed dates, we’ll dynamically replace starttime and endtime each day using the ESP32’s NTP-synced clock.

That means the device automatically fetches today’s earthquakes every 24 hours — no manual editing required.


GPS and Connections

Module ESP32 Pin Notes
NEO-6M TX GPIO16 (RX2) GPS data to ESP32
NEO-6M RX GPIO17 (TX2) Optional
LCD SDA GPIO21 I²C
LCD SCL GPIO22 I²C
Buzzer + GPIO25 Output
RGB LED R GPIO26 Red pin
RGB LED G GPIO27 Green pin
SD CS GPIO5 SD card chip select
SD MOSI GPIO23 SPI data (ESP32 → SD)
SD MISO GPIO19 SPI data (SD → ESP32)
SD SCK GPIO18 SPI clock

Code Overview

Here’s the project flow summarized:

  1. Connect to Wi-Fi and get time from NTP.
  2. Format today’s date into YYYY-MM-DD.
  3. Construct the API URL dynamically.
  4. Fetch and parse the GeoJSON data.
  5. Get your GPS location (latitude & longitude).
  6. Compute the distance between your location and each quake’s epicenter using the Haversine formula.
  7. Update the LCD, RGB LED, and buzzer accordingly.
  8. Log quake data to the SD card.
  9. Host a simple web page displaying recent logs.

Example Code Snippet (Simplified)

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TinyGPSPlus.h>
#include <HardwareSerial.h>
#include <SD.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

#define BUZZER_PIN 25
#define LED_R 26
#define LED_G 27
#define SD_CS 5

LiquidCrystal_I2C lcd(0x27, 16, 2);
HardwareSerial gpsSerial(2);
TinyGPSPlus gps;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 28800); // +8 GMT (Philippines)

const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

void setup() {
  Serial.begin(115200);
  lcd.init(); lcd.backlight();
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(LED_R, OUTPUT);
  pinMode(LED_G, OUTPUT);

  gpsSerial.begin(9600, SERIAL_8N1, 16, 17);

  WiFi.begin(ssid, password);
  lcd.print("Connecting WiFi...");
  while (WiFi.status() != WL_CONNECTED) delay(500);

  timeClient.begin();
  while(!timeClient.update()) timeClient.forceUpdate();

  if(!SD.begin(SD_CS)) lcd.print("SD Fail!"); else lcd.print("SD Ready");
  delay(2000);
  lcd.clear();

  fetchEarthquakes();
}

void fetchEarthquakes() {
  // Get today's date
  time_t epoch = timeClient.getEpochTime();
  struct tm *tm_info = localtime(&epoch);
  char date_str[11];
  strftime(date_str, 11, "%Y-%m-%d", tm_info);

  String url = "https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson";
  url += "&starttime=" + String(date_str);
  url += "&endtime=" + String(date_str);
  url += "&minmagnitude=4.5&minlatitude=5.0&maxlatitude=20.0&minlongitude=115.0&maxlongitude=130.0&orderby=time";

  HTTPClient http;
  http.begin(url);
  int code = http.GET();
  if(code == 200) {
    DynamicJsonDocument doc(16384);
    deserializeJson(doc, http.getString());

    for(JsonObject f : doc["features"].as<JsonArray>()) {
      double lon = f["geometry"]["coordinates"][0];
      double lat = f["geometry"]["coordinates"][1];
      double mag = f["properties"]["mag"];
      const char* place = f["properties"]["place"];

      double myLat = gps.location.lat();
      double myLon = gps.location.lng();

      double dist = TinyGPSPlus::distanceBetween(myLat, myLon, lat, lon) / 1000.0;
      logToSD(place, mag, dist);

      if(dist < 200) alertUser(place, mag);
    }
  }
  http.end();
}

void alertUser(const char* place, double mag) {
  lcd.clear();
  lcd.print("ALERT!");
  lcd.setCursor(0,1);
  lcd.print(place);
  digitalWrite(LED_R, HIGH);
  digitalWrite(LED_G, LOW);
  tone(BUZZER_PIN, 1000, 2000);
  delay(5000);
  noTone(BUZZER_PIN);
  digitalWrite(LED_R, LOW);
  digitalWrite(LED_G, HIGH);
}

void logToSD(const char* place, double mag, double dist) {
  File f = SD.open("/quakes.csv", FILE_APPEND);
  if(f) {
    f.printf("%s,%.1f,%.1f km\n", place, mag, dist);
    f.close();
  }
}

Adding a Web Dashboard

With the ESP32’s Wi-Fi capability, it’s easy to serve quake logs over a local webpage.

The idea:

  • The ESP32 starts a web server.
  • When a user visits the ESP32’s IP address (e.g., http://192.168.1.25), the page displays the contents of quakes.csv from the SD card.
  • The page auto-refreshes every 60 seconds, so you always see the latest events.
#include <WebServer.h>

WebServer server(80);

void handleRoot() {
  if (!SD.exists("/quakes.csv")) {
    server.send(200, "text/html", "<h3>No quake data logged yet.</h3>");
    return;
  }

  File file = SD.open("/quakes.csv");
  if (!file) {
    server.send(500, "text/html", "Error opening quake log.");
    return;
  }

  String html = "<!DOCTYPE html><html><head><meta charset='UTF-8'>";
	html += "<meta http-equiv='refresh' content='60'>";
	html += "<title>ESP32 Earthquake Monitor</title>";
	html += "<style>body{font-family:Arial;background:#f8f9fa;color:#333;text-align:center;}";
	html += "table{margin:auto;border-collapse:collapse;width:80%;}";
	html += "th,td{border:1px solid #aaa;padding:8px;}th{background:#004b87;color:white;}</style></head><body>";
	html += "<h1>ESP32 Earthquake Log</h1><table><tr><th>Location</th><th>Magnitude</th><th>Distance (km)</th></tr>";


  while (file.available()) {
    String line = file.readStringUntil('\n');
    int firstComma = line.indexOf(',');
    int secondComma = line.indexOf(',', firstComma + 1);
    if (firstComma > 0 && secondComma > 0) {
      String place = line.substring(0, firstComma);
      String mag = line.substring(firstComma + 1, secondComma);
      String dist = line.substring(secondComma + 1);
      html += "<tr><td>" + place + "<td><td>" + mag + "</td><td>" + dist + "</td></tr>";
    }
  }
  file.close();

  html += "</table><p><em>Auto-refreshes every 60 seconds</em></p><body></html>";
  server.send(200, "text/html", html);
}

void startWebServer() {
  server.on("/", handleRoot);
  server.begin();
  Serial.println("Web server started. Access via http://" + WiFi.localIP().toString());
}

void loop() {
  gpsSerial.listen();
  while (gpsSerial.available()) gps.encode(gpsSerial.read());

  server.handleClient();
}

How it works

  1. WebServer server(80); creates a basic web server on port 80.
  2. The handleRoot() function reads quakes.csv and formats it into an HTML table.
  3. The meta refresh tag reloads the page every minute automatically.
  4. The startWebServer() function launches the web interface after Wi-Fi connects and SD initializes.

To start the dashboard, just call this inside setup() after SD initialization:

startWebServer();

When you connect to your ESP32’s IP (check Serial Monitor), you’ll see a simple HTML table listing quake records stored on the SD card:

Date Location Magnitude Distance
2025-10-18 Davao Region 5.7 120 km
2025-10-18 Mindoro Strait 4.9 450 km

The full code can be downloaded here: github repo

Notes

  • You can open the page from any device on the same Wi-Fi network (phone, laptop, tablet).
  • To clear old logs, simply remove or format the SD card.
  • You can expand this with JavaScript charting (like Chart.js) for visual magnitude trends later.

Visual Indicators

  • RGB LED Green — No nearby quakes.
  • RGB LED Red + Buzzer — Earthquake within ~200 km radius.

You can tweak the threshold or add yellow for “moderate distance.”


Bonus Improvements

  • Add a real-time clock (RTC) backup if NTP isn’t reachable.
  • Include magnitude filtering (e.g., only warn for M≥5.0).
  • Replace the buzzer with a relay and a siren for stronger sound alerts
  • Create a map visualization using Google Maps API for stored quakes.

Final Thoughts

With the NTP-based auto date update, GPS-based distance calculation, SD card logging, RGB alert LED, and now this web dashboard, your ESP32 Earthquake Monitor is a full-fledged, connected device worthy of a spot on your desk.

It not only helps answer “Was that an earthquake?” —it lets you prove it with data, logs, and a neat little web interface.

Check Also

How to use LM32 with Arduino or ESP32

How to Use LM35 Temperature Sensor with Arduino and ESP32: Complete Guide with Example Projects

Updated: October 31, 2025Introduction to LM35 Temperature Sensor The LM35 is a precision temperature sensor …

Index