Final project
Modular Hydroponic System¶
GROWZEN © 2025 by Zhirayr Ghukasyan is licensed under CC BY-NC-SA 4.0
Designed for growing plants at home in urban environments, it addresses the challenges of modern city living, where limited space and time often prevent people from interacting with nature. The system automatically takes care of the plants by supplying water, regulating lighting, monitoring liquid levels, and controlling other essential parameters. All information is conveniently displayed on the user’s smartphone. This makes plant care simple and accessible even for those with no gardening experience. The project provides an efficient and user-friendly solution that brings a touch of nature back into everyday urban life and makes it available to anyone, regardless of their schedule or experience.
Task List¶
-
Tasks Completed / Not Completed¶
- ✅ Modular construction
- ✅ Water circulation system
- ✅ System integration
- ✅ Application development
- ⬛ Liquid auto-calibration
- ⬛ Lighting integration
-
What Worked / What Didn’t¶
- ✅ Aerator for oxygenating water
- ✅ Water pump for liquid supply
- ✅ Water temperature sensor
- ✅ Float-type water level sensor
- ✅ TDS meter for dissolved solids
- ⬛ pH meter for measuring liquid acidity
Weekly Assignments for Final Project Development¶
-
Week 2
Forming the Idea and Initial Sketches.
-
Week 5
First Draft of the 3D Mode.
-
Week 8
Development and Assembly of the Electronic Circuit.
-
Week 10
Testing the Water Pump.
-
Week 11
ESP32-C3 Control via Wi-Fi Using the Blynk.
-
Week 14
Application Improvement and TDS Meter Calibration.
-
Week 15
System Assembly and Testing.
-
Week 16-20 - This page
Final 3D Model Creation, Connection Nodes Testing, Final PCB Fabrication, Programming, and Assembly.
Project Management¶
To complete the project on time, I decided to divide the development process into two main stages. This approach allowed me to structure the work, set clear priorities, and ensure high-quality execution of each part of the project.
The first stage focused on the visual aspect of the system. At this stage I concentrated on designing the exterior, ergonomics, choice of materials, and overall aesthetics. It was important for the device not only to perform its functions but also to blend well into a home environment. I created a 3D model of the casing, developed a modular construction system with proper mounting solutions, and went through several design iterations based on feedback and observations.
The second stage addressed the internal part of the system, its functional and electronic components. During this phase I selected and connected all necessary components, such as sensors, the microcontroller, the power supply system, water pumps, and other elements. I also developed the automation logic, wrote the code for the microcontroller, and conducted tests to ensure the system’s stability and reliability.
By dividing the project into these two stages I was able to thoroughly focus on both the visual and technical aspects of the system without overlapping tasks. As a result, I achieved a balanced outcome that combines both aesthetic appeal and robust functionality.
Process¶
Research¶
Automated hydroponic systems are quite popular both in open-source communities and on the commercial market. Many solutions have already been implemented through educational platforms like Fab Academy, as well as in the form of ready-to-use consumer products.
Here are some projects by Fab Academy students that I found very interesting and inspiring. They helped me better understand different approaches to developing my own hydroponic system and gave me ideas for both technical implementation and design.
Fab Academy Student Projects.¶
Commercially Available Systems.¶
These commercially available systems demonstrate different approaches to home hydroponic growing, each with unique features:
-
Gardyn Home 4.0 - a smart vertical system with cameras and artificial intelligence, enabling automatic plant monitoring and care.
-
LetPot Smart Garden - a compact and budget-friendly solution that makes hydroponics accessible to more users without sacrificing functionality.
-
AeroGarden Harvest/Sprout - simple and reliable hydroponic kits popular for their ease of use and consistent results.
Studying these systems gave me valuable ideas on balancing technology, cost, and user convenience in my own project.
Sketches¶
Since the very beginning of the course, I was certain that this would be my final project, so I started developing the concept in the first week. At that time, I created several initial sketches to visualize the core ideas. Later, during the Computer Aided Design week, I began turning those sketches into digital drafts. I focused on making the shapes more accurate and realistic to evaluate the overall appearance and design logic of the device at an early stage.
During the 3D Scanning and Printing week, I decided to slightly modify the original design of the device. Experiments with 3D scanning and printing gave me a new perspective on the structure and form of certain elements. However, this revised version did not become the final one — I later abandoned it in favor of a more refined design. Still, this stage was important in the development process, as it helped me better understand the limitations of the technologies and influenced the evolution of the project.
3D Model¶
After the MidTerm Review, I finalized the shape and overall design direction of the device. At this stage, I began working on a more detailed construction using Rhinoceros. I applied basic tools, simple geometric forms, and techniques that I had already demonstrated during previous weekly assignments and documented accordingly. This approach helped maintain a clean and logical design while also simplifying the preparation of the model for production.
A thorough modular design approach was applied to the hydroponic system to ensure maximum flexibility and ease of use. Each module was designed with specific functions and overall system requirements in mind, facilitating assembly, maintenance, and potential scalability.
The main modules include¶
- seed planting module
- pipe to maintain the necessary distance between plant growth modules
- electronics enclosure
- enclosure cover
- adapters for securing the modules and enclosure
- sensor placement module
- top plug
The module connection principle in the system is very simple and intuitive. First, the pipe is inserted into the plant growth module, then rotated clockwise to secure the connection. All connection points have standardized dimensions and tolerances, ensuring compatibility between modules. This allows for easy addition of extra pipes or modules as needed, enabling system expansion and adaptation to different requirements.
A similar twist-lock mechanism is provided for attaching the modules to the enclosure cover, ensuring a simple and secure fixation of the components.
The enclosure cover is secured to the main enclosure using six M3 bolts, providing a reliable and watertight connection. The cover is designed to prevent water ingress during circulation, protecting the electronics from damage and increasing the overall durability of the system.
The module for sensors easily inserts into a specially designed opening in the enclosure, providing the required insertion depth for the sensors and secure fixation. This design ensures stable sensor operation and facilitates convenient replacement during system maintenance.
The case fits snugly yet easily into the liquid reservoir, which was purchased at a local store. The case cover rests tightly on the edges of the reservoir, providing a reliable seal and preventing contaminants from entering the system.
After completing the 3D modeling, it becomes possible to observe the full interaction of all parts within a unified system. This not only allows for visualization of the final appearance of the device but also enables the assessment of module compatibility, verification of connection accuracy, and identification and resolution of potential errors and issues at the design stage. Such an approach significantly simplifies subsequent assembly and increases the reliability of the finished product.
Printing¶
After confirming the correctness of all connections and the accuracy of the 3D model, it was time to proceed to printing the parts. The 3D printing process turned out to be probably the longest and most labor-intensive stage of the project, requiring careful parameter control and a meticulous approach to achieve high-quality and precise components.
The parts were printed on a Qidi Tech Q1 3D printer using PET-G filament. This material was chosen for its strength and resistance to moisture and chemicals, which is especially important for components of the hydroponic system. The printing process required fine-tuning of optimal settings to ensure high accuracy and quality of the final parts. You can check the parameters for printing PET-G on the Qidi printer here
Laser Cut¶
To ensure moisture retention in the modules, it was decided to use a cellulose sponge. The purchased material had a thickness of 2 mm and dimensions of 106×66 mm. After soaking, the sponge thickness increases to 15–20 mm, significantly enhancing its ability to retain moisture. To integrate the sponge into the design, I created a DXF file with the necessary holes. These holes were designed to allow free circulation of the liquid while simultaneously ensuring moisture retention by the sponge.
Using a template, I placed the dry sponge on the laser cutter bed and set the cutting parameters to 20% power and 30 mm/s speed. These settings ensured precise and clean material processing without damage. After that, I placed the sponge into the module and slightly moistened it. Due to expansion when wet, the sponge fits tightly in place, providing reliable moisture retention.
The photos below show a visual comparison of the sponge in its dry state and after soaking. After being immersed in water, the sponge significantly increases in volume and changes its structure, confirming its ability to effectively retain moisture within the module.
Electronics Production¶
As the basis for the project, I used a printed circuit board (PCB) that I created during the Electronics Production week. This board served as the foundation for integrating all electronic components of the system, providing the necessary routing and reliable connections between elements. Thanks to the custom design, I was able to account for all specific project requirements and optimize component placement for ease of assembly and future maintenance.
I decided to make the PCB double-sided to reduce its size and increase the compactness of the device. Using a two-layer design allowed for more optimal placement of components and routing, improving overall ergonomics and simplifying assembly.
To implement double-sided milling, I made small holes for pins in the four corners of the PCB. Thanks to the symmetrical design, after completing the front side processing, I simply flipped the board and fixed it on the worktable using the pre-made holes, additionally securing it with double-sided tape to ensure reliable fixation during the milling of the back side. After that, I proceeded with milling the back side of the PCB.
After completing the milling process, I began soldering all the electronic components onto the board, carefully ensuring each element was correctly connected. After assembly, I connected the power button and tested the operation of the water pump, as well as verified the overall functionality of the board, confirming the system was working properly.
Input Devices and Output Devices¶
- Input section, which includes:
- A pH meter used to measure the acidity or alkalinity of water. It displays the pH value, indicating whether the water is acidic, neutral, or alkaline.
- A TDS meter used to measure the total dissolved solids in water such as minerals to assess water quality.
- A Water level sensor.
- A Water temperature sensor.
-
Output section, which includes:
-
A water pump, for circulating or delivering water to the plants,
-
An aerator, for increasing the oxygen level in the water,
-
Programming¶
During the project development, I used DeepSeek to merge separate code fragments, which helped avoid conflicts and ensured stable program operation.
Code for Hydroponic System
// ===== BLYNK SETTINGS ===== //
#define BLYNK_TEMPLATE_ID "TMPL6lHnyAGw0" // Blynk template ID
#define BLYNK_TEMPLATE_NAME "Hydrophobics" // Project name in Blynk
#define BLYNK_AUTH_TOKEN "Your Auth Token" // Device auth token
#define BLYNK_PRINT Serial // Enable debug output to Serial
// ===== LIBRARIES ===== //
#include <WiFi.h> // ESP32 WiFi functionality
#include <WiFiClient.h> // WiFi client for connections
#include <BlynkSimpleEsp32.h> // Blynk library for ESP32
#include <OneWire.h> // 1-Wire protocol library
#include <DallasTemperature.h> // DS18B20 temperature sensors
#include <DFRobot_PH.h> // pH sensor library
// ===== CONNECTION DATA ===== //
char ssid[] = "staff"; // WiFi network SSID
char pass[] = "SRGB2020"; // WiFi password
char auth[] = BLYNK_AUTH_TOKEN; // Blynk authentication token
// ===== PIN ASSIGNMENTS FOR XIAO ESP32C3 ===== //
const int tdsPin = 2; // TDS sensor pin (GPIO2, ADC1)
const int phPin = 3; // pH sensor pin (GPIO3, ADC1)
const int tempPin = 4; // Temperature sensor pin (GPIO4)
const int floatSwitchPin = 5; // Float switch pin (GPIO5)
const int pumpPin = 10; // Water pump control pin (GPIO10)
const int aeratorPin = 6; // Aerator control pin (GPIO6, PWM)
// ===== BLYNK VIRTUAL PINS ===== //
#define V_TDS 0 // Virtual pin for TDS value
#define V_PH 3 // Virtual pin for pH value
#define V_TEMP 1 // Virtual pin for temperature
#define V_FLOAT_SWITCH 2 // Virtual pin for float switch
#define V_FLOAT_LED 2 // Virtual pin for level indicator
#define V_PUMP_SWITCH 4 // Virtual pin for pump control
#define V_AERATOR_SWITCH 5 // Virtual pin for aerator control
// ===== PWM SETTINGS FOR AERATOR ===== //
#define AERATOR_PWM_CHANNEL 0 // LEDC channel (0-5)
#define AERATOR_PWM_FREQ 5000 // PWM frequency 5 kHz
#define AERATOR_PWM_RESOLUTION 8 // 8-bit resolution (0-255)
#define AERATOR_PWM_VALUE 128 // Duty cycle value (50%)
// ===== TIMING SETTINGS (ms) ===== //
const long tdsTempDuration = 5 * 60 * 1000; // 5 min for TDS/temp measurements
const long phDuration = 5 * 60 * 1000; // 5 min for pH measurements
const long pumpWorkDuration = 3 * 60 * 1000; // 3 min pump operation time
const long aeratorWorkDuration = 10 * 60 * 1000;// 10 min aerator operation time
const long pumpRestDuration = 6 * 60 * 60 * 1000; // 6 hours pump idle time
const long aeratorRestDuration =3 * 60 * 60 * 1000; // 3 hours aerator idle time
// ===== SYSTEM STATE VARIABLES ===== //
unsigned long sensorTimer = 0; // Sensor switching timer
bool isTdsTempPhase = true; // Current measurement phase flag
unsigned long pumpTimer = 0; // Pump operation timer
unsigned long aeratorTimer = 0; // Aerator operation timer
bool pumpState = false; // Current pump state
bool aeratorState = false; // Current aerator state
bool systemEnabled = false; // System active flag
// ===== SENSOR OBJECTS ===== //
OneWire oneWire(tempPin); // Initialize 1-Wire bus
DallasTemperature sensors(&oneWire); // Temperature sensors object
DFRobot_PH ph; // pH sensor object
void setup() {
Serial.begin(115200); // Initialize serial communication
Blynk.begin(auth, ssid, pass); // Connect to Blynk server
// Pin configuration
pinMode(tdsPin, INPUT); // Set TDS pin as input
pinMode(phPin, INPUT); // Set pH pin as input
pinMode(floatSwitchPin, INPUT_PULLUP); // Float switch with pull-up
pinMode(pumpPin, OUTPUT); // Pump control as output
// PWM configuration for aerator
ledcSetup(AERATOR_PWM_CHANNEL, // Configure PWM channel
AERATOR_PWM_FREQ,
AERATOR_PWM_RESOLUTION);
ledcAttachPin(aeratorPin, AERATOR_PWM_CHANNEL); // Attach pin to PWM channel
ledcWrite(AERATOR_PWM_CHANNEL, 0); // Initially turned off
// Sensor configuration
analogReadResolution(12); // Set ADC to 12-bit resolution
sensors.begin(); // Initialize temperature sensor
sensors.setResolution(12); // Set 12-bit resolution
ph.begin(); // Initialize pH sensor
// Initial states
digitalWrite(pumpPin, LOW); // Turn pump off initially
pumpState = false; // Reset pump state
aeratorState = false; // Reset aerator state
systemEnabled = false; // System starts disabled
sensorTimer = millis(); // Initialize sensor timer
Serial.println("System initialized"); // Ready message
}
void loop() {
Blynk.run(); // Handle Blynk operations
if (systemEnabled) { // If system is active
// Measurement mode management
if (isTdsTempPhase) { // TDS and temperature phase
if (millis() - sensorTimer > tdsTempDuration) { // Check elapsed time
isTdsTempPhase = false; // Switch to pH phase
sensorTimer = millis(); // Reset timer
Serial.println("Switching to pH");
} else {
readAndSendTDS(); // Read and send TDS value
readAndSendTemp(); // Read and send temperature
}
} else { // pH phase
if (millis() - sensorTimer > phDuration) { // Check elapsed time
isTdsTempPhase = true; // Switch back to TDS/temp
sensorTimer = millis(); // Reset timer
Serial.println("Switching to TDS and temperature");
} else {
readAndSendPH(); // Read and send pH value
}
}
// Pump control logic
if (!pumpState && (millis() - pumpTimer > pumpRestDuration)) {
pumpTimer = millis(); // Reset timer
digitalWrite(pumpPin, HIGH); // Turn pump on
pumpState = true; // Update state
Serial.println("Pump activated");
}
else if (pumpState && (millis() - pumpTimer > pumpWorkDuration)) {
pumpTimer = millis(); // Reset timer
digitalWrite(pumpPin, LOW); // Turn pump off
pumpState = false; // Update state
Serial.println("Pump deactivated");
}
// Aerator control (only when pump is off)
if (!pumpState) {
if (!aeratorState && (millis() - aeratorTimer > aeratorRestDuration)) {
aeratorTimer = millis(); // Reset timer
ledcWrite(AERATOR_PWM_CHANNEL, AERATOR_PWM_VALUE); // Turn on
aeratorState = true; // Update state
Blynk.virtualWrite(V_AERATOR_SWITCH, 1); // Update Blynk
Serial.println("Aerator activated (6V)");
}
else if (aeratorState && (millis() - aeratorTimer > aeratorWorkDuration)) {
aeratorTimer = millis(); // Reset timer
ledcWrite(AERATOR_PWM_CHANNEL, 0); // Turn off
aeratorState = false; // Update state
Blynk.virtualWrite(V_AERATOR_SWITCH, 0); // Update Blynk
Serial.println("Aerator deactivated");
}
} else {
if (aeratorState) { // Force turn off if pump is on
ledcWrite(AERATOR_PWM_CHANNEL, 0); // Turn off aerator
aeratorState = false; // Update state
Blynk.virtualWrite(V_AERATOR_SWITCH, 0); // Update Blynk
Serial.println("Aerator deactivated (pump is running)");
}
}
}
checkFloatSwitch(); // Check water level status
delay(1000); // 1 second delay
}
// ===== SENSOR FUNCTIONS ===== //
void readAndSendTDS() {
float tdsValue = analogRead(tdsPin); // Read raw TDS value
float voltage = tdsValue * 3.3 / 4095.0; // Convert to voltage
float ecValue = (133.42*pow(voltage,3) + // Calculate conductivity
255.86*pow(voltage,2) +
857.39*voltage) * 0.54;
float tdsValuePpm = ecValue * 0.5; // Convert to ppm
Blynk.virtualWrite(V_TDS, tdsValuePpm); // Send to Blynk
Serial.print("TDS: "); // Print to Serial
Serial.print(tdsValuePpm);
Serial.println(" ppm");
}
void readAndSendTemp() {
sensors.requestTemperatures(); // Request temperature reading
float tempC = sensors.getTempCByIndex(0); // Get temperature in °C
Blynk.virtualWrite(V_TEMP, tempC); // Send to Blynk
Serial.print("Temperature: "); // Print to Serial
Serial.print(tempC);
Serial.println(" °C");
}
void readAndSendPH() {
float voltage = analogRead(phPin) * 3.3 / 4095.0; // Read and convert pH value
float phValue = ph.readPH(voltage, 16.52); // Calculate pH
Blynk.virtualWrite(V_PH, phValue); // Send to Blynk
Serial.print("pH: "); // Print to Serial
Serial.println(phValue);
}
void checkFloatSwitch() {
int floatState = digitalRead(floatSwitchPin); // Read float switch state
if (floatState == LOW) { // If water level is low
Blynk.virtualWrite(V_FLOAT_SWITCH, 1); // Send alert to Blynk
Blynk.virtualWrite(V_FLOAT_LED, 1); // Turn on indicator
} else { // If water level is normal
Blynk.virtualWrite(V_FLOAT_SWITCH, 0); // Send normal status
Blynk.virtualWrite(V_FLOAT_LED, 0); // Turn off indicator
}
}
// ===== BLYNK HANDLERS ===== //
BLYNK_WRITE(V_PUMP_SWITCH) { // System toggle handler
systemEnabled = param.asInt(); // Get switch state
if (systemEnabled) { // If turning on
pumpTimer = millis(); // Reset timers
aeratorTimer = millis();
digitalWrite(pumpPin, HIGH); // Turn pump on
pumpState = true;
ledcWrite(AERATOR_PWM_CHANNEL, 0); // Turn aerator off
aeratorState = false;
Serial.println("System activated"); // Notification
} else { // If turning off
digitalWrite(pumpPin, LOW); // Turn pump off
pumpState = false;
ledcWrite(AERATOR_PWM_CHANNEL, 0); // Turn aerator off
aeratorState = false;
Serial.println("System deactivated"); // Notification
}
}
One of the most problematic sensors was the pH meter. Since my sensor lacked specific documentation, working with it was quite challenging. To address this, I studied various articles and resources online and borrowed code from a website called Electronic Clinic, as their sensor was similar to mine. However, despite this, I was unable to use the code correctly.
As an alternative, I considered replacing the ESP32-C3 microcontroller with an Arduino, because the maximum input voltage for the ESP32-C3 is 3.3 V. For proper operation, I tried using a voltage divider resistor to step down 5 V to the allowable 3.3 V. Nevertheless, this did not solve the measurement range problem: instead of the expected 0–14 pH, the range was reduced to 5–12, and ultimately, the sensor stopped distinguishing acidic from alkaline environments.
System Integration¶
As part of the system integration week, I designed an enclosure to house the main components required for the operation of my hydroponic system. These include sensors for measuring the characteristics of the nutrient solution, the main control board, as well as the water and air pumps.
Removable module for input devices.
Below is the appearance of the assembled electronics after connecting all components and installing them in a specially designed case.
Bylnk Application¶
As I mentioned earlier, I used the Blynk application for remote control of the hydroponic system. A detailed guide for creating the application can be found in the Networking and Communications and Interface and Application Programming sections.
The final version of the application interface includes the following elements:
-
1 - Power button for turning the hydroponic system on and off.
-
2 - Liquid temperature indicator.
-
3 - Virtual LED indicators that light up when the required liquid level is reached.
-
4 - Dissolved minerals concentration indicator (in ppm).
-
5 - Graph showing changes in dissolved minerals levels with selectable time intervals: 15 minutes, 30 minutes, 1 hour, 3 hours, 6 hours, and 12 hours. The graph can also display real-time data.
-
6 - Real-time pH level indicator.
-
7 - Graph showing changes in pH levels with selectable time intervals: 15 minutes, 30 minutes, 1 hour, 3 hours, 6 hours, and 12 hours. The graph can also display real-time data.
After using the application for some time, I discovered a limitation of the free plan, which allows sending up to 30,000 data messages per month. Since I was constantly monitoring real-time data, the number of messages sent accumulated quickly, leading to a rapid exhaustion of the available limit. This limitation forced me to reconsider the monitoring mode and optimize the data update frequency for more efficient resource usage.
Assembly¶
The assembly process, starting from connecting all electronic components and ending with integrating the modules into a single functioning system, is shown in detail in the video. It demonstrates the sequence of actions, assembly features, and nuances of integrating various parts of the project, which helps to better understand the technical details and logic of the assembly.
BOM¶
Components | Price (USD) |
---|---|
ESP32C3 Seeed Studio XIAO BLE WIFI module | $ 4.70 |
PH meter | $ 13.51 |
TDS meter | $ 2.20 |
Тemperature sensor DS18B20 | $ 0.49 |
Water pump | $ 0.68 |
Aerator | $ 2.13 |
PVC universal tube 6 mm*5 meters (food grade hose) | $ 3 |
16 mm button with indicator, housing mounting / Locking | $ 4,66 |
Power connector 5.5x2.5mm socket | $ 2,19 |
PET-G plastic 2X | $ 28,76 |
12V 2A Universal power supply 5.5x2.5mm | $ 4,65 |
Water reservoir(Local shop) | $ 15,63 |
Total | $ 77,8 |
Conclusion¶
During the final project, I gained valuable experience in developing a modular hydroponic system, including stages such as 3D modeling, printing parts, designing and manufacturing the printed circuit board, and integrating electronic components. Working with the Blynk application allowed me to master remote control and real-time monitoring of the system.
Among the challenges I faced, working with the pH sensor stood out. The lack of precise documentation and the limited measurement range complicated the correct integration of the sensor into the system. Additionally, the free Blynk plan’s limitation on the number of data messages required optimizing the data update frequency.
Despite these difficulties, the project helped me better understand the interaction between hardware and software components, as well as the importance of thorough calibration and sensor testing to achieve accurate and stable results. In the future, I plan to continue improving the system, taking into account the lessons learned and recommendations.
Licensing¶
GROWZEN © 2025 by Zhirayr Ghukasyan is licensed under CC BY-NC-SA 4.0