Autonomous Flood Protection System
IoT-based automated flood barrier with real-time monitoring and control
FloodGate is an IoT system designed for automated flood protection. It combines local water detection (responding without cloud dependency) with remote monitoring and control (Web Dashboard / Smartphone). The system supports both automatic operation and manual override by the user.
Applications include:
- Garage Entrances: Protect basement garages from street flooding
- Building Entrances: Secure ground-floor premises during heavy rainfall
- Industrial Sites: Protect critical infrastructure and storage areas
- Technical Gates: Automated barrier for access points vulnerable to water damage
Default language is Polish. To switch UI to English:
cd scripts
python switch_language.py en # Switch to English
python switch_language.py pl # Switch back to PolishThis changes:
- ESP32 OLED display labels (WodaโWater, BramaโGate)
- SMS messages sent by device
- Frontend dashboard UI text
After switching, rebuild ESP32 firmware:
pio run
| Feature | Description |
|---|---|
| ๐จ Automatic Flood Detection | Water sensor triggers immediate gate closure |
| ๐ฑ Real-time Dashboard | React-based mobile-friendly interface |
| โฑ๏ธ Fail-safe Timer | Configurable countdown before auto-close |
| ๐ SMS Alerts | Notifications via MQTT (Wokwi simulation) |
| ๐ Telemetry Logging | TimescaleDB time-series storage |
| ๐ค๏ธ Weather Integration | Current weather from Open-Meteo API |
| ๐ Two Operation Modes | AUTOMATIC (instant) or MANUAL (confirmation) |
| ๐ฎ ESP32 Simulator | Full Wokwi integration in VS Code |
| ๐ Autonomous Operation | Non-blocking MQTT - works offline |
| ๐ Scheduler Support | Automated daily raise/drop times |
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ FRONTEND - React 19 + Vite + TailwindCSS โ
โ http://localhost:5173 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ HTTP REST
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ BACKEND API - FastAPI (Python 3.12) โ
โ http://localhost:8001 โ
โ Endpoints: /status, /command, /settings, /mode โ
โโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ MQTT
โโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโ
โผ โผ
โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ MQTT Broker โโโโโโโโโโโ Worker (Python) โ
โ Mosquitto:1883 โ โ Telemetry โ Database โ
โโโโโโโโโโฌโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ESP32-S3 (Wokwi Simulator) โ
โ Water Sensor, Stepper Motor, OLED, LEDs โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ DATABASE - TimescaleDB (PostgreSQL 15) โ
โ Port: 5434 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโ
โ ESP32 sends โ
โ sensor data โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ MQTT Broker โ
โ receives msg โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ Worker stores โ
โ in Database โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Data: water_level, battery โ
โ gate_state, timestamp โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโ
โ User clicks โ
โ gate button โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ Frontend sends โ
โ POST /command โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ API publishes โ
โ to MQTT โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ ESP32 receives โ
โ and moves gate โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ Telemetry sent โ
โ with new state โ
โโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโ
โ Water Detected โ
โ (sensor > 2000) โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโ
โผ โผ
โโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
โ AUTOMATIC โ โ MANUAL โ
โ MODE โ โ MODE โ
โโโโโโโโฌโโโโโโ โโโโโโโโโฌโโโโโโโโ
โ โ
โผ โผ
โโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
โClose gate โ โ Show Fail-Safeโ
โimmediately โ โ Modal (5 min) โ
โSend SMS โ โโโโโโโโโฌโโโโโโโโ
โโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโผโโโโโโโโโโโโโ
โผ โผ โผ
โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ
โ CLOSE โ โ CANCEL โ โ TIMEOUT โ
โ NOW โ โ (ignore)โ โ (5 min) โ
โโโโโโฌโโโโโโ โโโโโโฌโโโโโโ โโโโโโฌโโโโโโ
โ โ โ
โผ โผ โผ
โโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โโโโโโโโโโโโโโ
โClose gate โ โGate stays โ โClose gate โ
โSend SMS: โ โOPEN โ โSend SMS: โ
โ"Confirmed" โ โUser takes โ โ"Timeout" โ
โโโโโโโโโโโโโโ โresponsibilityโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโ
โ Worker checks โ
โ schedules table โ
โ (every minute) โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโ
โผ โผ
โโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
โ No match โ โ Time matches โ
โ (skip) โ โ enabled rule โ
โโโโโโโโโโโโโโ โโโโโโโโโฌโโโโโโโโ
โ
โโโโโโโโโโโโโโโดโโโโโโโโโโโโโโ
โผ โผ
โโโโโโโโโโโโโโ โโโโโโโโโโโโโโ
โ Water NOT โ โ Water IS โ
โ detected โ โ detected โ
โโโโโโโโฌโโโโโโ โโโโโโโโฌโโโโโโ
โ โ
โผ โผ
โโโโโโโโโโโโโโ โโโโโโโโโโโโโโ
โ Execute โ โ SKIP actionโ
โ scheduled โ โ Safety has โ
โ action โ โ priority! โ
โโโโโโโโโโโโโโ โโโโโโโโโโโโโโ
- Docker (for containers)
- Python 3.10+ with pip
- Node.js 18+ with npm
- VS Code with PlatformIO extension (for ESP32)
cd backend-infrastructure
docker-compose up -dStarts:
floodgate_db- TimescaleDB on port 5434floodgate_mqtt- Mosquitto on port 1883
cd backend-core
pip install -r requirements.txt
python run_api.pyAPI available at http://localhost:8001
cd backend-core
python worker.pycd frontend
npm install
npm run devDashboard at http://localhost:5173
Before running the ESP32 firmware, you must set up your network credentials:
First time setup:
cd firmware
cp include/Secrets.h.example include/Secrets.hThen edit firmware/include/Secrets.h with your actual credentials:
#define WIFI_SSID "YOUR_WIFI_SSID" // Your WiFi network name
#define WIFI_PASS "YOUR_WIFI_PASSWORD" // Your WiFi password
#define MQTT_SERVER "YOUR_MQTT_IP" // MQTT broker IP addressFor Wokwi simulation:
WIFI_SSID:"Wokwi-GUEST"WIFI_PASS:""(empty)MQTT_SERVER: Your PC's IP address (runipconfigon Windows,ip aon Linux/macOS)
Important: include/Secrets.h is gitignored and will NOT be committed to the repository for security.
- Open
firmware/folder in VS Code - Install Wokwi for VS Code extension
- Press
F1โ "Wokwi: Start Simulator" - Firmware will compile with credentials from
include/Secrets.h
| Technology | Version | Purpose |
|---|---|---|
| React | 19.2.0 | UI Framework |
| TypeScript | 5.9.3 | Type Safety |
| Vite | 7.2.4 | Build Tool |
| TailwindCSS | 4.1 | Styling |
| TanStack Query | 5.x | Server State |
| Zustand | 4.x | Client State |
| Framer Motion | 11.x | Animations |
| Axios | 1.x | HTTP Client |
| Technology | Version | Purpose |
|---|---|---|
| FastAPI | 0.109 | REST API |
| Python | 3.12 | Runtime |
| Paho MQTT | 2.0 | MQTT Client |
| SQLAlchemy | 2.x | ORM |
| AsyncPG | 0.29 | PostgreSQL Driver |
| Uvicorn | 0.27 | ASGI Server |
| Technology | Version | Purpose |
|---|---|---|
| TimescaleDB | 2.x | Time-series Database |
| PostgreSQL | 15 | Database Engine |
| Mosquitto | 2.x | MQTT Broker |
| Docker | 24.x | Containerization |
| Technology | Version | Purpose |
|---|---|---|
| ESP32-S3 | - | Microcontroller |
| Arduino | 2.0.6 | Framework |
| PlatformIO | 6.x | Build System |
| PubSubClient | 2.8 | MQTT Library |
| ArduinoJson | 6.21 | JSON Parsing |
| Adafruit SSD1306 | 2.5 | OLED Display |
INZYNIERKA/
โโโ backend-core/ # Python API + Worker
โ โโโ main.py # FastAPI application
โ โโโ worker.py # MQTT โ Database bridge
โ โโโ database.py # SQLAlchemy models
โ โโโ requirements.txt
โโโ backend-infrastructure/ # Docker services
โ โโโ docker-compose.yml
โโโ frontend/ # React application
โ โโโ src/
โ โ โโโ components/ # UI components
โ โ โโโ hooks/ # Custom React hooks
โ โ โโโ api/ # API client
โ โ โโโ App.tsx
โ โโโ package.json
โโโ firmware/ # ESP32 code
โ โโโ src/main.cpp # Main firmware
โ โโโ platformio.ini # PlatformIO config
โ โโโ diagram.json # Wokwi circuit
โ โโโ wokwi.toml # Wokwi config
โโโ scripts/
โ โโโ switch_language.py # PL/EN language switcher
โโโ simulation/ # HIL testing tools
โโโ README.md
This project uses Wokwi for ESP32 simulation, integrated into VS Code.
- Install VS Code extension: Wokwi for VS Code
- Get free license at https://wokwi.com/license
- Open
firmware/diagram.json - Press
F1โ "Wokwi: Start Simulator"
| Component | GPIO | Function |
|---|---|---|
| Water Sensor | GPIO4 | Analog input (0-50cm) |
| Battery Sensor | GPIO5 | Analog input (0-100%) |
| Stepper STEP | GPIO10 | Motor control |
| Stepper DIR | GPIO11 | Motor direction |
| Red LED | GPIO16 | Gate closing indicator |
| Green LED | GPIO17 | Gate opening indicator |
| OLED SDA | GPIO18 | Display data |
| OLED SCL | GPIO19 | Display clock |
The sendSMS() function publishes to MQTT topic debug/sms instead of sending real SMS. This is for Wokwi compatibility. For production with SIM800L module, replace the implementation with AT commands.
Returns current device status with weather data.
{
"device_id": "ESP32_MAIN_001",
"telemetry": {
"water_level_cm": 3.2,
"gate_closed": 0,
"battery_pct": 85,
"state": "IDLE",
"scheduler_locked": 0
},
"logic": {
"current_mode": "AUTOMATIC",
"current_state_code": 0,
"fail_safe_deadline": null
},
"weather": {
"temperature": 12.5,
"precipitation": 0.0
}
}Telemetry Fields:
water_level_cm- Water level in centimeters (0-50cm range)gate_closed- Gate state: 0=OPEN, 1=CLOSEDbattery_pct- Battery percentage (0-100%)state- System state: IDLE, WATER_DETECTED, CLOSED, AUTO_DROP, etc.scheduler_locked- Scheduler lock: 0=unlocked, 1=locked (water detected)
Note: Firmware also sends backward-compatible fields (
water_sensor_status,curtain_state,battery_soc_perc) for legacy compatibility.
Send manual command to device.
{
"device_id": "ESP32_MAIN_001",
"action": "DROP" // or "RAISE"
}Get historical telemetry data (time-series).
Query Parameters:
device_id- Device identifier (default: ESP32_MAIN_001)limit- Number of records (default: 100)
Response: Array of telemetry records with timestamps.
Get alarm history (water detection events).
Query Parameters:
device_id- Device identifierlimit- Number of records (default: 50)
Get command history (user actions, scheduler actions).
Query Parameters:
device_id- Device identifierlimit- Number of records (default: 50)
Get configured automation schedules.
Response:
[
{
"id": 1,
"device_id": "ESP32_MAIN_001",
"action_type": "daily_raise",
"hour": 8,
"minute": 0,
"days": ["mon", "tue", "wed", "thu", "fri"],
"active": true,
"custom_label": "Morning open"
}
]Scheduler Features:
- Automated daily raise/drop at configured times
- Day-of-week filtering (e.g., weekdays only)
- Safety override: scheduler locked when water detected
- Worker monitors schedules every minute
This section documents known limitations and architectural choices that represent acceptable trade-offs for the current scope.
Current Implementation: The React dashboard uses HTTP Polling (5-second interval) to fetch device status from the backend API.
Why Polling?
- Simplified Architecture: Avoids WebSocket infrastructure complexity for the scope of this thesis project
- Backend Infrastructure: The backend (FastAPI) already provides a robust REST API; existing MQTT connection for device communication
- Cross-platform Compatibility: HTTP polling works consistently across all network conditions (firewalls, proxies)
- Single Source of Truth: Device state is computed server-side; frontend just reflects current state
- Sufficient for Flood Monitoring: 5-second refresh interval is acceptable for this use case (gates don't move faster than ~30 seconds)
Trade-off: The UI refreshes every 5 seconds, so user actions may appear with up to 5-second delay. If someone closes the gate, the UI updates within the next polling cycle (max 5sec).
When WebSockets Would Be Preferred:
- Enterprise deployment with thousands of concurrent dashboards
- Real-time dashboards requiring sub-second response (e.g., stock trading)
- Bandwidth-constrained environments (polling 5sec ร 1000 clients = significant overhead)
Production Path: To upgrade to WebSockets:
# Backend: Add python-socketio and python-socketio[aiohttp]
from socketio import AsyncServer
# Push device updates to connected clients via MQTT bridgesImplementation Details: See frontend/README.md for polling configuration (staleTime: 0, refetchInterval: 5000, etc.).
Current Implementation: sendSMS() function publishes to MQTT topic debug/sms for Wokwi simulation compatibility.
How It Works:
- Dashboard can subscribe to
debug/smsto receive "SMS" messages - Useful for testing without real GSM hardware
- No actual SMS sent in simulation mode
Production Implementation: Requires SIM800L GSM module with AT command implementation.
Setup for Production:
- Connect SIM800L module to ESP32 UART (GPIO5=RX, GPIO4=TX by default)
- Set phone number in
firmware/include/Secrets.h:#define GSM_PHONE_NUMBER "+48XXXXXXXXX"
- Uncomment SIM800L code block in
firmware/src/main.cppinsendSMS()function - Requires dedicated 4.2V power supply for GSM module
Code Template Provided: See firmware/README.md for complete AT command reference and production code example.
Design Challenge: Initial blocking delayMicroseconds() loops during gate movement locked the processor, preventing MQTT client.loop() from executing. This resulted in connection timeouts and unresponsive user commands during operation.
Architectural Solution: Implemented AccelStepper library with non-blocking state machine. The updateStepperMotion() function executes every loop iteration (~2ms per step), enabling concurrent MQTT processing between motor steps.
Result: Device maintains responsive MQTT communication and processes user commands immediately during gate movement.
Implementation Details: See firmware/README.md for architecture diagram and code details.
Design Challenge: Initial implementation used blocking MQTT connection loop in setup(), preventing ESP32 from booting if broker was unavailable. Device would hang indefinitely showing "Booting..." on OLED.
Architectural Solution:
- Setup Phase: Max 3 connection attempts with 1-second timeout each
- Loop Phase: Non-blocking reconnect every 30 seconds
- Autonomous Mode: Device operates fully offline if MQTT unavailable
Implementation:
// setup() - Try 3 times, then continue
int mqttAttempts = 0;
while (!client.connected() && mqttAttempts < 3) {
if (client.connect(DEVICE_ID)) break;
mqttAttempts++;
delay(1000);
}
// Continue regardless of connection status
// loop() - Retry every 30 seconds (non-blocking)
static unsigned long lastMqttRetry = 0;
if (!client.connected() && (millis() - lastMqttRetry > 30000)) {
lastMqttRetry = millis();
client.connect(DEVICE_ID); // Single attempt, no blocking
}Benefits:
- โ ESP32 boots in 3-4 seconds even without MQTT broker
- โ Sensors, OLED, and motor control work offline
- โ Automatic reconnection when broker becomes available
- โ Water detection and auto-close work without backend
Result: Device is fully autonomous and resilient to network failures.
The fail-safe countdown relies on client-side timer (setInterval). For critical systems, this should run server-side with the device itself enforcing the timeout via hardware interrupt (E-STOP button for production).
Current Safety Level: Device has hardware E-STOP interrupt (GPIO2 pull-to-ground). Even if software fails, gate can be stopped physically.
Design Choice: Sensitive credentials (WiFi, MQTT, GSM phone) stored in gitignored Secrets.h file, never committed to repository.
How It Works:
firmware/include/Secrets.h.exampleprovides template- User copies to
Secrets.hand fills in credentials .gitignoreprevents accidental commit
Production Safety: Each device deployment has unique Secrets.h; credentials not exposed in git history or public repositories.
Implementation: See firmware/README.md for setup instructions.
Design Choice: Gate position saved to EEPROM only when changed (not every movement). Extends device lifetime from ~273 years to 137+ years within the 100k write cycle limit.
Calculation:
- Estimated usage: 2 movements/day
- Writes per year: 730
- Lifetime: 100,000 รท 730 = 137+ years โ
Implementation: See firmware/README.md for code and monitoring details.
This project is licensed under the PolyForm Noncommercial 1.0.0 - see the LICENSE file for details.
โ ๏ธ LICENSE: This project is shared under the PolyForm Noncommercial 1.0.0 license.
- โ Free: For private, educational, and hobbyist use (Self-Hosted).
- โ Paid/Requires Permission: For any commercial use, resale, or commercial deployment.
For commercial licensing inquiries (B2B), please contact: adam.gajewski.art@gmail.com
๐ Created as an engineering thesis project.
Made with โค๏ธ using ESP32 and Python
