09 Software — Pi Setup
09 Software — Pi Setup
The hardware is wired and the relays click on cue. Now get an OS onto the Pi. This page walks Pi Imager (one screen — set the hostname, WiFi, and SSH key, then write the SD card), the first SSH-in over the LAN, and the one-shot setup-pi.sh script that installs every Python dependency, enables I2C, sets up a venv under ~/irrigation/, and wires up the cron schedule. Reboot when prompted, verify with i2cdetect -y 1, and you’re ready for page 10.
Get an OS on the SD card
Download Raspberry Pi Imager from raspberrypi.com and install it on your laptop. Insert a microSD card (8 GB minimum, class 10 or better) into your laptop’s card reader.
In the Imager, pick Raspberry Pi OS Lite (64-bit) under “Choose OS → Raspberry Pi OS (other)”. Lite means no desktop — this Pi is a headless server, so the desktop would just waste SD-card space and boot time.
Before you click “Write”, click the gear icon (advanced settings) and configure:
- Hostname:
irrigator(so you can SSH toirrigator.localinstead of memorizing an IP). - Enable SSH: pick “Use public-key authentication” if you already have an SSH key on your laptop (recommended); password auth works too if you’re new to SSH.
- Set username and password: username
pi, password your choice. - Configure wireless LAN: enter your WiFi SSID + password and set the country (the Pi needs the country code to enable the right WiFi channels).
- Set locale: your timezone + keyboard layout.
Save the settings, then click “Write” and confirm. The Imager flashes Pi OS Lite onto the SD card in about 3 minutes. Eject the card, slide it into the Pi’s SD slot (underside of the board), and power it on. First boot takes ~60 seconds — the Pi expands the filesystem, joins WiFi, and starts the SSH daemon.
First boot and SSH in
From your laptop, on the same WiFi network as the Pi:
The first connection asks you to confirm the host key — type yes and press Enter. After that you’re at a Pi shell prompt: pi@irrigator:~ $. Everything you type from here runs on the Pi.
What is SSH? Secure Shell — a way to type commands into a remote computer (the Pi) from your laptop. The terminal you’re typing in is on your laptop; everything after ssh [email protected] is running on the Pi. When you exit the SSH session, you’re back at your laptop’s shell.
What if .local doesn’t resolve? The .local suffix relies on mDNS, and mDNS doesn’t work on every router or every OS combination. If ssh [email protected] hangs for 30 seconds and then says “host not found”, look at your router’s admin page (usually 192.168.1.1 or 192.168.0.1) for the DHCP lease list and find the Pi by hostname irrigator. Then SSH by IP: ssh [email protected] (or whatever IP the router shows). On a Mac, dns-sd -B _ssh._tcp lists every mDNS-advertised SSH server on your LAN — handy for debugging.
The one-shot setup script
The script below installs every Python dependency, enables I2C, creates ~/irrigation/ with a logs/ subdirectory, sets up a Python virtual environment, copies the four irrigation scripts into place, and installs a cron schedule for 7am + 6pm watering checks. Run it once on a fresh Pi OS Lite image; reboot when it tells you to.
#!/bin/bash
# Raspberry Pi Irrigation Controller — Full Setup Script
# Run this on the Pi via SSH or directly
# Usage: bash setup-pi.sh
set -e
echo "============================================"
echo "Irrigation Controller Setup"
echo "============================================"
# 1. Update system
echo "[1/6] Updating system packages..."
sudo apt update && sudo apt upgrade -y
# 2. Install system dependencies
echo "[2/6] Installing system dependencies..."
sudo apt install -y python3-pip python3-smbus i2c-tools python3-venv
# 3. Enable I2C
echo "[3/6] Enabling I2C..."
sudo raspi-config nonint do_i2c 0
# 4. Create project structure
echo "[4/6] Creating project structure..."
mkdir -p ~/irrigation/logs
cd ~/irrigation
# 5. Create virtual environment and install Python packages
echo "[5/6] Setting up Python environment..."
python3 -m venv venv
source venv/bin/activate
pip install adafruit-circuitpython-ads1x15 RPi.GPIO
# 6. Copy scripts (assumes they're in the same directory as this setup script)
echo "[6/6] Installing scripts..."
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
for script in irrigate.py calibrate.py status.py manual_water.py; do
if [ -f "$SCRIPT_DIR/$script" ]; then
cp "$SCRIPT_DIR/$script" ~/irrigation/
chmod +x ~/irrigation/$script
echo " Installed $script"
else
echo " WARNING: $script not found in $SCRIPT_DIR"
fi
done
# Create cron wrapper
cat > ~/irrigation/run.sh << 'EOF'
#!/bin/bash
cd ~/irrigation
source venv/bin/activate
python3 irrigate.py
EOF
chmod +x ~/irrigation/run.sh
# Set up cron schedule
echo "Setting up cron schedule..."
(crontab -l 2>/dev/null | grep -v irrigation; echo "0 7 * * * ~/irrigation/run.sh >> ~/irrigation/logs/cron.log 2>&1"; echo "0 18 * * * ~/irrigation/run.sh >> ~/irrigation/logs/cron.log 2>&1") | crontab -
echo ""
echo "============================================"
echo "Setup complete!"
echo "============================================"
echo ""
echo "Next steps:"
echo " 1. Reboot: sudo reboot"
echo " 2. After reboot, verify I2C: sudo i2cdetect -y 1"
echo " 3. Calibrate sensors: cd ~/irrigation && source venv/bin/activate && python3 calibrate.py"
echo " 4. Update thresholds: nano ~/irrigation/irrigate.py"
echo " 5. Test run: python3 ~/irrigation/irrigate.py"Run it
You need the script and the four irrigation Python files (irrigate.py, calibrate.py, status.py, manual_water.py) on the Pi together in one directory. Either git clone from your fork of the repo, or scp them from your laptop (scp -r irrigation/ [email protected]:~/). Then from the Pi’s SSH session:
cd ~/irrigation
bash setup-pi.shThe script logs each step ([1/6] through [6/6]); apt update + the Python deps takes 3-5 minutes on a fresh image. The first time it runs raspi-config nonint do_i2c 0 you may see a brief flash about reconfiguring dphys-swapfile — that’s normal.
What the script does, step-by-step
[1/6] apt update + upgrade— refreshes package lists and applies security patches (the freshest Pi OS image is usually a few weeks old by the time you flash it).[2/6] install python3-pip + python3-smbus + i2c-tools + python3-venv— Python 3’s package manager, the smbus library for I2C, thei2cdetectdebug tool, and the venv module.[3/6] enable I2C— turns on the I2C kernel module viaraspi-config nonint do_i2c 0(thenonintflag means no interactive menu — the script can flip the bit and move on).[4/6] create ~/irrigation/— the project directory, with alogs/subdirectory for the cron output log.[5/6] venv + pip install adafruit-circuitpython-ads1x15 + RPi.GPIO— an isolated Python environment under~/irrigation/venv/plus the two librariesirrigate.pyimports (the ADS1115 driver for the moisture sensors, andRPi.GPIOfor the relay pins).[6/6] copy scripts + create cron wrapper + install cron schedule— dropsirrigate.py,calibrate.py,status.py, andmanual_water.pyinto~/irrigation/, createsrun.sh(the cron wrapper that activates the venv before runningirrigate.py), and installs cron lines for 7am + 6pm watering checks logged to~/irrigation/logs/cron.log.
After the script finishes you’ll have this layout under ~/irrigation/:
~/irrigation/
├── venv/ # Python virtual environment (5)
├── logs/
│ └── cron.log # appended by cron at 7am + 6pm
├── irrigate.py # main loop — page 10
├── calibrate.py # interactive sensor reader — page 11
├── status.py # one-shot status print
├── manual_water.py # manual override CLI
├── run.sh # cron wrapper (sources venv, runs irrigate.py)
└── setup-pi.sh # this script (kept around for re-runs)
What is a venv? A Python virtual environment — a self-contained venv/ directory under ~/irrigation/ with its own Python interpreter and pip-installed packages. The source venv/bin/activate line tells your shell to use the venv’s Python instead of the system Python; which python3 after activating points into ~/irrigation/venv/bin/. It keeps the irrigation libraries from polluting the rest of the Pi’s Python install (and vice-versa — Pi OS updates won’t break your pinned package versions). Activate with source ~/irrigation/venv/bin/activate; deactivate with the bare command deactivate.
Reboot and verify
The I2C kernel module needs a reboot to load:
sudo rebootWait ~30 seconds; SSH back in once the LED activity settles.
Verify I2C is working — you should see 48 in the address grid (the ADS1115’s default I2C address):
sudo i2cdetect -y 1If 48 shows up, your sensors are reachable from the Pi and you’re ready for page 10. If the grid is empty, one of three things is wrong: the ADS1115 isn’t powered (check 3.3V on its VDD pin), SDA and SCL are swapped at the Pi header (re-check the page-08 wiring table), or the ADDR pin is floating instead of tied to GND. Page 13’s troubleshooting section walks the full I2C debug path.
With the Pi software installed and I2C verified, page 10 walks the irrigation script itself — what each config block in irrigate.py means, how the watering loop decides to fire a zone, and the finally: all_off() fail-safe that guarantees no relay stays latched if the script crashes.