A project using a Raspberry Pi board and Python, which checks the upcoming weather forecast for rain and can enable a bypass on your irrigation controller.
A Note on Irrigation Systems: Not all irrigation controllers are created equal, nor do they all operate in the same way. I have created this project based on a single example in my own home, which is the "Rain Bird ESP Modular" model. This controller has a pair of "Sensor" electrical contacts inside, which are devoted to any external rain sensor you might want to connect. The Rain Bird ESP Module controller sensor system operations on a "Normally Closed" architecture, meaning that the sensor contacts are part of a simple electrical circuit that is normally complete - i.e. the contacts are connected to each other and have continuity. If the contacts are connected, the irrigation controller follows its normally programmed irrigation cycle. If that circuit is "broken", it overrides the irrigation cycle programming and your irrigation system will NOT run. Please research the documentation on your irrigation controller before attempting to use this project. If your irrigation controller sensor system operates on a Normally Closed or Normally Open basis, this project could work - though if your controller requires a Normally Open configuration, you will need to swap the pinout on the Relay Output connectors from what is shown in this documentation. Happy Irrigating!
Parts to purchase:
Tools needed:
Bring your own:
The Raspberry Pi computing platform most commonly runs a distribution of the Linux operating system, written for ARM processor architectures. In this case I am using the standard Debian Linux distribution recommended by the creators of the RPi. This comes in two versions: Desktop (has a GUI interface) and Lite (CLI only). I am using the Lite version to save on system resources and because I intend to run the Pi in "headless" mode, without a keyboard, mouse or video display. Let's get started!
ssh
- there should be NO file extension in the filename. This file tells Debian to enable SSH access permanently on first bootup.wpa_supplicant.conf
and add the text below. MAKE SURE to replace YOURSSID
and YOURPASSWORD
with your actual wireless SSID and PSK (leave the "" surrounding your SSID and PSK). This pre-loads Debian with your wireless network info so it will automatically connect.ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=US
network={
ssid="YOURSSID"
psk="YOURPASSWORD"
scan_ssid=1
}
config.txt
file that already exists and add the following lines at the bottom of the file. This setting allows you to use the USB cable for direct console access for emergency troubleshooting.# Enable UART
enable_uart=1
# Enable Ethernet over USB
dtoverlay=dwc2
cmdline.txt
file that already exists and add the text modules-load=dwc2,g_ether
after rootwait
. This file should contain a single line of text with no line breaks and the text you add should be separated from rootwait
by a single space. The end result should look like this:console=serial0,115200 console=tty1 root=PARTUUID=eabcf7ff-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2,g_ether
If you purchased the Adafruit Featherwing Non-Latching relay board, you will need to solder on a few components. You will want to attach the 3-pin terminal block and you may want to attach header pins to the appropriate through holes.
The non-latching relay on the Featherwing board works by applying 3.3v to one side of the relay switch, through a transistor. The "Signal" pin activates the transistor when 3.3v is applied to it, and this completes the 3.3v --> Ground circuit. When this circuit is completed, it powers an electromagnet inside the relay which actuates a larger switch (capable of handling much higher voltage and amperage). The relay output has two states:
On the Raspberry Pi, we will need to use the following GPIO pin types:
The 3.3v power and Ground pins will provide power to the actuation side of the Relay, one GPIO pin will provide 3.3v power (as needed) to the Relay Signal pin, and the other GPIO pin will track the Normally Open state of the Relay Output. The Normally Open relay GPIO pin will supply a small amount of voltage at all times, in order to "read" whether the circuit is complete or not. This gives us the ability to know with certainty - i.e. a sanity check - what the Relay Output state is at any given time.
Here is a sample wiring diagram that depicts one possible way to connect the relay to the Raspberry Pi. Any set of pins which provide the right capabilities (i.e. power, ground, and GPIO signal) can be used:
This project makes use of the OpenWeathermap API to obtain local weather forecast data. OpenWeathermap provides a free licensing tier that includes the "3-Hour Forecast 5 Days" API endpoint, which is what this script will use. Create a free account by clicking on the "Get API Key" button under the Free column on this page: https://openweathermap.org/price Once you've created your account, you will need to generate your API (called "app-id") key, and add it to the Environment Variable file described in the next section. You will also need to obtain the Latitude and Longitude coordinates for your location, to a 2 decimal point precision (don't forget any negative (-) symbols for Longitude!) - this can easily be obtained from the Google Maps website.
An example of the API output is located here for reference. The API documentation can be found here: https://openweathermap.org/forecast5
OWM_UNITS
: Measurement system for units returned by API ("metric", "imperial", "standard")OWM_LAT
: Latitude for forecast location, measured to 2 decimal points (ex: 44.88)OWM_LON
: Longitude for forecast location, measured to 2 decimal points (ex: -93.22)OWM_APPID
: OpenWeathermap API keyOWM_CNT
: Number of timestamps API should return; forecasts are 3 hour periods, so 8 timestamps would equal 24 hours.OWM_3H_INTERVALS
: Number of forecast intervals to be evaluated by the forecast.py
script. Default to 4 which makes the script evaluate 12 hours of forecast data.OWM_THRESHOLD
: Percentage of precipitation (rain) possibility that will trigger a bypass of the irrigation system. This value is compared to the pop
field in the API JSON output and is expressed as a decimal ratio between 0 and 1 (0 = 0%, 1 = 100%, 0.5 = 50%).OWM_URL
: OpenWeathermap API base URL; currently defaults to "https://api.openweathermap.org/"OWM_IRR_HOUR
: Hour of the day (expressed in 24h format) that your irrigation system is programmed to start running. This is used by the forecast.py
script to determine whether irrigation should be bypassed, based on the date/time stamp of forecast data.OWM_IRR_EVEN_ODD
: If your local regulations require you to irrigate on only even or odd days, set this value to 0 (for even days) or 1 (for odd days). Leave blank if you irrigate every day.OWM_GMAIL_USER
: Gmail user account for sending alert emails.OWM_GMAIL_RECIPIENT
: Email recipients list for alert emails. This MUST be expressed as a Python list in String format, such as this example: '["email1", "email2"]' (Please note and emulate the placement of both single and double quotation marks)OWM_GMAIL_APP_PASSWORD
: Application password that you have generated for the sender Gmail account (you can not authenticate using the account's actual password - you MUST generate an application password).OWM_DB_FILE
: Name of the TinyDB database file used to store forecast data. Default is 'db.json'.RAIN_SENSOR_HOST
: The local IP address of your Raspberry Pi board; used for the flask run
command. It is highly recommended NOT to set this value to: "0.0.0.0"RAIN_SENSOR_PORT
: The local port that Flask should bind to when running the applicaiton. This should always be set to "80". If you change this port, you may need to alter the app.py
and/or forecast.py
scripts to accomodate the change.RAIN_SENSOR_LOG
: Logging level for the Python application and forecast.py
script. Valid values are: DEBUG, INFO, WARNING, ERROR, CRITICALRAIN_SENSOR_SIGNAL_PIN
: GPIO pin connected to the "Signal" pin on the relay board, using the Broadcom (BCM) Pinout mode (see wiring diagram or search Google for details).RAIN_SENSOR_RELAY_NO_PIN
: GPIO pin connected to the "Normally Open" relay output on the relay board, using the Broadcom (BCM) Pinout mode.In this section we'll begin the installation and setup process. We'll start by verifying that Python 3 is installed (the Debian image comes with Python 2 and 3 pre-installed but this script is not fully backward compatible with Python 2) and the necessary Python modules. Then we will install the Python script and configure the background service. Additionally, in the Testing and Troubleshooting section I've given an explanation of the sudo
command prefix that you'll find in this section.
pi
raspberry
passwd
. Follow the prompts to change the password.git
command line tool is installed:
sudo apt-get update
sudo apt-get install git -y
git clone https://github.com/miarond/RPi_Irrigation_Bypass_Sensor.git rain_sensor
cd rain_sensor
default.env
file to .env
with the command: mv default.env .env
.env
file and update all of the relevant Environment Variable values.rain-sensor.service
file and update the FLASK_RUN_HOST
environment variable with your Raspberry Pi's local IP address.setup.sh
file:
ls -al | grep setup
to view the file and its attributes.
pi@raspberrypi:~ $ ls -al | grep setup
-rw-r--r-- 1 pi pi 1848 Dec 23 12:41 setup.sh
drwxrwxrwx
where the first letter denotes either a file (-
) or a directory (d
). The next groupings of 3 letters denote read (r
), write (w
) and execute (x
) permissions. As you can see, my file is missing the execute permission.chmod +x setup.sh
. Because the pi
user account is the owner of the file, we can run this command without adding the sudo
prefix.sudo ./setup.sh
Enter
key to continue.http://<raspberry_pi_IP_address>
.The core of this project is a Web application and REST API, created using the Flask package in Python. This application is completely contained in the app.py
script and templates/index.html
file, and is run at startup by the rain-sensor
background service under systemd
. You can access this application when the service is running by visiting http://<raspberry_pi_IP_address>
in any web browser, while you're on your local network. This page has an ON/OFF button which, when clicked, will send a REST API call to the Flask application and will trigger the relay to change from its current state. The new state will then be reported back to the web page and displayed as "ON", "OFF", or if a fault is encountered "UNKNOWN".
The web page also has a checkbox for activating a Manual Override, which is persistent and stored in a separate database file on disk. When the page loads, the override status is checked via an API call to the Flask application, and the state of the checkbox is updated accordingly. When the checkbox is clicked, a jQuery script sends an API call to the Flask application requesting an update to the manual override state database.
Please note: The manual change of the relay state from the ON/OFF button can be overridden automatically by the forecast.py
script. Also, any power outage will cause the relay to return to its unpowered, Normally Closed state. However, if the Manual Override checkbox has been checked or unchecked via the webpage, this change is stored on local disk on the Rasbperry Pi and will persist across reboots and power outages.
The forecast.py
script is configured to run periodically via a CRON job that is created during the initial setup phase. This script will run at the prescribed times, download forecast data, determine if the rain percentage is greater than or equal to the threshold percentage (set in the Environment Variables), and will make REST API calls to the app.py
Flask application in order to change the Relay state. The script will also use the TinyDB Python package to create a simple document database for storing the previous forecast data, and the resulting irrigation system state. This data is stored in a local file named db.json
and is flushed at the beginning of every run of the forecast.py
script.
Wait, you mean it didn't work right the first time??? It's a well known axiom that code rarely works right on the first try...and if it does, you should be suspicious! There are several places where this setup process could go wrong and its always best to watch the SSH console output carefully as the installation progresses. Detailed error messages or warnings will often be displayed on the console.
Some common spots for trouble could be:
sudo
prefix. The sudo
command stands for "Superuser Do" and it is the equivalent of choosing "Run as Administrator" on Windows operating systems.ls -al
command. Running the chmod +x <filename>
command will add execute permissions - using +r
or +w
will add read or write permissions.apt-get
) package manager for installing programs.sudo
because this will install the package at the system level, making it available to all users and Python instances.python3 <script_name>
.service rain-sensor status
journalctl -u rain-sensor.service -f
(shows the STDOUT and STDERR logs from the service - the "-f" flag follows the log file and displays any new updates)sudo nano /etc/systemd/system/rain-sensor.service
Ctrl + O
to save the file, then Ctrl + X
to exit.sudo systemctl daemon-reload
sudo systemctl start rain-sensor.service
gpio readall
. This runs the wiringpi
package and displays a table of GPIO status information (additional information can be found via the command man gpio
)If your Pi doesn't come online and connect to your wireless network automatically, you can try connecting a keyboard, mouse and monitor if you have the proper adapters for both Micro USB and Mini HDMI. However, if you don't have those adapters you CAN use the USB data cable to establish an emergency terminal/console session. The process is partially documented on this website The Polyglot Developer. Windows users will need to install Apple's Bonjour Print Services application to communicate with the Pi over USB (this is the only method I have personally tested). Mac users should not need this additional step (as documented here).
Once setup is complete on your computer, connect the Micro USB cable to the USB port on the Pi (NOT the PWR IN port) and to a USB port on your computer. The Pi should power on and establish a network connection to your computer via the USB cable. You can then simply SSH to raspberrypi.local
from your computer and you should be able to connect to the Pi just like you would over a network connection.
The following is a directory tree structure that illustrates the files installed and where they are placed.
/
āāāā home
| āāāā pi
| āāāā rain_sensor
| āāāā setup.sh
| āāāā app.py
| āāāā forecast.py
| āāāā gpio_cleanup.py
| āāāā db.json
| āāāā .env
| āāāā templates
| āāāā index.html
āāāā etc
āāāā systemd
āāāā system
āāāā rain-sensor.service
Owner
Contributors
Categories
Programming Languages
PythonLicense
Code Exchange Community
Get help, share code, and collaborate with other developers in the Code Exchange community.View Community