Skip to Content
DevelopersGardyn hardware map

Gardyn hardware map

Draft. This page describes intended behaviour that has not been verified on a real Gardyn yet.

Status: checked against the stock firmware, not yet probed on the board. Rows marked “upstream” come from iot-root/garden-of-eden  (config.py, app/lib/hardware.py, README). Rows marked “stock fw” match the firmware on a Gardyn Home 3.0’s stock card (hardware profile hw_gh30, version master.440, Raspbian 9 on a Pi Zero W), read on 2026-11-01. When a row is probed on the board, mark it “verified <date>, model X”.

BCM numbering (not header pin numbers).

FunctionInterfacePin / addressNotesSource
Grow lightPWM outGPIO1820 kHz hardware PWM (stock); upstream used 8 kHzstock fw
PumpGPIO outGPIO24Stock drives it plain on/off (100 %), 5 min runs, ~10.6 W; upstream used 50 Hz software PWM capped at 30 % for brown-outs. See belowstock fw
Water levelDYP-A01 ultrasonictrigger GPIO26, echo GPIO19Stock: 30 µs trigger, 1 s timeout, keeps readings in 3–25 cm and takes the median of the last 6stock fw
ButtonGPIO inGPIO13pull-up, active low, falling edge, 80 ms debounce (stock)stock fw
Over-temp alertGPIO inGPIO25PCT2075 OS output, pull-down; stock sets the over-temperature and hysteresis thresholds to 70 °C and only reports itstock fw
PCB temperatureI²C0x48 PCT2075reads ~47 °C with the lights at 100 %stock fw
Pump powerI²C0x40 INA2190.08 Ω shunt (stock calibration)stock fw
Air temp + humidityI²C0x5C AM2320 (Gardyn 1.0/2.0) · 0x38 DHT20 (3.0, Studio)Stock tries AM2320, then DHT20; our 3.0 uses the DHT20. AM2320 needs a wake-up write before it ACKsstock fw
Upper cameraUSB UVC/dev/seedypod/camera-upper (udev, by USB port; /dev/video0 fallback)through an on-board hub; port unverifiedupstream
Lower cameraUSB UVC/dev/seedypod/camera-lower (udev, by USB port; /dev/video2 fallback)port unverifiedupstream
Controller—Pi Zero W (our 3.0) / Zero 2 WmicroSD boot; stock runs it at force_turbo=1, over_voltage=6stock fw

Tank and pump, from two weeks of stock logs

The data is in tests/fixtures/gardyn-gh30-stock-2024/.

  • Water distance runs from ~5.9 cm just after a fill to ~20 cm empty, falling about 1.3 cm a day.
  • The pump draws ~10.6 W while it lifts water. From ~19.6 cm it loses prime and draws ~3.3 W, which makes pump power a usable dry-run signal.
  • Stock schedules, as observed in the logs: lights at 100 % from 09:00 to 23:00; the pump for 5 min at 03:00, 09:00, 15:00 and 21:00.
  • Raw ultrasonic readings below 3 cm (the blind zone) were the common bad reading; 1 % of good ones read under 4.4 cm.

Model detection

DHT20 ACKs at 0x38 ⇒ Gardyn 3.0 or Studio; otherwise AM2320 ⇒ 1.0/2.0. Studio tank ≈ 4 gal, Home ≈ 5 gal / 30 pods.

Known failure modes (from upstream’s issue tracker — these are our test cases)

  • Pump safety scattered across callers (#108, #109, #114) → PumpGuard is the only path (ADR-0009).
  • Guard used one ultrasonic ping while the alert used a median (#111) → median everywhere.
  • PWM re-init on process start turns the light off (#131) → one long-lived daemon.
  • Camera captures not serialized (#117); fswebcam -S 2 overexposes (#143); exits 0 when unplugged (#144) → mutex, ≥10 skip frames, validate JPEG size.
  • AM2320 doesn’t answer i2cdetect (#142) → wake write before read.
  • Shared MQTT identity across units (#130) → id from /proc/cpuinfo serial.

Phase 1 checklist

  1. Photograph both sides of the PCB, the Pi, header orientation, camera USB routing, PSU label → docs/hardware/photos/.
  2. dd the stock microSD to an image (store off-repo).
  3. Flash Raspberry Pi OS Lite 64-bit (Zero 2 W) with SSH/Wi-Fi/hostname preset.
  4. sudo i2cdetect -y 1; run upstream’s distance.py, light.py --on, pump.py --on --speed 20 (5 s, water present), both cameras — as throwaway probes only. hald --list-cameras → record which USB port is the upper camera, so hald --camera-rules gets the default right.
  5. Check the install steps on real Raspberry Pi OS, which the simulator and the installer tests can’t:
    • Camera ports: hald --list-cameras names both cameras, and the generated udev rules put upper and lower on the right ports.
    • Wi-Fi setup hotspot: holding the button for 10 s opens seedypod-setup-xxxx, and joining a network from http://10.42.0.1:3000/wifi works (NetworkManager, polkit rule).
    • Mosquitto: systemctl status mosquitto is active with /etc/mosquitto/conf.d/seedypod.conf; --mqtt-lan opens 1884 with the printed password.
    • SD card wear settings (ADR-0021): after install-hal, ls /etc/systemd/journald.conf.d/ shows 50-seedypod-volatile.conf and journalctl --header | grep -i 'file path' points under /run/log/journal; swapon --show lists /dev/zram0 and no /var/swap; findmnt -no OPTIONS / includes noatime. Reboot, then check all three again, and that hald and core come back. Settings → Storage shows a writes-per-day figure.
    • Restore on a real card: download a backup, reflash, run both installers, restore from Welcome. The helper runs through sudo -n and systemd-run, and the unit comes back with the same Home Assistant device. Then Undo restore and Redo restore.
  6. Update this table with verified values and the model; file ADR-0008.

Sources: iot-root/garden-of-eden (reference implementation, GPL-3; no code copied)  · [Stock Gardyn firmware, read-only inspection 2026-11-01 (proprietary; facts only, no code copied)](https://github.com/seedypod/core/blob/8781ac82e6a3549d5c7684ab33ac66f3c79e5ba2/docs/hardware/stock  microSD of a Gardyn Home 3.0 (firmware master.440))

Imported from docs/hardware/pin-map.md in seedypod/core. Edit it there, not here.

Last updated on