Building an Advanced Reef Controller with Arduino Mega and NodeMCU
Maintaining a thriving reef aquarium requires precision and care. With the help of Arduino Mega 2560 and NodeMCU, we can automate many essential tasks, ensuring the perfect environment for marine life. This guide explains how to build a complete reef controller, including temperature regulation, lighting control, water level monitoring, and remote data visualization via a web interface.
This reef controller automates the following functions:
The Mega handles sensor inputs, relay outputs, and feeder control. It periodically sends data to the NodeMCU via Serial communication. Key libraries used include:
NodeMCU receives data from the Mega and hosts a simple web server to display temperature, water levels, and other parameters. The server uses HTML and JavaScript for real-time updates via AJAX.
This reef controller is an excellent project for enthusiasts looking to automate their aquarium while learning about microcontroller programming and IoT. With some initial effort, you can ensure a stable and thriving environment for your aquatic life!
Maintaining a thriving reef aquarium requires precision and care. With the help of Arduino Mega 2560 and NodeMCU, we can automate many essential tasks, ensuring the perfect environment for marine life. This guide explains how to build a complete reef controller, including temperature regulation, lighting control, water level monitoring, and remote data visualization via a web interface.
Overview of the System
This reef controller automates the following functions:
- Temperature Control: Monitors water temperature using a DS18B20 sensor and controls a heater via a relay.
- Lighting Management: Automates aquarium lights with gradual brightness adjustments.
- Water Level Monitoring: Detects water levels using float switches.
- Leak Detection: Monitors for potential leaks using water sensors.
- Data Visualization: Displays real-time data (temperature, water levels, and more) on a web dashboard hosted by NodeMCU.
Component List
Microcontrollers
- Arduino Mega 2560
- NodeMCU (ESP8266)
Sensors and Modules
- virtuabotixRTC (DS1302 Real-Time Clock)
- DS18B20 Temperature Sensor
- Adafruit TCS34725 Color Sensor
- 3-Channel Relay Module
- Leak Sensors (2 units)
- Water Level Sensors (2 units)
Actuators
- Servo Motor (for feeder)
Other Components
- Jumper Wires
- Breadboard (optional for prototyping)
- Resistors (e.g., 10kΩ for pull-ups)
- Power Supplies (5V and 12V, depending on components)
Hardware Connections
Arduino Mega 2560 Connections
- virtuabotixRTC (DS1302):
- CLK (Clock): D6
- DAT (Data): D7
- RST (Reset): D8
- VCC: 5V
- GND: GND
- DS18B20 Temperature Sensor:
- Data Pin: D3 (with a 4.7kΩ pull-up resistor to 5V)
- VCC: 5V
- GND: GND
- Adafruit TCS34725 Color Sensor:
- SCL: SCL (Pin 21)
- SDA: SDA (Pin 20)
- VIN: 5V
- GND: GND
- Relay Module:
- Relay 1 (Heater): D22
- Relay 2 (Light): D23
- Relay 3 (Return Pump): D24
- Leak Sensors:
- Sensor 1 Signal: D4
- Sensor 2 Signal: D5
- VCC: 5V
- GND: GND
- Water Level Sensors:
- Sensor 1 Signal: D11
- Sensor 2 Signal: D12
- VCC: 5V
- GND: GND
- Servo Motor (Feeder):
- Signal: D32
- VCC: 5V
- GND: GND
NodeMCU Connections
- WiFi Communication: NodeMCU connects to the Arduino Mega via UART for data exchange.
- Power: Powered via USB or a 5V source.
- Web Server: Hosts a web dashboard for real-time data display.
Software Setup
Arduino Mega Code
The Mega handles sensor inputs, relay outputs, and feeder control. It periodically sends data to the NodeMCU via Serial communication. Key libraries used include:
- virtuabotixRTC for RTC module
- DallasTemperature and OneWire for DS18B20
- Adafruit_TCS34725 for color sensor
Code:
// Arduino Mega 2560 Code
#include <Wire.h>
#include <RTClib.h>
#include <Servo.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Adafruit_TCS34725.h>
// RTC Configuration
RTC_DS1307 rtc;
// DS18B20 Temperature Sensor Configuration
#define ONE_WIRE_BUS 3
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// Color Sensor (TCS34725)
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_600MS, TCS34725_GAIN_1X);
// PWM Pins for Lighting
#define DAYLIGHT_PIN 9
#define MOONLIGHT_PIN 10
// Leak Sensors
#define LEAK_SENSOR_1 4
#define LEAK_SENSOR_2 5
// Water Level Sensors
#define WATER_LEVEL_1 11
#define WATER_LEVEL_2 12
// Servo (Feeder)
#define SERVO_PIN 32
Servo feederServo;
// Relay Pins for Pumps
#define RETURN_PUMP_PIN 22
#define HEATER_PIN 23
// Timing Variables
unsigned long lastUpdate = 0;
const unsigned long updateInterval = 1000; // 1 second
// Helper Functions for Lighting Control
float sineWaveBrightness(float t, float startTime, float endTime) {
if (t < startTime || t > endTime) return 0;
float phase = (t - startTime) / (endTime - startTime) * 3.14159;
return sin(phase) * 255;
}
void setup() {
Serial.begin(9600); // For UART Communication with NodeMCU
// Initialize RTC
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
if (!rtc.isrunning()) {
Serial.println("RTC is NOT running, setting the time...");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // Set RTC to compile time
}
// Initialize Sensors
sensors.begin();
tcs.begin();
// Initialize Pins
pinMode(DAYLIGHT_PIN, OUTPUT);
pinMode(MOONLIGHT_PIN, OUTPUT);
pinMode(LEAK_SENSOR_1, INPUT);
pinMode(LEAK_SENSOR_2, INPUT);
pinMode(WATER_LEVEL_1, INPUT);
pinMode(WATER_LEVEL_2, INPUT);
pinMode(RETURN_PUMP_PIN, OUTPUT);
pinMode(HEATER_PIN, OUTPUT);
digitalWrite(RETURN_PUMP_PIN, LOW);
digitalWrite(HEATER_PIN, LOW);
// Initialize Servo
feederServo.attach(SERVO_PIN);
feederServo.write(0); // Default position
}
void loop() {
unsigned long currentMillis = millis();
// Get current time from RTC
DateTime now = rtc.now();
int hr = now.hour();
int min = now.minute();
float hour = hr + min / 60.0; // Convert to a float for sine wave calculation
// Lighting Control
float daylightBrightness = sineWaveBrightness(hour, 7, 9) + sineWaveBrightness(hour, 17, 18);
analogWrite(DAYLIGHT_PIN, daylightBrightness);
if (hour >= 18 || hour < 6) {
analogWrite(MOONLIGHT_PIN, 50); // Low moonlight brightness
} else {
analogWrite(MOONLIGHT_PIN, 0);
}
// Sensor Monitoring and Actuator Control
if (currentMillis - lastUpdate >= updateInterval) {
lastUpdate = currentMillis;
// Temperature Sensor
sensors.requestTemperatures();
float temperature = sensors.getTempCByIndex(0);
Serial.print("Temperature: ");
Serial.println(temperature);
// Leak Sensors
bool leak1 = digitalRead(LEAK_SENSOR_1);
bool leak2 = digitalRead(LEAK_SENSOR_2);
Serial.print("Leak Sensor 1: ");
Serial.println(leak1 ? "No Leak" : "Leak Detected");
Serial.print("Leak Sensor 2: ");
Serial.println(leak2 ? "No Leak" : "Leak Detected");
// Water Level Sensors
bool level1 = digitalRead(WATER_LEVEL_1);
bool level2 = digitalRead(WATER_LEVEL_2);
Serial.print("Water Level 1: ");
Serial.println(level1 ? "Normal" : "Low");
Serial.print("Water Level 2: ");
Serial.println(level2 ? "Normal" : "Low");
// Return Pump Control
digitalWrite(RETURN_PUMP_PIN, level1 ? HIGH : LOW);
// Heater Control
if (temperature < 25.0) { // Example threshold
digitalWrite(HEATER_PIN, HIGH);
} else {
digitalWrite(HEATER_PIN, LOW);
}
// Communicate data to NodeMCU
Serial.print("DATA:");
Serial.print(temperature);
Serial.print(",");
Serial.print(leak1);
Serial.print(",");
Serial.print(leak2);
Serial.print(",");
Serial.print(level1);
Serial.print(",");
Serial.println(level2);
}
}
NodeMCU Code
NodeMCU receives data from the Mega and hosts a simple web server to display temperature, water levels, and other parameters. The server uses HTML and JavaScript for real-time updates via AJAX.
Code:
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <DHT.h>
// WiFi Credentials
const char *ssid = "Your_SSID";
const char *password = "Your_PASSWORD";
// DHT Sensor
#define DHTPIN D4 // GPIO pin where the DHT sensor is connected
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// Relay Pins
#define HEATER_PIN D1
#define LIGHT_PIN D2
#define RETURN_PUMP_PIN D3
// Web server on port 80
ESP8266WebServer server(80);
void setup() {
Serial.begin(115200);
dht.begin();
// Initialize relays
pinMode(HEATER_PIN, OUTPUT);
pinMode(LIGHT_PIN, OUTPUT);
pinMode(RETURN_PUMP_PIN, OUTPUT);
digitalWrite(HEATER_PIN, LOW);
digitalWrite(LIGHT_PIN, LOW);
digitalWrite(RETURN_PUMP_PIN, LOW);
// Connect to WiFi
Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println(".");
}
Serial.println("WiFi connected.");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Define server routes
server.on("/", handleRoot);
server.on("/api/data", handleApiData);
server.on("/api/control", handleControl);
server.begin();
Serial.println("HTTP server started.");
}
void loop() {
server.handleClient();
}
// Serve HTML page
void handleRoot() {
String html = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<title>Reef Controller</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; }
.control { margin: 20px; }
button { padding: 10px 20px; font-size: 16px; cursor: pointer; }
</style>
</head>
<body>
<h1>Reef Controller</h1>
<div id="temperature">Loading temperature...</div>
<div id="humidity">Loading humidity...</div>
<div class="control">
<h3>Control Panel</h3>
<button onclick="sendCommand('heater', 1)">Turn Heater ON</button>
<button onclick="sendCommand('heater', 0)">Turn Heater OFF</button><br><br>
<button onclick="sendCommand('light', 1)">Turn Light ON</button>
<button onclick="sendCommand('light', 0)">Turn Light OFF</button><br><br>
<button onclick="sendCommand('pump', 1)">Turn Pump ON</button>
<button onclick="sendCommand('pump', 0)">Turn Pump OFF</button>
</div>
<script>
async function fetchData() {
const response = await fetch('/api/data');
const data = await response.json();
document.getElementById('temperature').innerText = `Temperature: ${data.temperature} °C`;
document.getElementById('humidity').innerText = `Humidity: ${data.humidity} %`;
}
async function sendCommand(device, state) {
const response = await fetch(`/api/control?device=${device}&state=${state}`);
const result = await response.text();
alert(result);
}
setInterval(fetchData, 5000); // Refresh data every 5 seconds
fetchData(); // Initial fetch
</script>
</body>
</html>
)rawliteral";
server.send(200, "text/html", html);
}
// API to send sensor data
void handleApiData() {
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
String json = "{\"temperature\": " + String(temperature) + ", \"humidity\": " + String(humidity) + "}";
server.send(200, "application/json", json);
}
// API to control relays
void handleControl() {
String device = server.arg("device");
int state = server.arg("state").toInt();
if (device == "heater") {
digitalWrite(HEATER_PIN, state);
server.send(200, "text/plain", "Heater control successful.");
} else if (device == "light") {
digitalWrite(LIGHT_PIN, state);
server.send(200, "text/plain", "Light control successful.");
} else if (device == "pump") {
digitalWrite(RETURN_PUMP_PIN, state);
server.send(200, "text/plain", "Pump control successful.");
} else {
server.send(400, "text/plain", "Invalid device.");
}
}
Building the System
- Hardware Assembly:
- Connect all components to the Arduino Mega and NodeMCU according to the pin connections listed above.
- Ensure all grounds (GND) are connected to a common point.
- Use relays to control high-power components (heater, lights, pump).
- Software Upload:
- Upload the Arduino Mega code to the Mega 2560 using the Arduino IDE.
- Upload the NodeMCU code to the ESP8266 using the Arduino IDE or another compatible uploader.
- Powering the System:
- Use a 5V power supply for the Arduino Mega and components.
- Ensure sufficient power for relays and servo motors by using an external power source if required.
- Testing:
- Verify each sensor’s functionality (temperature, water level, and leak sensors).
- Check the operation of relays (turning heater, lights, and pump on/off).
- Access the NodeMCU web dashboard via its IP address and confirm real-time data updates.
How It Works
- Real-Time Monitoring: The Mega collects data from sensors every second and processes control signals for relays and servos.
- Data Transmission: Processed data is sent to NodeMCU over Serial communication.
- Web Dashboard: NodeMCU hosts a web server, providing a real-time view of the aquarium's status, accessible on any WiFi-enabled device.
- Automation: Relays and servos are triggered based on sensor readings, ensuring the aquarium's environment stays within ideal conditions.
Future Enhancements
- Water Parameter Testing: Add solenoid valves and sensors for testing parameters like alkalinity and nitrate.
- Mobile App: Extend the web interface to a dedicated mobile application for remote control and notifications.
- Camera Integration: Include an IP camera for live monitoring of the aquarium.
This reef controller is an excellent project for enthusiasts looking to automate their aquarium while learning about microcontroller programming and IoT. With some initial effort, you can ensure a stable and thriving environment for your aquatic life!