Watering System 💦 with web interface on Raspberry Pi
Tags: python, raspberrypi, tutorial
Published: 2023-10-24 09:56:14

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

1. [Schematic and thought process](#schematic-and-thought-process)
2. [Code review](#code-review)
3. [Images, web site, github](#images-web-site-github)
4. [Component breakdown](#component-breakdown)

---

## 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](https://excalidraw.com/#json=RlH4OjntAQs4o_2UkupOm,U1BlJojmNKWQhYva5iNXTw)... 
And after few rectangles, lines and dream later [I have basic schematic for my watering system...](https://excalidraw.com/#json=RlH4OjntAQs4o_2UkupOm,U1BlJojmNKWQhYva5iNXTw)

![Watering System Schematic ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l6nj5mh16cdr8tao9dxz.jpg)

---

## 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..
---
[controller.py](https://github.com/BorisKlco/pi.watering-system/blob/main/controller.py)

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](#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](#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](https://github.com/BorisKlco/pi.watering-system/blob/main/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

<u>Web interface have temporary images while I gather more data to put there...</u>

**Website:** https://pi.tricksofthe.trade/
**Github:** https://github.com/BorisKlco/pi.watering-system

![Image of case](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bpr5ljtyqusf8itt4uja.jpg)
![Image of case](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qj25ndq4f82zet0bqhil.jpg)

---

## Component breakdown

Here, I will list all components and aliexpress listing for it.

## [5v Relay 2 channel](https://www.aliexpress.com/w/wholesale-relay-5v.html)
Best video about relay what you can watch is from [Brad Henson](https://www.youtube.com/watch?v=FWvEEtrTGRQ)! Depends on you, what type of relay you will buy, but in my case I have **Relay One** in his [video](https://youtu.be/FWvEEtrTGRQ?si=EWFybAj0NbNwZquG&t=176) 

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**.

![Relay voltage, activation schematic - Brad Henson](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/me28n382pyaovywt05lb.JPG)

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.

<u>**WARNING!!!**</u> - 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](https://www.aliexpress.com/w/wholesale-Soil-Humidity-Development-Board.html)

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 ](https://www.youtube.com/watch?v=udmJyncDvw0)

  _Quick overview:_ 
- _**Two-legged sensor with controller PCB:**_ Output is digital and analog but will be quicky destroyed after uninterrupted connection of power source...
![Two-legged sensor with controller PCB - Andreas Spiess](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/byojvpafr82dkx1t2ltc.jpg)

- _**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!
![Capacitive, unexposed copper sensor - Andreas Spiess](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xi2x7em4liychr5idq9k.jpg)

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](https://www.youtube.com/watch?v=IGP38bz-K48) 

  _Quick overview:_ 

Check if 555 timer and 662k voltage regulator is present.
![Capacitive Soil Moisture Sensors - Flaura - Smart Plant Pot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gnr9ivujdob19vqocpm3.jpg)
Check if hole is between resistors and not under.
![Capacitive Soil Moisture Sensors - Flaura - Smart Plant Pot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n81ydxsfhayayxxdpm75.jpg)

---

## [Pump](https://www.aliexpress.com/w/wholesale-DC-3V-5V-Mini-Submersible-Pump-Water-.html)
Any 3v,5v pump 💪 will do... 

---

## [Cam](https://www.aliexpress.com/w/wholesale-rasperry-pi-cam.html)
Buy Pi supported cam, you can even experiment with new python lib PiCamera2.

---

## [Tubes](https://www.aliexpress.com/w/wholesale-Silicone-Tube.html?g=y&SearchText=Silicone+Tube)
Check Pump output width, from there you can pick "perfect" tubes for that...

---

## [Cables](https://www.aliexpress.com/w/wholesale-1p-cable.html)
1P-female to female will do...

---

Thank you for reading ♥ My next project will be watering system but on STM32 😮