Raspberry Pi auto water changer + ATO

Sam Rowe

Community Member
View Badges
Joined
Dec 10, 2017
Messages
38
Reaction score
47
Location
Plymouth
Rating - 0%
0   0   0
Hey everyone.

I've been having a play with a spare raspberry pi I have at home and want to automate doing water changes so I can have a 100l container for example and over the course of a week or so the system will do a small daily water change to help keep parameters stable and fairly constant.

I'm quite a noob when it comes to coding and have little experience but have a working python code that's written very similarly to C as I;ve made an auto water changer a few years ago with an Arduino until the chip blew and all pumps turned on messing all my parameters up and nearly causing a small flood. (it was down to the 5V going in as wasn't regulated and must have spiked blowing up the chip ;Facepalm)
I'm wondering if there are any guys on here that would be happy to help rewrite the code to be how I would want it.
I'm looking to have it set up in such a way that its possible to view on a web browser and change some settings relevant to container size, tank size, the percentage of weekly water change so that the system can calculate the required run times based on set pump flow etc.

At the moment I have the basic code set that will enable the system to be autonomous and all that would be required is to put the right amount of salt in the container and at the push of a button it opens a solenoid to fill the container from my RO filter, once the container is full closing the solenoid and proceeding to run an internal pump to mix the salt water solution for a set amount of time.
After the filling and mixing is complete it will run the sequence of pumps once a day at a defined time to complete the water change.
When the container is empty the system will stop being able to do water changes either until refilled or the option of entering a cleaning process to partially fill the container and run the mixing pump and then drain the tank back down ready for salt and refill.

I have included an ATO set fo code as I currently have a Reef-Pi setup from a thread made by @Ranjib but undertaking the water changes would fool the Reef-Pi into a low water state and cause it to start its ATO where how I have set my AWC to stop its ATO when the change is called.

I'm very basic to coding and the whole webpage/webserver I am very much going out of my depth.
I will post my code up on here for anyone to see and if anyone can help that would be amazing. I would like to possibly do the system in python as I would like to learn along the way ideally rather than just have someone rewrite my code so it works but I don't have any clue about it.

Thanks.
 
OP
OP
Sam Rowe

Sam Rowe

Community Member
View Badges
Joined
Dec 10, 2017
Messages
38
Reaction score
47
Location
Plymouth
Rating - 0%
0   0   0
The code I have so far is:

Code:
import RPi.GPIO as GPIO
import datetime
import time
import schedule

Var1 = 0 #variable to have system trigger mixing after filling container
Var2 = 0 #variable to lockout buttons to prevent premature program triggers while changing water etc
Var3 = 0 #variable to prevent ATO from topping up tank when perforing water change
CON = 5 #container on, time to wait to partial fill container to be able to clean
CLEAN = 5 #time to wait while container is cleaning
MIX = 5 #Time to pause to leave mixing pump running
wait = 5 #Dosing time run time ni seconds


now = time.strftime("%H:%M")
go = "18:00" #Water change trigger time, program prompt for trigger time at start
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

GPIO.setup(5, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(6, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(13, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(17, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(18, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(19, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(26, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(14, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(15, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(16, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(21, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_UP)
#Define raspberry pi input pin names
SW1 = 14 #Go button
SW2 = 15 #Dosing pump manual on
SW3 = 16 #Cleaning cycle start
Float1 = 23 #Float to detect container full
Float2 = 24 #Float to detect container empty
Float3 = 21 #Float for ATO
#Define raspberry pi output pin names
Sol1 = 17 #Solenoid valve for filling container
Sol2 = 18 #Solenoid valve for controlling emptying container
Sol3 = 13 #Solenoid valve for topping up tank (ATO)
MixP = 26 #Pump for mixing salt water in container and to clean tank)
EmPump = 19 #Pump on line to empty container (Used in cleaning cycle)
Dos1 = 5 #Pump IN Salt Water
Dos2 = 6 #Pump OUT Tank Water

#go = input("Insert dosing trigger time: ")
print("Time has been set to " +str(go))

def Change():
    if Var1 == 0 and Var2 == 1:
        Var3 = 1
    print("Starting water change")
        GPIO.output(6, GPIO.LOW)
    print("Removing aquarium water")
        time.sleep(wait)
        GPIO.output(6, GPIO.HIGH)
    print("Done!")
        time.sleep(2)
        GPIO.output(5, GPIO.LOW)
    print("Topping up with salted water")
        time.sleep(wait)
        GPIO.output(5, GPIO.HIGH)
    print("Done!")
    Var3 = 0
        print("Water change complete - same again tomorrow :-) ")

schedule.every().day.at(go).do(Change)

while True:

    schedule.run_pending()
    time.sleep(0.5)

#Purge in line
    #Manually Run Dosing in pump to purge line
    if (GPIO.input(15) == False):
        GPIO.output(5, GPIO.LOW)
        print("Manual pump on")
        time.sleep(1)
    else:
        GPIO.output(5, GPIO.HIGH)

#Fill process
    #Start process pushing SW1 to trigger container filling
    if (GPIO.input(14) == False and Var2 == 0): #Switch input to start filling Var2 = 0 to prevent button being pushed at later date while doing scheduled water changes
        GPIO.output(17, GPIO.LOW)
        print("In Solenoid Opened Waiting until full")
        Var1 = 1 #Variable to trigger solenoid off when tank full
        time.sleep(1)

#Mixing process
    #Once container full triggered by Float1 solenoid closed and pixing pump turned on
    if Var1 == 1 and GPIO.input(23) == True:
        GPIO.output(17, GPIO.HIGH)
        print("In solenoid closed proceeding to mix")
        time.sleep(3)
        GPIO.output(26, GPIO.LOW)
        print("Mixing Started")
        time.sleep(MIX)
        GPIO.output(26, GPIO.HIGH)
        print("Mixing Complete")
        Var1 = 0 #Lockout
        Var2 = 1 #Allow system to change
        print(Var1 , Var2)
        print(go)
        print(now)

#Empty container releasing lockout preventing accidental fill trigger call before tank is fully empty
    if GPIO.input(24) == False and Var2 == 1:
        print("Container Empty Press Button 3 (16) to trigger cleaning")
        print("Or put in more salt and trigger filling again (14)")
        print("Releasing Lockout")
        Var2 = 0

#Cleaning process to give container and clean and drain down
    if GPIO.input(16) == False and Var2 == 0:
        GPIO.output(17, GPIO.LOW)
        print("Part filling contrainer to clean")
        time.sleep(CON)
        GPIO.output(17, GPIO.HIGH)
        print("Container part filled for cleaning")
    time.sleep(0.5)
        GPIO.output(26, GPIO.LOW)
    print("Mixing pump on to clean")
        time.sleep(CLEAN)
        print("Container cleaned emptying")
        GPIO.output(18, GPIO.LOW)
        GPIO.output(19, GPIO.LOW)
        time.sleep(CON-3)
        GPIO.output(26, GPIO.HIGH)
        print("Mix pump turned off waiting for container to empty")
        time.sleep(CON)
        GPIO.output(18, GPIO.HIGH)
        GPIO.output(19, GPIO.HIGH)
        print("Container empty ready for salt and refill")

#ATO to top up evaporated Water
    if GPIO.input(21) == False and Var3 == 0:
    print("Tank Water Low")
    print("Topping up")
    GPIO.output(13, GPIO.LOW)
    else:
    GPIO.output(13, GPIO.HIGH)

I do have some bits commented out as when testing I was calling for the time to run the water change sequence.

This code is most likely very basic and crappy but as I said before I'm and total noob and only have very basic coding knowledge.
 
OP
OP
Sam Rowe

Sam Rowe

Community Member
View Badges
Joined
Dec 10, 2017
Messages
38
Reaction score
47
Location
Plymouth
Rating - 0%
0   0   0
Already have a running reef-pi. Not liking to have it running dosing pumps and not built to do what I want to do. With the code I have written all that would be needed is to put the right amount of salt in the container and then just push the button for it to go. It will fill the container with RO as it’s directly plumbed to my filter, once full will run a pump inside for a while to then follow on to undertake water changes every day. Until the container is empty. When empty it will allow the option to either run a clean cycle of the container or put in more salt and restart the process.

I want to build it to have a web interface to allow for it to be customised and if others wish to build a setup and use the code it’s all here for use. I just don’t have the knowledge of python to get a web server running to be able to customise the settings and see feedback of for example when the ato last triggered etc.
I have found tutorials on YouTube about using flask as a web server and will continue to look into it but was wondering if anyone on here would be happy to assist.
 
OP
OP
Sam Rowe

Sam Rowe

Community Member
View Badges
Joined
Dec 10, 2017
Messages
38
Reaction score
47
Location
Plymouth
Rating - 0%
0   0   0
Been having a bit of a play with the system and currently have it running on a 30l container which has worked fairly well although has highlighted some issues that I have addressed and will be updating the python script this week.
I’ve also got an e paper display that I’ve managed to get working although in general online there isn’t a great deal of info in how to get them working with a raspberry pi.
It’s a bit basic but updates relevant to what the unit is doing or when the top up last ran or the changer sequence.
I’m happy with my progress although would still like to have it working through a browser to be able to update in real-time but still can’t figure out how to make this happen.

This is a picture of the display running on my raspberry pi that I’m using to debug the code to ensure the display updates properly and getting the text positions in the right place.

50FEC96B-6F93-4B54-8E96-864B7A24FC66.jpeg
 

Ranjib

7500 Club Member
View Badges
Joined
Apr 16, 2016
Messages
9,843
Reaction score
17,056
Location
Pleasant Hill, Concord
Rating - 0%
0   0   0
The code I have so far is:

Code:
import RPi.GPIO as GPIO
import datetime
import time
import schedule

Var1 = 0 #variable to have system trigger mixing after filling container
Var2 = 0 #variable to lockout buttons to prevent premature program triggers while changing water etc
Var3 = 0 #variable to prevent ATO from topping up tank when perforing water change
CON = 5 #container on, time to wait to partial fill container to be able to clean
CLEAN = 5 #time to wait while container is cleaning
MIX = 5 #Time to pause to leave mixing pump running
wait = 5 #Dosing time run time ni seconds


now = time.strftime("%H:%M")
go = "18:00" #Water change trigger time, program prompt for trigger time at start
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

GPIO.setup(5, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(6, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(13, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(17, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(18, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(19, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(26, GPIO.OUT, initial = GPIO.HIGH)
GPIO.setup(14, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(15, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(16, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(21, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_UP)
#Define raspberry pi input pin names
SW1 = 14 #Go button
SW2 = 15 #Dosing pump manual on
SW3 = 16 #Cleaning cycle start
Float1 = 23 #Float to detect container full
Float2 = 24 #Float to detect container empty
Float3 = 21 #Float for ATO
#Define raspberry pi output pin names
Sol1 = 17 #Solenoid valve for filling container
Sol2 = 18 #Solenoid valve for controlling emptying container
Sol3 = 13 #Solenoid valve for topping up tank (ATO)
MixP = 26 #Pump for mixing salt water in container and to clean tank)
EmPump = 19 #Pump on line to empty container (Used in cleaning cycle)
Dos1 = 5 #Pump IN Salt Water
Dos2 = 6 #Pump OUT Tank Water

#go = input("Insert dosing trigger time: ")
print("Time has been set to " +str(go))

def Change():
    if Var1 == 0 and Var2 == 1:
        Var3 = 1
    print("Starting water change")
        GPIO.output(6, GPIO.LOW)
    print("Removing aquarium water")
        time.sleep(wait)
        GPIO.output(6, GPIO.HIGH)
    print("Done!")
        time.sleep(2)
        GPIO.output(5, GPIO.LOW)
    print("Topping up with salted water")
        time.sleep(wait)
        GPIO.output(5, GPIO.HIGH)
    print("Done!")
    Var3 = 0
        print("Water change complete - same again tomorrow :-) ")

schedule.every().day.at(go).do(Change)

while True:

    schedule.run_pending()
    time.sleep(0.5)

#Purge in line
    #Manually Run Dosing in pump to purge line
    if (GPIO.input(15) == False):
        GPIO.output(5, GPIO.LOW)
        print("Manual pump on")
        time.sleep(1)
    else:
        GPIO.output(5, GPIO.HIGH)

#Fill process
    #Start process pushing SW1 to trigger container filling
    if (GPIO.input(14) == False and Var2 == 0): #Switch input to start filling Var2 = 0 to prevent button being pushed at later date while doing scheduled water changes
        GPIO.output(17, GPIO.LOW)
        print("In Solenoid Opened Waiting until full")
        Var1 = 1 #Variable to trigger solenoid off when tank full
        time.sleep(1)

#Mixing process
    #Once container full triggered by Float1 solenoid closed and pixing pump turned on
    if Var1 == 1 and GPIO.input(23) == True:
        GPIO.output(17, GPIO.HIGH)
        print("In solenoid closed proceeding to mix")
        time.sleep(3)
        GPIO.output(26, GPIO.LOW)
        print("Mixing Started")
        time.sleep(MIX)
        GPIO.output(26, GPIO.HIGH)
        print("Mixing Complete")
        Var1 = 0 #Lockout
        Var2 = 1 #Allow system to change
        print(Var1 , Var2)
        print(go)
        print(now)

#Empty container releasing lockout preventing accidental fill trigger call before tank is fully empty
    if GPIO.input(24) == False and Var2 == 1:
        print("Container Empty Press Button 3 (16) to trigger cleaning")
        print("Or put in more salt and trigger filling again (14)")
        print("Releasing Lockout")
        Var2 = 0

#Cleaning process to give container and clean and drain down
    if GPIO.input(16) == False and Var2 == 0:
        GPIO.output(17, GPIO.LOW)
        print("Part filling contrainer to clean")
        time.sleep(CON)
        GPIO.output(17, GPIO.HIGH)
        print("Container part filled for cleaning")
    time.sleep(0.5)
        GPIO.output(26, GPIO.LOW)
    print("Mixing pump on to clean")
        time.sleep(CLEAN)
        print("Container cleaned emptying")
        GPIO.output(18, GPIO.LOW)
        GPIO.output(19, GPIO.LOW)
        time.sleep(CON-3)
        GPIO.output(26, GPIO.HIGH)
        print("Mix pump turned off waiting for container to empty")
        time.sleep(CON)
        GPIO.output(18, GPIO.HIGH)
        GPIO.output(19, GPIO.HIGH)
        print("Container empty ready for salt and refill")

#ATO to top up evaporated Water
    if GPIO.input(21) == False and Var3 == 0:
    print("Tank Water Low")
    print("Topping up")
    GPIO.output(13, GPIO.LOW)
    else:
    GPIO.output(13, GPIO.HIGH)

I do have some bits commented out as when testing I was calling for the time to run the water change sequence.

This code is most likely very basic and crappy but as I said before I'm and total noob and only have very basic coding knowledge.
This is awesome. You have a long way to go if you want to take this to the state that want (customization and web interface). I'll recommend starting a github repo where folks can contribute code (I am happy to chip in), and start with a requirement document enlisting the steps (logic), then enlist the minium hardware required (like container, level switches, pumps). This will simplify the coding process as others will know what the code assume.
Webserver will involve some html/css/javascript work on the frontend and some flask type of framework (or raw http library) on the backend (in python)
godspeed
 

Ranjib

7500 Club Member
View Badges
Joined
Apr 16, 2016
Messages
9,843
Reaction score
17,056
Location
Pleasant Hill, Concord
Rating - 0%
0   0   0
Already have a running reef-pi. Not liking to have it running dosing pumps and not built to do what I want to do. With the code I have written all that would be needed is to put the right amount of salt in the container and then just push the button for it to go. It will fill the container with RO as it’s directly plumbed to my filter, once full will run a pump inside for a while to then follow on to undertake water changes every day. Until the container is empty. When empty it will allow the option to either run a clean cycle of the container or put in more salt and restart the process.

I want to build it to have a web interface to allow for it to be customised and if others wish to build a setup and use the code it’s all here for use. I just don’t have the knowledge of python to get a web server running to be able to customise the settings and see feedback of for example when the ato last triggered etc.
I have found tutorials on YouTube about using flask as a web server and will continue to look into it but was wondering if anyone on here would be happy to assist.
If all you want is a button, then I would say you don't even need a web interface, you can directly use few LEDs to indicate status and push buttons to triggers things. That will reduce code complexity and other failure modes.

regarding reef-pi, I plan to add macro features as part of 2.0, I expect that to solve some of similar use cases
 
OP
OP
Sam Rowe

Sam Rowe

Community Member
View Badges
Joined
Dec 10, 2017
Messages
38
Reaction score
47
Location
Plymouth
Rating - 0%
0   0   0
If all you want is a button, then I would say you don't even need a web interface, you can directly use few LEDs to indicate status and push buttons to triggers things. That will reduce code complexity and other failure modes.

regarding reef-pi, I plan to add macro features as part of 2.0, I expect that to solve some of similar use cases
Thanks for the feedback Ranjib
I’ve got the system running to a capacity and although for myself once running there’s no real need for myself to have lots of the adjustments to make using a browser it would be nice as can update the percentages of the water change without having to stop the code which how it currently is would mess up and would require any salt water in the container to be dumped.

I’ll look into the github and things as a way for others to assist in adapting the code to have some more of the features that I would like to implement but don’t have the knowledge to.
 

SDchris

Active Member
View Badges
Joined
Mar 3, 2015
Messages
123
Reaction score
164
Location
Sydney
Rating - 0%
0   0   0
Nice start Sam.
A simple alternative for a UI is to use Node-Red as the front end with your python script as the back end. Then communicate with each other via mqtt or sockets.

Chris
 
OP
OP
Sam Rowe

Sam Rowe

Community Member
View Badges
Joined
Dec 10, 2017
Messages
38
Reaction score
47
Location
Plymouth
Rating - 0%
0   0   0
Nice start Sam.
A simple alternative for a UI is to use Node-Red as the front end with your python script as the back end. Then communicate with each other via mqtt or sockets.

Chris
Thanks for the info Chris I’ll have a look into it. Is it slightly noob friendly or at least not a massive learning curve. Being a self employed electrician doesn’t give me heaps of spare time to learning loads currently as I’m a fairly new business but I like to try and further my knowledge when I get a chance.
 

Robert Fowler

Community Member
View Badges
Joined
Mar 12, 2016
Messages
44
Reaction score
15
Rating - 0%
0   0   0
The Pi project has really taken off in the last couple years might have to try to put one together myself...
 

SDchris

Active Member
View Badges
Joined
Mar 3, 2015
Messages
123
Reaction score
164
Location
Sydney
Rating - 0%
0   0   0
Is it slightly noob friendly or at least not a massive learning curve
Hey Sam,
It will be the easiest way of doing it. Node-Red was developed so people with little programing experience could connect devices to the IOT. But like everything there is a small learning curve. This way allows you to invest the least amount of time setting up a UI while allowing you to invest most of your time learning python.
Chris
 
OP
OP
Sam Rowe

Sam Rowe

Community Member
View Badges
Joined
Dec 10, 2017
Messages
38
Reaction score
47
Location
Plymouth
Rating - 0%
0   0   0
Hey Sam,
It will be the easiest way of doing it. Node-Red was developed so people with little programing experience could connect devices to the IOT. But like everything there is a small learning curve. This way allows you to invest the least amount of time setting up a UI while allowing you to invest most of your time learning python.
Chris
I’ll look into this tomorrow as finally a day off haha. Would be cool to get a gui running on it. I’m up for a bit of a learning curve, keeps things interesting.
 
OP
OP
Sam Rowe

Sam Rowe

Community Member
View Badges
Joined
Dec 10, 2017
Messages
38
Reaction score
47
Location
Plymouth
Rating - 0%
0   0   0
I have made some adjustments to the code relevant to letting the system still top up the tank while the container is being filled. Need to do the same for the mixing as having a sleep call for 3 hours will be a bit much as won’t let the rest of the system run.

I have ran into a bit of an issue and do t quite understand why.
Without the display and just running the script I was able to add the path to the local auto start file so the script would run on boot and did so without any issues.
Since configuring and installing for the epaper display if I do the same of having the script run from the Auto start file it doesn’t.
Having cronlog setup as tried another way to autorun on boot and it comes back saying that schedule module isn’t found. Yet if I from the terminal manually start my script it runs with no issue what so ever?
Any pointers as to what I’m not seeing?
 
OP
OP
Sam Rowe

Sam Rowe

Community Member
View Badges
Joined
Dec 10, 2017
Messages
38
Reaction score
47
Location
Plymouth
Rating - 0%
0   0   0
Can you post what you added to the crontab file?

Chris
This is what I added to the crontab file

Code:
@reboot python /home/pi/Water/Changer.py &

Its strange if in terminal I cd into my directory Water and then run 'python Changer.py' it runs without any problems, If I'm out of the Water directory and run at 'python /home/pi/Water/Changer.py' it throws up the statement
Code:
Traceback (most recent call last):
  File "/home/pi/Water/Changer.py", line 83, in <module>
    paper.Initial()
  File "/home/pi/Water/epaper.py", line 30, in Initial
    frame_black = epd.get_frame_buffer(Image.open('black1.bmp'))
  File "/usr/lib/python2.7/dist-packages/PIL/Image.py", line 2312, in open
    fp = builtins.open(filename, "rb")
IOError: [Errno 2] No such file or directory: 'black1.bmp'
but if I run 'sudo python /home/pi/Water/Changer.py' I get
Code:
Traceback (most recent call last):
  File "/home/pi/Water/Changer.py", line 5, in <module>
    import schedule
ImportError: No module named schedule

I can't figure out whats wrong?
 
OP
OP
Sam Rowe

Sam Rowe

Community Member
View Badges
Joined
Dec 10, 2017
Messages
38
Reaction score
47
Location
Plymouth
Rating - 0%
0   0   0
OP
OP
Sam Rowe

Sam Rowe

Community Member
View Badges
Joined
Dec 10, 2017
Messages
38
Reaction score
47
Location
Plymouth
Rating - 0%
0   0   0
Wow this year has gone pretty fast, I've been way too busy with work and after having the water changer script working it kind of took a backseat in my list of priorities.
Some recent bad news being I managed to get salt water on the Pi and bust it. Having some time off work over the christmas I have finally had the time to look at rebuilding it and have been experimenting with getting it to work with a flask webserver.
I am in the process of adding what I have to a GitHub repository and will add links shortly, any help from anyone regarding developing this would be much appreciated as I have a huge learning curve trying to get this working with the flask web server as I am having to re-write my code so that it functions properly
 

Being sticky and staying connected: Have you used any reef-safe glue?

  • I have used reef safe glue.

    Votes: 108 87.1%
  • I haven’t used reef safe glue, but plan to in the future.

    Votes: 8 6.5%
  • I have no interest in using reef safe glue.

    Votes: 5 4.0%
  • Other.

    Votes: 3 2.4%
Back
Top