Arduino based Aquarium Automation System


  1. What: This is a Aquarium automation experience using Arduino and a Flask Web App as a Backend.
  2. Why: To monitor and automate a Fish Aquarium.
  3. How: Using the Arduino to read the sensors (ldr, temperature and umidity) and to control the actuators (heater and step motor).
  4. Where: At home in my personal Aquarium.
  5. Who: Me and my son.

Project History

Version 1

The first version I was using a low cost IoT device based on the ESP-8266 module which can be programmed with the Arduino IDE. The main reason to using this is to make Json request from my Web App to handle the food feed time and to manage the time to turn ON/OFF the light and Filter Bomb. The WebApp is very simple. From Arduino point of view we do a request with a URL and parser the Json object to split the information.


Control box
Helicoidal screw and dc motor
Food dispenser

First I send a request to the web app with the luminosity intensity from the LDR and after how I handle the Json response.

String url = "" + statusLido;
HTTPClient http;

Serial.print("Requested Link: ");

http.begin(client, url);
int httpCode = http.GET();
String payload = http.getString();
DynamicJsonDocument doc(1024);
deserializeJson(doc, payload);
JsonObject obj =;
String status = obj["status"];

StringSplitter *splitter = new StringSplitter(status, ',', 7);
String log_time = splitter->getItemAtIndex(0);
String numero_voltas = splitter->getItemAtIndex(2);
String bomb_time_status = splitter->getItemAtIndex(3);
String food_time_status = splitter->getItemAtIndex(4);
String feeded_times = splitter->getItemAtIndex(5);

From the Web App point of view, I get the LDR readed intensity of light to store in the log file together with log time, number of step motor turns, bomb time status, food time status and the number of food feeded times.

@app.route('/get_resume', methods=['GET', 'POST'])
def get_resume():

if request.args.get('ldr'):
ldr = request.args.get('ldr')
numero_voltas = settings.numero_voltas

today =
log_time = datetime.datetime.strftime(today, '%Y-%m-%d_%H:%M:%S')

food_time_status, start_date, end_date, now, food_time_count = check_food_time_func()
# print(food_time_status, start_date, end_date, now, food_time_count)
feeded_times = todays_food_func()

bomb_time_status, hour_now = get_bomb_time_func()

to_file = log_time + ',' + str(ldr) + ',' + str(numero_voltas) + ',' + str(bomb_time_status) + ',' + str(food_time_status) + ',' + str(feeded_times)
if bomb_time_status == 'yes':
with open('static/log.csv', 'a') as f:
return jsonify(status=to_file)

return jsonify(status='failed')

The food time status is handled by another function called check_food_time_func. This function basicaly read the food log to check how many times the fishes were feeded at this day and check the interval I defined in start_hour and end_hour.

def check_food_time_func():

df = pd.read_csv('static/dispenser.csv')
now =
date, time = get_today()

start_hour = ['06', '10', '14', '18']
end_hour = ['07', '11', '15', '19']

count = len(list(df.loc[df['date'] == date].date))
for i in range(4):
start_date = date + ' ' + start_hour[i] + ':00:00'
end_date = date + ' ' + end_hour[i] + ':00:00'
# print(start_date, now, end_date)
start = datetime.datetime.strptime(start_date, '%Y-%m-%d %H:%M:%S')
end = datetime.datetime.strptime(end_date, '%Y-%m-%d %H:%M:%S')
if now > start and now < end and count <= i:
return 'yes', start_date, end_date, now, count

return 'no', start_date, end_date, now, count

The Food dispenser was a particular project too. First I tried the cheaper version building a helicoidal screw with electrical wire, which worked well for extruded type of food but not for flakes. The second attempt was a hand made helicoidal screw using pieces of washes put together with a electric soldering iron which doesn't worked well. The third attempt was a 16mm Wood screw that I cutted to fit my needs. That doesn't worked well with flakes too. Note, I tried those types of screw only with 2 types of motors, a Step Motor and a 3V DC Motor. I didn't want try another types of motors and using just what I already have.

electrical wire
hand made screw with washes
A piece of 16mm wood screw
3D print design

The pictures bellow is showing the Sketchup 3D design I made to help in the process. And after that the pictures I took from the result.

Sketchup design

Control box
Helicoidal screw and dc motor
Food dispenser

Version 2

After been exasperated with the helicoidal screw, in the version 2, I decided leave this option and try a simpler solution. I attach the food recipient to the dc motor with a hole in it. That solution worked weel and was stable but the food amount dispended to the fishes was difficult to measure. I attribute this to the 3 main reasons:

  1. the size of the hole.
  2. umidity in the flakes.
  3. amount the food inside the recipient.


Here you can see very clearly the simplicity of the hardware. The Nodemcu, relay driver and the PWM to the motor. It was important to use the PWM because we can choose the velocity of the motor keeping the motor torque.

Electric and electronic parts
Control box
New food dispenser

Sketchup design

Control box
Helicoidal screw and dc motor
Food dispenser

To make sure the number of motor's turns I implemented a switch attached on the other side of the motor axi, as you can see in the picture bellow.

Version 3

In this version I tried a different approach:

  1. Arduino + Nodemcu set up.
  2. Focus on the system reliability.
  3. Care less about aesthetics.

Here I am using a Arduino to read sensors and switch the light, bomb and others devices I want in the future, led indicators and Step motor control. The Nodemcu I kept to manage the time food and bomb and light time. The communicattion between Nodemcu and Arduino was made via Serial port. The leds have the purpose of indicate how many times the fishes were feeded. The others functions are the same from the older versions:

  • Manual feed button.
  • LDR to check the light intensity.


Nodemcu + Arduino
Removable Control box
Food dispenser separately
New food dispenser

In this version I could fix many points, such as:

  • Space to cable management.
  • Control box easily removable.
  • Step motor and food dispenser separately.
  • New food dispenser with amount of the food regulation.

Looks very ugly I know, but this is easy and fast way to get the final version, believe me.

Comercial Food dispenser

The food dispenser was based on the comercial Food dispenser automation available in the market (see picture bellow).

Arduino and Nodemcu delay() workaround solution

Now lets talk about the new code implementations. The Nodemcu have a different behavior with the delay() function. When the loop stop in some point for much time the Nodemcu reset the device. Instead using the delay() function I used the following approach:

const long interval = 60000;
long previousMillis = 0;

void setup(){
// your configuration

void loop(){
long currentMillis = millis();

if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;

// run the code

Basically speaking, we set a interval time, when the difference between the current time is greater than the previous time the Micro-controller runs the code. It works like a charm.

Version 4

In the Version 4 I decided keep the system off-line and working the code to do the job nicely. Basically talking we have the following steps:

This version is working very well. It is reliable, consistent and the fishes are happy as well. Could not be the best option for places with problems on Power supply, because this approach don't have memory. Once the Power supply is turned OFF the interval counting is lost.

To have a good turn ON/OFF time I have been monitoring the LDR value with the Arduino IDE Serial monitor in the morning (6 AM) and in the evening (7 PM). Doing this I could set a properly value to turn ON/OFF the filter and light as I wished and it is working with a few minutes of difference ( around 5 mins ). Of course this approach will depends on your location in the Globe :).

1. Import libraries
2. Variable and constant declaration
3. Setup
- PIN IN/OUT attribution
- Turn ON/OFF Filter and Light (LDR value dependent)
4. Loop
- reset check and food current time
- read manual feed button
- check time
- check LDR
- check status day/night

You can download the code here


In this picture you can see each part of the circuit.

  1. Step Motor
  2. ULN2003 driver
  3. Arduino
  4. LDR input
  5. 3 channel relay
  6. Manual feed button

Version 05 (running version)

For this version I bought a RTC module to fix the time better and to try the module for the first time. The RTClib does a real good job and make the code very easy to implement. First you need to set up the time and as the module has a battery to keep the memory ON, we do not have the problem we had in the previous version, when the Power supply shutdown cause lost of tracking time. The light and filter will turn ON/OFF the time you choose and your fishes will be happy to eat every day at the right time.


Nodemcu + Arduino
Removable Control box
Food dispenser separately
New food dispenser


Bellow you can check some piece of code to make the reading less tedious.

Only you need to do is set the time calling the rtc.adjust() function with the time you want. After uploading the code you need to comment this line and upload the code again, of course :).

void setup(){

rtc.adjust(DateTime(2020, 3, 10, 14, 12, 30));

After that you can get the date and time by just calling the rtc function as bellow.

void loop(){
// get the time
DateTime rtctime =;

// You can access the values calling the related function as you can see b
hour = rtctime.hour();
minute = rtctime.minute();
second = rtctime.second();
year = rtctime.year();
month = rtctime.month();
day =;


You can check a more RTC lib fuctions examples here:

New setup

For this version I decided make the aquarium and Control Box a different system in order to facilitate the Aquarium maintenance.

Another advantage to this approach is portability as I can change the Aquarium many times I want because the size of the Aquarium don't interfers in the Control Box.

As you can see in the pictures, I didn't buy the temperature sensor and the heater yet, and also I am using a home made relay setup instead a arduino module. Just beacuse I had the components here and I wanted to keep this project as cheaper as possible.

List of Materials

Here you can find the link for almost all the materials I have used in this project. You have an international supplier (Amazon) and 2 Brazillian suppliers ( Filipeflop and Bau da Eletronica). I don't have any financial relationship with the mentioned shops, I just wanted to show where you can find these hardwares.

Product name Amazon Filipeflop Bau da Eletronica
Arduino UNO link link link
RTC DS1307 link link link
Relay 4 channel link link link
Step motor 28BYJ-48/ULN2003 link link link
Arduino 9V power supply (comes with Arduino) link link link
5V/2A power supply link link link
wires/jumpers link link link
barrel connector link link -
3 terminal switches link link link
P2 connector male link link link
P2 connector female link link link

© Copyright 2019