Alright, alright I know what you thinking... Oh jeepers 😣 yet another raspberry watering tutorial with 4 lines of while loop... But hA! I will do it differently! I will make it "harder" on purpose! 😅
What about 🤔 somehow nice box, cam module for creating time lapse video AND web interface?
If you rlly want, something like this can be amazing project for learning basic electronics. Running linux on own HW, even learn little bit of soldering!
In this article I will describe my thought process, links and articles that helped me understand what is and how to use GPIO pins...
Table of Contents
Schematic and thought process
My idea was do something "fancy" but not too much, main reason was that I dont have any experiences with custom design like 3D printed casing.
MacGyver time! I chose an old box from my GPU as a case, and used the internal anti-shock foam to hold the components in place.
Final product just unwraped itself! Only thing I did before setting it into case was inform myself about GPIO pins and what and how I need to connect tham.
For this I chose to use online graphic tool Excalidraw...
And after few rectangles, lines and dream later I have basic schematic for my watering system...
Code review
Path of least resistance
best choice for Raspberry Pi is Python... Quick, simple, and many things like GPIO, Cam driver is build for us. Bonus? do web interface in Flask. Do you need some fetching? Do htmx! You dont even need htmx... Flask will do everything for you... Building this with something like next.js is just... overkill.. But you do you 😅
Main reason why I split watering code and flask code is that I wanna run frontend on my VPS.
After watering, Pi will send data about it, as time, photo taken to my VPS.
VPS will resize photo, create new time lapse video, add record into db and serve all of it in frontend...
Let's write controller class for somehow manageable GPIO control..
First we define how we wanna let our code know what GPIO pin we want to control.
We have 2 options, GPIO.BCM, GPIO.BOARD, difference is, BCM refers to literal name of pin, and BOARD is physical location on board.
ALL ABOUT PINS, and info for every pin can be found on https://pinout.xyz/
# GPIO/BCM Number
GPIO.setmode(GPIO.BCM)
# Physical/Board pin
# GPIO.setmode(GPIO.BOARD)
- GPIO(General-purpose input/output) have 2 modes.. Input and Output.
- after setting up how we wanna refer to our pin. We need pick what pin we wanna use and what mod will be used.
For more info how relay works, pleas read end of article Component breakdown
Relay class:
- We will not read data from relay, we want control relay by sending low/high state of pin.
- init will setup pin to GPIO.OUT
- we will control On/Off state of relay by sending GPIO.output()
- to power on relay we need send GPIO.LOW/0/False
- to power on relay we need send GPIO.HIGH/1/True
Why Low to On and High to Off? Again, pleas refer to Component breakdown
class Relay:
def __init__(self, pin):
self.pin = pin
def init(self, name):
GPIO.setup(self.pin, GPIO.OUT)
print(f"{name} - GPIO.OUT - pin {self.pin} - init...")
def on(self):
GPIO.output(self.pin, GPIO.LOW)
def off(self):
GPIO.output(self.pin, GPIO.HIGH)
Sensor class:
- After powering on Relay what control voltage to Sensor, we want to read data from it.
- Now we setup init class as GPIO.IN
- We will read data from it just by calling GPIO.input(pin)
class Sensor:
def __init__(self, pin):
self.pin = pin
def init(self, name):
GPIO.setup(self.pin, GPIO.IN)
print(f"{name} - GPIO.IN - pin {self.pin} - init...")
def output(self):
return GPIO.input(self.pin)
Setting up app.py to run code
- We import controller
- We define 2 relays and reading for sensor data
from controller import Relay, Sensor
sensor_data = Sensor(22)
pump = Relay(23)
sensor = Relay(24)
Now create few functions to make while loop clean
- init() to set up modes for devices
- sensor_output() , Turn on relay to power up sensor --> Make reading --> Turn off relay --> return reading(True or False)
- water(sec=5), Turn on relay to power up pump --> sleep for x sec while pump is going --> Turn off relay
def init():
sensor_data.init("Sensor output data")
pump.init("Pump Relay")
sensor.init("Sensor Relay")
def sensor_output():
sensor.on()
time.sleep(2)
reading = sensor_data.output()
time.sleep(1)
sensor.off()
return reading
def water(sec=5):
pump.on()
time.sleep(sec)
pump.off()
While loop
- call init() so we can control relay and sensor
- create infinity while True: loop, we dont need to run code every sec,min or hour... Set up SLEEP_INTERVAL for something like 24h,48h.
- to play it safe we can add GPIO.cleanup() to finally block to clear pins.
try:
init()
while True:
time.sleep(SLEEP_INTERVAL)
dry_soil = sensor_output()
if dry_soil :
print("WATERING!!!")
water()
finally:
print("\n-- END -- \ncleaning GPIO channels...")
GPIO.cleanup()
Images, web site, github
Web interface have temporary images while I gather more data to put there...
Website: https://pi.tricksofthe.trade/
Github: https://github.com/BorisKlco/pi.watering-system
Component breakdown
Here, I will list all components and aliexpress listing for it.
5v Relay 2 channel
Best video about relay what you can watch is from Brad Henson! Depends on you, what type of relay you will buy, but in my case I have Relay One in his video
In very short explanation, we will use voltage from Pi, 5v -> VCC to power relay and activating it. This is why we have jumper connecting VCC and JD-VCC.
This is reason why we have define ON state in our code as Low State or GPIO.LOW, when we set INC pin to Low, we have 0 volts potential on that pin. This will create ground option for our VCC and turn on LED and activate relay.
WARNING!!! - DON'T SWAP VCC and INC PINS ON PI TO USE HIGH STATE AS ON STATE... CAN DMG YOUR PI IF RELAY WILL NOT USE EXTERNAL POWER SOURCE...
def on(self):
GPIO.output(self.pin, GPIO.LOW)
def off(self):
GPIO.output(self.pin, GPIO.HIGH)
Humidity Sensor
As with everything else you can buy several types of humidity sensor.
Andreas Spiess 10 min video explaining different type of sensors and how they works
Quick overview:
Two-legged sensor with controller PCB: Output is digital and analog but will be quicky destroyed after uninterrupted connection of power source...
Capacitive, unexposed copper sensor: Legs can't be dissolved in water, no exposed cooper. 555 timer creates a square wave for one leg, another leg of sensor is Ground, after sensor is submerged into water, two legs will create capacitator... fuucking genius!
Best possible choice what you can do is buy Capacitive Soil Sensor, but be careful! Quality of sensor in this case matters.
For this part I can advice you to watch video from Flaura - Smart Plant Pot , amazing overview of Capacitive Sensor and what can go wrong. Link to video
Quick overview:
Check if 555 timer and 662k voltage regulator is present.
Check if hole is between resistors and not under.
Pump
Any 3v,5v pump 💪 will do...
Cam
Buy Pi supported cam, you can even experiment with new python lib PiCamera2.
Tubes
Check Pump output width, from there you can pick "perfect" tubes for that...
Cables
1P-female to female will do...
Thank you for reading ♥ My next project will be watering system but on STM32 😮
Top comments (0)