IoT-Based Vertical Hydroponic System for Sustainable Off-Season Cultivation of Cucumis melo (Melon)
One greenhouse (4 × 5 m), two existing vertical hydroponic towers, one ESP32-based IoT controller, automated nutrient dosing, water-flow management, environmental control, hybrid solar/grid power, and a web-based monitoring and management system.
Features · Tech Stack · Quick Start · Hardware · Project Structure · Documentation
HydroLT monitors and automates a soilless vertical-farm grow environment end to end: an ESP32 controller reads pH, EC, temperature, humidity, water flow and NPK from connected sensors, runs local fail-safe automation, and streams telemetry to a Firebase Realtime Database backend. A Next.js web app provides a real-time dashboard, historical trending, remote controls and an alerts feed — usable from any browser, on desktop or mobile.
Automation keeps running without an internet connection (FR-10); the cloud layer is for observability and remote override, not for keeping plants alive.
- pH and EC (nutrient strength) with configurable target bands and safety alarms
- NPK (nitrogen / phosphorus / potassium) via a dedicated RS485 Modbus RTU probe — measured, never derived from pH/EC
- Air temperature & humidity (DHT22) with exhaust-fan and misting control
- Water flow (pulse sensor) with low-flow pump cutoff
- Telemetry streamed to Firebase Realtime Database (
devices/<device>/…) with live state and device presence
- Closed-loop pH/EC dosing — one channel at a time, hard burst caps, cooldowns
- Closed-loop NPK dosing (FR-13) — bounded and interlocked; blocked whenever the probe, pH or EC is invalid, EC is above target, or the solution is not circulating
- Exhaust fan (temperature) and misting (humidity) automation
- Irrigation pump with flow-verified startup and fail-safe low-flow cutoff
- Manual override from the web app via RTDB command queue (
devices/<device>/commands)
- Invalid sensor readings block dosing — no uncontrolled nutrient/acid dosing
- Non-blocking,
millis()-based main loop; watchdog recovery on the main loop - Local automation continues with no internet; cloud is optional
- Security rules on the Firebase Realtime Database; no secrets or credentials stored in the database
- Real-time dashboard with live stat cards and trend charts
- History page with time-window filters (6 h / 24 h / 7 d / 30 d) and CSV export
- Controls page for setpoints, NPK bands, kill switches and manual dose triggers
- Alerts feed with device health and event history
- Demo mode — runs with simulated data and no backend, so you can preview instantly
- Password auth (Firebase) protecting the dashboard and device controls
| Layer | Technology |
|---|---|
| Framework | Next.js 15 (App Router) + React 19 |
| Language | TypeScript 5.7 |
| Backend / DB | Firebase — Realtime Database, Auth, security rules |
| Realtime | RTDB live queries; polling hooks in the client |
| Charts | Custom lightweight LineChart component |
| Component | Detail |
|---|---|
| Board | ESP32 Dev Module (Arduino-ESP32 core 3.3.11) |
| Framework | Arduino framework via arduino-cli / Arduino IDE |
| Libraries | Firebase Arduino Client (Mobizt) · DHT sensor library + Adafruit Unified Sensor · ArduinoJson 7.4.3 |
| Field bus | RS485 Modbus RTU master built into the sketch (no extra library) over UART2 via MAX485 |
| Verified build | esp32:esp32:esp32 — 1,260,853 B flash (96 %), 53,688 B RAM (16 %) |
- Node.js 18+ and npm
- arduino-cli (or Arduino IDE) with the
esp32:esp32board package — firmware only - A Firebase project — optional; without it the app runs in demo mode
cd src/webapp/HydroLT
npm install
npm run devOpen http://localhost:3000.
The dashboard runs in demo mode with simulated data when no Firebase environment variables
are set, so you can preview it immediately. To connect a real backend, copy .env.example to
.env.local and fill in your Firebase project values — see docs/setup.md.
With a real backend, the first-run flow is: sign up (or sign in) → connect to your
controller by entering its unique device ID → dashboard. The device ID is validated against
the devices/{id} node and remembered in the browser.
npm run build # production build
npm start # serve the production build
npm run typecheck # tsc --noEmit- Open
src/esp/HydroLT/HydroLT.inoin the Arduino IDE (or PlatformIO). The sketch is split into modules (config.h,sensors.*,npk.*,automation.*,firebase_db.*,commands.*, …) — the IDE compiles them automatically as long as the whole folder is kept together. - Install the board support esp32 by Espressif Systems and the libraries:
Firebase Arduino Client Library for ESP8266 and ESP32(Mobizt)DHT sensor library(Adafruit) +Adafruit Unified SensorArduinoJson(Benoit Blanchon)- (the RS485 NPK probe needs no extra library — a Modbus RTU master is built into the firmware)
- Copy
secrets.h.exampletosecrets.h(git-ignored) and setHYDRO_WIFI_SSID,HYDRO_WIFI_PASS,HYDRO_FB_API_KEY,HYDRO_FB_DB_URL,HYDRO_FB_EMAIL,HYDRO_FB_PASSWORD,HYDRO_DEVICE_ID, plus pin assignments for your actual wiring. - Select ESP32 Dev Module, compile, upload.
- Serial monitor at 115200 baud for boot and diagnostic logs.
Full wiring/setup guidance: docs/setup.md.
Note: the NPK probe and the three N/P/K dosing pumps are optional. The firmware, database and web app already support them, and the system runs fine without the hardware fitted.
| Category | Component | Role |
|---|---|---|
| Controller | ESP32 Dev Module | Main controller, Wi-Fi + Firebase RTDB |
| MAX485 module | RS485 transceiver for the NPK probe | |
| Sensors | pH sensor + analog module | Nutrient acidity (GPIO 34) |
| EC sensor + module | Nutrient conductivity / strength (GPIO 35) | |
| DHT22 | Air temperature & humidity (GPIO 4) | |
| Water flow sensor | Irrigation flow (GPIO 27, interrupt) | |
| RS485 NPK probe (optional) | N / P / K via Modbus RTU (GPIO 16/17/13) | |
| Actuators | 5× peristaltic dosing pumps | pH-up, pH-down, N, P, K (GPIO 32/14/18/19/21) |
| Submersible pump | Irrigation (relay, GPIO 26) | |
| Exhaust fan | Cooling / VPD control (relay, GPIO 25) | |
| Misting pump | Humidity / cooling (relay, GPIO 33) | |
| Power | Hybrid solar/grid supply | Controller + peripherals |
Full pin map and wiring: docs/setup.md.
hydrolyt/
├── README.md ← this file
├── LICENSE ← MIT
├── docs/ ← project documentation
│ ├── requirements.md ← full requirements & acceptance criteria
│ ├── database-schema.md ← RTDB schema + security rules
│ └── setup.md ← firmware & web app setup guide
└── src/
├── esp/
│ └── HydroLT/ ← ESP32 controller firmware (modular Arduino sketch)
│ ├── HydroLT.ino ← setup() + loop() entry point
│ ├── config.h ← pins, limits, timings, credential macros
│ ├── sensors.* npk.* ← pH/EC/climate/flow and RS485 NPK probe
│ ├── actuators.* automation.* ← relays and control loops
│ ├── firebase_db.* commands.* connectivity.* ← RTDB, commands, session
│ └── state.* types.h util.* logging.* settings_store.* ← support modules
└── webapp/
└── HydroLT/ ← Next.js + TypeScript web application
├── app/ ← App Router pages (dashboard, history, controls, alerts)
├── components/ ← reusable UI components
├── hooks/ ← telemetry polling hooks
└── lib/ ← types, Firebase client, mock data
| Document | Contents |
|---|---|
| docs/requirements.md | Functional/hardware requirements, automation logic, scope, 3-week plan, acceptance criteria |
| docs/database-schema.md | RTDB tree layout, security rules, retention, migration notes |
| docs/setup.md | Environment setup, firmware configuration, RTDB paths, deployment notes |
RTDB layout: devices/<device_id>/ → info, status, telemetry, history, state, settings, commands, acks, alerts, events — plus users/<uid> for roles.
| Dashboard | Controls |
|---|---|
![]() |
![]() |
Contributions are welcome. This project is under active development for a client deployment, so issues and pull requests are accepted but may be reviewed selectively.
- Fork the repository and create a feature branch (
git checkout -b feature/my-feature). - Make your changes and keep the build green —
npm run buildandnpm run typecheckmust pass; firmware must compile warning-free foresp32:esp32:esp32. - Open a pull request with a clear description of the change and its rationale.
Please keep safety-critical invariants intact: pH/EC must never be presented or derived as NPK, invalid readings must continue to block dosing, and local automation must keep running offline.
qppd — github.com/qppd
This project is licensed under the MIT License — see LICENSE for details.
- Espressif Systems — ESP32 platform and Arduino core
- Arduino —
arduino-cliand the library ecosystem - Mobizt's Firebase Arduino Client — Firebase Auth + Realtime Database for ESP32
- Adafruit — DHT sensor library and Unified Sensor abstraction
- ArduinoJson by Benoit Blanchon — JSON for embedded
- Firebase — Realtime Database, Auth and security rules
- Mains (220 V) and the 3.3 V/5 V ESP32 domain must stay physically separated. Use rated contactors/relays, fuses/breakers, grounding, and a protected enclosure.
- Never tie the grid and inverter outputs together without approved automatic transfer equipment and backfeed prevention.
- pH and EC do not measure NPK. Nitrogen, phosphorus and potassium are read only from the dedicated RS485 NPK probe — never derived from pH or EC, and shown as unavailable whenever the probe is faulted or not fitted.
- NPK dosing is bounded and interlocked: one channel at a time, hard burst cap, cooldown, and a 30-minute lockout with an alert if a reading stops responding. It is blocked whenever the NPK probe, pH or EC is invalid, EC is above target, or the solution is not circulating.
- Firmware enforces fail-safe behavior: invalid sensor readings block dosing, low flow stops the irrigation pump, and local automation keeps running without internet.
Three-week implementation target: W1 foundation + dashboard + preliminary 3D model · W2 firmware + integration · W3 testing + handover.

