Skip to the content
PCBKitNew board
2 layers75 × 55 mmTide carrier, the printed circuit board in 3D

An e-ink tide and weather display for Lakebay, WA (Mayo Cove · Puget Sound). An ESP32 wakes on a timer, fetches NOAA tide predictions and NWS weather over HTTPS, renders a dashboard into a framebuffer on-device, streams…

Size
75 × 55 mm
Copper layers
2
Thickness
1.6 mm
Parts
6
Nets
5
Pads
52
Tracks, vias
13, 0
Pours
1
Routed
Yes
KiCad
KiCad 10.0 (file 20260206)
Created
8 Aug 2026
Updated
8 Aug 2026

Overview

Tide carrier is an open-source printed circuit board by toddself, from the toddself/weather-esp32-eink repository on GitHub. It is a 2-layer board of 75 × 55 mm with 6 parts on 5 nets, routed with 13 tracks and 0 vias.

Its parts include 2 resistors and 2 ICs. It belongs with the lEDs and displays boards and the ESP32 boards of this library.

README

README.md

tide-monitor

An e-ink tide and weather display for Lakebay, WA (Mayo Cove · Puget Sound). An ESP32 wakes on a timer, fetches NOAA tide predictions and NWS weather over HTTPS, renders a dashboard into a framebuffer on-device, streams it to a 13.3" e-paper panel, and goes back to sleep.

Repository layout

  • tide-fw/ — Arduino/ESP32 firmware (PlatformIO). Fetches data, renders the dashboard, and drives the e-ink display.
  • tide-assets/ — offline Rust tool that bakes the Inter font and dashboard icons into C++ atlas headers consumed by the firmware. Only needs to be re-run when the font/icon set changes; the generated headers are checked in.
  • docs/ — Waveshare reference material and wiring-power.md (the PowerBoost-to-driver-board power wiring).
  • pcb/ — board files.

How it runs (firmware flow)

On each wake (tide-fw/src/main.cpp):

  1. Init the display and connect to WiFi (30 s timeout).
  2. Sync the clock over SNTP (timezone PST8PDT, US DST rules).
  3. fetchAll() pulls NOAA tides + NWS forecast and parses them into TideData.
  4. The dashboard is rendered into a 2-bpp framebuffer and streamed to the panel over SPI.
  5. The ESP32 enters deep sleep for REFRESH_SECS seconds, then repeats.

Any failure (no WiFi, no time, fetch error) skips straight to deep sleep and retries on the next wake.

Prerequisites

  • PlatformIO (pio) — firmware build/flash/test. This repo pins the PATH to ~/.platformio/penv/bin via mise.toml, and Python via mise.
  • Rust toolchain (stable, 2021 edition) — only needed to regenerate asset headers with tide-assets.
  • just — task runner (see Common commands).
  • mise (optional but recommended) — provisions Python and sets default environment variables (see below).

Configuration / environment variables

The firmware is configured at build time. tide-fw/platformio.ini reads these values from the environment (sysenv.*) and bakes them into the binary as compile-time -D flags:

VariableRequiredPurpose
WIFI_SSIDyesWiFi network name (2.4 GHz only — the ESP32 has no 5 GHz)
WIFI_PASSyesWiFi password
REFRESH_SECSyesDeep-sleep interval between refreshes, in seconds
NWS_LATyesLatitude (decimal degrees) for the NWS forecast + sun/moon
NWS_LONyesLongitude (decimal degrees)
NWS_STATION_TEMPyesNWS observation station ID for current conditions (e.g. KTIW)
NWS_STATION_TIDEyesNOAA CO-OPS tide station ID (e.g. 9446583)

mise.toml supplies defaults for all of these except WIFI_PASS, which is intentionally not committed and must be provided at flash time (this project keeps it in fnox). The committed defaults point at Lakebay, WA:

toml
# mise.toml
WIFI_SSID        = "…"
REFRESH_SECS     = "900"          # 15 minutes
NWS_LAT          = "47.259174"
NWS_LON          = "-122.764622"
NWS_STATION_TEMP = "KTIW"
NWS_STATION_TIDE = "9446583"

To point the display at a different location, change NWS_LAT/NWS_LON and the two station IDs — no source edits required. If you are not using mise, export them all yourself before flashing:

bash
export WIFI_SSID="your-network"
export WIFI_PASS="your-password"
export REFRESH_SECS=900
export NWS_LAT=47.259174
export NWS_LON=-122.764622
export NWS_STATION_TEMP=KTIW
export NWS_STATION_TIDE=9446583

These are read by PlatformIO's build, so they must be set in the same shell that runs just fw-flash. NWS_STATION_TEMP (weather/temperature) and NWS_STATION_TIDE (tides) are two different stations from two different NOAA services — find a nearby observation station via api.weather.gov/points/<lat>,<lon> and a tide station at tidesandcurrents.noaa.gov.

Flashing the board — step by step

  1. Wire up power and the panel. See docs/wiring-power.md and the pin map in CLAUDE.md. The target board is the Waveshare E-Paper ESP32 Driver Board paired with the 13.3" e-Paper HAT (K).

  2. Set the on-board switches.

    • Switch 1 (display config resistor) → position A (3R) for the 13.3" (K) panel. If the display comes up blank or garbled, flip it to the other position.
    • Switch 2 (UART power) → ON (required to upload firmware).
  3. Connect the board over USB-C (older boards use micro-USB). The USB-UART bridge is a CH343 on recent boards (CP2102 on older ones) — install the matching driver if the serial port doesn't enumerate.

  4. Set the environment variables (see above). With mise, only WIFI_PASS is left to provide:

    bash
    export WIFI_PASS="your-password"
  5. (Optional) Regenerate assets if you changed the font or icons:

    bash
    just fw-assets
  6. Build and flash:

    bash
    just fw-flash

    To flash and immediately watch the serial log:

    bash
    just fw-flash-monitor
  7. Watch the boot log (115200 baud) to confirm WiFi connects, time syncs, and the fetch/render succeeds:

    bash
    just fw-monitor

    You should see it connect, render, then print Entering deep sleep for 900 s.

  8. For deployment, turn Switch 2 (UART power) OFF to save power once the firmware is flashed.

Common commands

All wrapped by just (see justfile):

bash
just               # list all recipes
just check         # lint + tests (Rust) + firmware native tests
just test          # cargo test -p tide-assets
just lint          # cargo fmt --check + clippy -D warnings
just fw-assets     # regenerate font/icon headers (cargo run -p tide-assets)
just fw-test       # pio test -e native  (host-side render/parse tests)
just fw-flash      # build + upload firmware
just fw-monitor    # open the serial monitor
just fw-flash-monitor  # upload, then open the serial monitor

Testing

tide-fw has a PlatformIO native env that compiles the platform-independent parsing/rendering code and runs it under the Unity test framework on the host — it excludes the ESP32-only sources (main.cpp, display.cpp, net.cpp, fetch.cpp, battery.cpp). Run it with just fw-test.

CI (self-hosted Forgejo runner) runs cargo fmt --check, clippy -D warnings, cargo test for tide-assets, and pio test -e native for the firmware.

Previewing the dashboard locally

The renderer is platform-independent, so you can preview the dashboard on the host without flashing:

bash
tide-fw/tools/render_preview.sh   # writes /tmp/render.png (as the panel shows it)

It renders renderDashboard with representative data and also emits /tmp/render_paper.png (inverted). Handy for iterating on layout/fonts/icons.

Note on device memory: a full 960×680 2bpp frame is ~159 KB, larger than the largest contiguous block on this no-PSRAM ESP32 (~110 KB). The firmware renders in two horizontal bands and streams each — grayscale is preserved. The host preview renders the whole frame at once.

Hardware summary

  • Board: Waveshare E-Paper ESP32 Driver Board (board = esp32dev) — ESP32, 4 MB flash, 2.4 GHz WiFi.
  • Panel: 13.3" e-Paper HAT (K), 4-wire SPI.
  • Power: a 3.7 V Li-ion cell (Adafruit #1781, 2200 mAh) → Adafruit PowerBoost 1000C → regulated 5.2 V into the driver board's 5V pin. Battery voltage is sensed on GPIO 34 via a 2:1 divider.

See CLAUDE.md and docs/ for the full pin map, switch settings, and wiring diagrams.

Parts

6
QtyValueFootprintReferences
2100kResistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P7.62mm_HorizontalR1, R2
2M2MountingHole:MountingHole_2.2mm_M2H1, H2
1PowerBoost_1000Ctide-carrier:PowerBoost_1000CU2
1Waveshare_ESP32_Drivertide-carrier:Waveshare_ESP32_DriverU1

Questions

How big is the Tide carrier PCB?

It measures 75 × 55 mm and has 2 copper layers, 1.6 mm thick.

What parts does the Tide carrier use?

6 parts. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Tide carrier KiCad files?

From the toddself/weather-esp32-eink repository on GitHub, at the commit this page was made from: the board is pcb/carrier/tide-carrier.kicad_pcb. PCBKit opens the board in the browser, with nothing to install.

Can I use the Tide carrier design in my own project?

Its repository states no licence, so its author keeps all rights: ask toddself before reusing the design.

Similar boards

  • 2 layers18.5 × 11.1 mmSwitch, the printed circuit board in 3D

    Switch

    byrantech/laptop

    anyon_e, a highly integrated, high end, open source laptop. Attempt the impossible.

    6 parts4.3kMIT
  • 2 layers14.6 × 33 mmBrain board SD Card 1, the printed circuit board in 3D

    Brain board SD Card 1

    rusefi/rusefi

    rusefi - GPL internal combustion engine control unit

    6 parts1.2k
  • 2 layers9 × 9 mmDpoint, the printed circuit board in 3D

    Dpoint

    Jcparkyn/dpoint

    Open-source digital stylus using camera tracking and inertial measurements

    6 parts1.1kMIT
  • 2 layers51.5 × 16.6 mmMicroswitchXY Endstop, the printed circuit board in 3D

    MicroswitchXY Endstop

    VoronDesign/Voron-Hardware

    Cool Hardware designed by the Voron Design group

    6 parts1.1kGPL-3.0
  • 2 layers21.9 × 76.7 mmAmiga External, the printed circuit board in 3D

    Amiga External

    hoglet67/RGBtoHDMI

    Bare-metal Raspberry Pi project that provides pixel-perfect sampling of Retro Computer RGB/YUV video and conversion to HDMI

    6 parts1kGPL-3.0
  • 2 layers88.9 × 50.8 mmBusinesscard, the printed circuit board in 3D

    Businesscard

    hackclub/OnBoard

    💡 Join 1,000 teenagers and make your first PCB with a $100 grant!

    6 parts915
  • 2 layers20.3 × 15.2 mmL0 RGB led, the printed circuit board in 3D

    L0 RGB led

    Luos-io/luos_engine

    Open-source and real-time orchestrator for cyber-physical-systems, to easily design, test and deploy embedded applications and digital twins.

    6 parts546MIT
  • 2 layers9 × 3.6 mmOpticalEncoder, the printed circuit board in 3D

    OpticalEncoder

    adamb314/ServoProject

    Getting the most out of your hobby servo

    6 parts545