Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ sudo apt install python3-yaml python3-smbus python3-pil python3-spidev python3-r
python3 -m pip install growhat
```

This will also install the display driver - ST7735 - and a driver for the light sensor - LTR559.
This will also install the display driver - st7735 - and a driver for the light sensor - LTR559.

## Reference

Expand Down Expand Up @@ -270,12 +270,12 @@ See the LTR559 library for a full reference: https://github.com/pimoroni/ltr559-

### Display

The ST7735 display on Grow is 160x80 pixels and a great way to convey current watering status or build an interface for controlling your watering station.
The st7735 display on Grow is 160x80 pixels and a great way to convey current watering status or build an interface for controlling your watering station.

The display must be set up like so:

```python
display = ST7735.ST7735(
display = st7735.ST7735(
port=0,
cs=1, # Chip select 1 (BCM )
dc=9, # BCM 9 is the data/command pin
Expand All @@ -292,4 +292,4 @@ You should use the Python Image Library to build up what you want to display, an
display.display(image)
```

See the examples for demonstrations of this. See the ST7735 library for a full reference: https://github.com/pimoroni/st7735-python/
See the examples for demonstrations of this. See the st7735 library for a full reference: https://github.com/pimoroni/st7735-python/
44 changes: 44 additions & 0 deletions docs/RaspberryPi5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Raspberry Pi 5 & Zero 1 W

Raspberry Pi 5 & Zero 1 W with GrowHAT mini

*Uses Astral `uv` for python package management*
**This will BUILD a newer version of numpy**

## Apt Package Configuration
```
apt-get install python3-pip swig liblgpio-dev libjpeg-dev cmake dh-autoreconf ninja-build re2c patchelf libfreetype6-dev
apt-get remove gpiod python3-rpi.gpio python3-rpi-lgpio python3-numpy python3-gpiozero python3-pigpio
```

### Editing `/boot/firmware/config.txt

```
# Enable I2C
dtparam=i2c=on
# Enable SPI
dtparam=spi=on
# Set SPI0 CS0 to pin(GPIO) 26 (unused)
# Set SPI0 CS1 to pin(GPIO) 7 for chip select used by HAT
dtoverlay=spi0-2cs,cs0_pin=26,cs1_pin=7
```

### Setup environment
```
# Install Astral UV
# https://docs.astral.sh/uv/getting-started/installation/

curl -LsSf https://astral.sh/uv/install.sh | sh

# Sync environment to uv.lock file
uv sync --frozen --verbose

# Walk away, this will take a while depending on your hardware.
```

### Run examples
```
uv run --directory examples/advanced moisture.py
uv run --directory examples/advanced lcd-demo.py
uv run --directory examples monitor.py
```
8 changes: 5 additions & 3 deletions examples/advanced/lcd-demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import logging

import ST7735
import st7735
from fonts.ttf import RobotoMedium as UserFont
from PIL import Image, ImageDraw, ImageFont

Expand All @@ -21,7 +21,7 @@
)

# Create LCD class instance.
disp = ST7735.ST7735(
disp = st7735.ST7735(
port=0, cs=1, dc=9, backlight=12, rotation=270, spi_speed_hz=10000000
)

Expand All @@ -43,7 +43,9 @@
back_colour = (0, 170, 170)

message = "Hello, World!"
size_x, size_y = draw.textsize(message, font)
left, top, right, bottom = draw.multiline_textbbox((0, 0), message, font)
size_x, size_y = right - left, bottom - top


# Calculate text position
x = (WIDTH - size_x) / 2
Expand Down
26 changes: 19 additions & 7 deletions examples/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import ltr559
import RPi.GPIO as GPIO
import ST7735
import st7735
import yaml
from fonts.ttf import RobotoMedium as UserFont
from PIL import Image, ImageDraw, ImageFont
Expand Down Expand Up @@ -46,6 +46,12 @@
icon_return = Image.open("icons/icon-return.png").convert("RGBA")



def _getbboxwidth(font, text, *args, **kwargs):
left, top, right, bottom = font.getbbox(text, *args, **kwargs)
return right - left


class View:
def __init__(self, image):
self._image = image
Expand Down Expand Up @@ -90,7 +96,9 @@ def label(
if position not in ["A", "B", "X", "Y"]:
raise ValueError(f"Invalid label position {position}")

text_w, text_h = self._draw.textsize(text, font=self.font)
left, top, right, bottom = self._draw.multiline_textbbox((0, 0), text, font=self.font)
text_w, text_h = right - left, bottom - top

text_h = 11
text_w += margin * 2
text_h += margin * 2
Expand Down Expand Up @@ -143,7 +151,7 @@ def text_in_rect(self, text, font, rect, line_spacing=1.1, textcolor=(0, 0, 0)):

while (
len(words) > 0
and font.getsize(" ".join(line + [words[0]]))[0] <= width
and _getbboxwidth(font, " ".join(line + [words[0]])) <= width
):
line.append(words.pop(0))

Expand All @@ -161,7 +169,9 @@ def text_in_rect(self, text, font, rect, line_spacing=1.1, textcolor=(0, 0, 0)):
bounds = [x2, y, x1, y + len(lines) * line_height]

for line in lines:
line_width = font.getsize(line)[0]
left, top, right, bottom = self.font.getbbox(line)
line_width = right - left

x = int(x1 + (width / 2) - (line_width / 2))
bounds[0] = min(bounds[0], x)
bounds[2] = max(bounds[2], x + line_width)
Expand Down Expand Up @@ -222,7 +232,8 @@ def render_channel(self, channel):
self.icon(icon_channel, (x, label_y), (200, 200, 200) if active else (64, 64, 64))

# TODO: replace number text with graphic
tw, th = self.font.getsize(str(channel.channel))
left, top, right, bottom = self.font.getbbox(str(channel.channel))
tw, th = right - left, bottom - top
self._draw.text(
(x + int(math.ceil(8 - (tw / 2.0))), label_y + 1),
str(channel.channel),
Expand Down Expand Up @@ -479,7 +490,8 @@ def render(self):

self.icon(icon_channel, (label_x, label_y), (200, 200, 200))

tw, th = self.font.getsize(str(self.channel.channel))
left, top, right, bottom = self.font.getbbox(str(self.channel.channel))
tw, th = right - left, bottom - top
self._draw.text(
(label_x + int(math.ceil(8 - (tw / 2.0))), label_y + 1),
str(self.channel.channel),
Expand Down Expand Up @@ -1015,7 +1027,7 @@ def handle_button(pin):


# Set up the ST7735 SPI Display
display = ST7735.ST7735(
display = st7735.ST7735(
port=0, cs=1, dc=9, backlight=12, rotation=270, spi_speed_hz=80000000
)
display.begin()
Expand Down
4 changes: 2 additions & 2 deletions examples/tools/calibrate-pump.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import time

import RPi.GPIO as GPIO
import ST7735
import st7735
from fonts.ttf import RobotoMedium as UserFont
from PIL import Image, ImageDraw, ImageFont

Expand Down Expand Up @@ -51,7 +51,7 @@
last_dose = time.time()
saturation = [1.0 for _ in range(NUM_SAMPLES)]

display = ST7735.ST7735(
display = st7735.ST7735(
port=0, cs=1, dc=9, backlight=12, rotation=270, spi_speed_hz=80000000
)

Expand Down
3 changes: 2 additions & 1 deletion grow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
from . import pwm

PLATFORMS = {
"Raspberry Pi 5": {"piezo": ("PIN33", pwm.OUTL)},
"Raspberry Pi 5": {"piezo": ("GPIO13", pwm.OUTL)},
"Raspberry Pi 4": {"piezo": ("GPIO13", pwm.OUTL)},
"Raspberry Pi Zero": {"piezo": ("GPIO13", pwm.OUTL)},
}


Expand Down
22 changes: 11 additions & 11 deletions grow/moisture.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
from gpiod import LineSettings
from gpiod.line import Bias, Edge

MOISTURE_1_PIN = 23
MOISTURE_2_PIN = 8
MOISTURE_3_PIN = 25
MOISTURE_INT_PIN = 4
MOISTURE_1_PIN = "GPIO23"
MOISTURE_2_PIN = "GPIO8"
MOISTURE_3_PIN = "GPIO25"
MOISTURE_INT_PIN = "GPIO4"


class Moisture(object):
Expand Down Expand Up @@ -46,25 +46,25 @@ def __init__(self, channel=1, wet_point=None, dry_point=None):
))

self._poll_thread_event = threading.Event()
self._poll_thread = threading.Thread(target=self._thread_poll)
self._poll_thread = threading.Thread(target=(lambda: self._thread_poll(self._poll_thread_event)))
self._poll_thread.start()

atexit.register(self._thread_stop)
atexit.register(lambda: self._thread_stop(self._poll_thread_event))

def __del__(self):
self._thread_stop()
self._thread_stop(self._poll_thread_event)

def _thread_stop(self):
self._poll_thread_event.set()
def _thread_stop(self, event):
event.set()
self._poll_thread.join()

def _thread_poll(self):
def _thread_poll(self, event):
poll = select.poll()
try:
poll.register(self._int.fd, select.POLLIN)
except TypeError:
return
while not self._poll_thread_event.wait(1.0):
while not event.wait(1.0):
if not poll.poll(0):
# No pulses in 1s, this is not a valid reading
continue
Expand Down
3 changes: 2 additions & 1 deletion grow/pump.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
PUMP_MAX_DUTY = 0.9

PLATFORMS = {
"Raspberry Pi 5": {"pump1": ("PIN11", pwm.OUTL), "pump2": ("PIN12", pwm.OUTL), "pump3": ("PIN15", pwm.OUTL)},
"Raspberry Pi 5": {"pump1": ("GPIO17", pwm.OUTL), "pump2": ("GPIO27", pwm.OUTL), "pump3": ("GPIO22", pwm.OUTL)},
"Raspberry Pi 4": {"pump1": ("GPIO17", pwm.OUTL), "pump2": ("GPIO27", pwm.OUTL), "pump3": ("GPIO22", pwm.OUTL)},
"Raspberry Pi Zero": {"pump1": ("GPIO17", pwm.OUTL), "pump2": ("GPIO27", pwm.OUTL), "pump3": ("GPIO22", pwm.OUTL)},
}


Expand Down
17 changes: 10 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ name = "growhat"
dynamic = ["version", "readme"]
description = "Grow HAT Mini. A plant valet add-on for the Raspberry Pi"
license = {file = "LICENSE"}
requires-python = ">= 3.7"
requires-python = ">= 3.11"
authors = [
{ name = "Philip Howard", email = "[email protected]" },
{ name = "Paul Beech", email = "[email protected]" },
Expand Down Expand Up @@ -36,13 +36,16 @@ classifiers = [
"Topic :: System :: Hardware",
]
dependencies = [
"setuptools",
"rpi-lgpio",
"gpiodevice",
"gpiod>=2.1.3",
"ltr559>=1.0.0",
"st7735>=1.0.0",
"pyyaml",
"fonts",
"font-roboto"
"ltr559>=1.0.0",
"st7735>=1.0.0",
"pyyaml",
"fonts",
"font-roboto",
"Pillow",
"numpy",
]

[project.urls]
Expand Down
Loading