Skip to content

vcs222/weather-square

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Weather Square

A dedicated weather display running on a Raspberry Pi Zero 2W with a HyperPixel 4 Square (720×720 px) touchscreen.

A single lean Rust binary fetches live 10-day forecasts from Open-Meteo and renders directly to the Linux framebuffer — no GUI stack, no browser, no window manager.

demo


Features

  • Two-view interface — swipe left/right to switch between Overview and Detail
  • Overview — 10-day hi/lo temperature chart with area fill, precipitation bar chart, and a 3-day summary strip
  • Detail — scrollable day cards (swipe up/down), each with hourly temperature + precipitation chart, condition, wind, UV, humidity, pressure, and sunrise/sunset
  • Live clock with blinking colon, updated every 500 ms
  • Zero runtime dependencies — one statically-linked binary, writes directly to /dev/fb0
  • Honest error states — shows a loading screen on first boot; if the network is unavailable it retries every 5 min and switches to 30 min once data is fetched

Hardware

Component Model
SBC Raspberry Pi Zero 2W
Display Pimoroni HyperPixel 4 Square (pim470) — touch model
Resolution 720 × 720 px, RGB565 framebuffer
Power 5V 2.5A USB-C

How to use it

Gesture Action
Swipe left Overview → Detail
Swipe right Detail → Overview
Swipe up (in Detail) Show later days
Swipe down (in Detail) Show earlier days

Architecture

Open-Meteo API (free, no key required)
        │
        │  HTTPS/JSON  (fetched on startup, then every 30 min)
        ▼
  weather-square (Rust binary)
        │
        ├── Render thread  — wakes every 500 ms, draws frame → /dev/fb0
        ├── Fetch thread   — fetches Open-Meteo on startup, retries every 5 min until first success, then every 30 min
        └── Touch thread   — reads /dev/input/event*, detects swipes

Shared state is an Arc<Mutex<WeatherData>> for weather data and Arc<AtomicU8> for UI state (active tab, scroll offset).


Getting started

  1. Set up your Pi — see Pi Setup below.
  2. Build — cross-compile on your dev machine (see Building below).
  3. Deploy — copy the binary to the Pi and install the systemd service (see Deployment below).

Configuration

All configuration is via environment variables. Defaults point at Mullsjö, Sweden — change them to your location.

Variable Default Description
OPEN_METEO_LAT 57.9171 Latitude
OPEN_METEO_LON 13.8783 Longitude
OPEN_METEO_TZ Europe/Stockholm Timezone (Open-Meteo format)
LOCATION_NAME MULLSJÖ, SWEDEN Display name shown in header
FB_PATH /dev/fb0 Framebuffer device path
TOUCH_PATH (auto) Touch input event device — auto-detected if not set

Set them in the systemd unit (see Deployment) or export before running manually.

Touch device auto-detection: at startup the binary scans /proc/bus/input/devices for the first device that reports BTN_TOUCH capability and opens it automatically. You only need to set TOUCH_PATH if auto-detection picks the wrong device.

Finding your timezone string: run timedatectl list-timezones on any Linux machine, or browse the tz database list.


Building

You'll need Rust installed on your dev machine. If you don't have it:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Cross-compilation uses cargo-zigbuild, which only requires Zig — no Docker needed.

# Install zig and cargo-zigbuild (once)
brew install zig          # macOS — on Linux: see ziglang.org/download
cargo install cargo-zigbuild

# Add the ARM64 Linux target (once)
rustup target add aarch64-unknown-linux-gnu

# Build
cargo zigbuild --release --target aarch64-unknown-linux-gnu

Binary output: target/aarch64-unknown-linux-gnu/release/weather-square


Deployment

Replace <user> and <pi-hostname> with your Pi's username and hostname (or IP).

Copy the binary

# Stop the service first (binary is locked while running)
ssh <user>@<pi-hostname> 'sudo systemctl stop weather-square'

scp target/aarch64-unknown-linux-gnu/release/weather-square <user>@<pi-hostname>:/home/<user>/weather-square

ssh <user>@<pi-hostname> 'sudo systemctl start weather-square'

systemd unit

Create /etc/systemd/system/weather-square.service on the Pi:

[Unit]
Description=Weather Square
After=network-online.target
Wants=network-online.target

[Service]
ExecStartPre=-/bin/sh -c 'printf "\033[?25l" > /dev/tty1'
ExecStart=/home/<user>/weather-square
Restart=always
RestartSec=5
User=<user>
Environment=OPEN_METEO_LAT=57.9171
Environment=OPEN_METEO_LON=13.8783
Environment=OPEN_METEO_TZ=Europe/Stockholm
Environment=LOCATION_NAME=MULLSJÖ, SWEDEN

[Install]
WantedBy=multi-user.target

Note: TOUCH_PATH is not needed — the binary auto-detects the touchscreen at startup. Only set it if you need to override (e.g. multiple input devices). Check journalctl -u weather-square to see which device was detected.

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable --now weather-square

Check it's running:

sudo systemctl status weather-square
sudo journalctl -u weather-square -f

Pi Setup

OS

Flash Raspberry Pi OS Lite (64-bit) using Raspberry Pi Imager. In the imager's advanced options, set your hostname, username, password, and WiFi credentials before writing — the Pi will boot headless and SSH-ready.

HyperPixel drivers

git clone https://github.com/pimoroni/hyperpixel4 --depth=1
cd hyperpixel4
sudo ./install.sh

Select Square and Touch when prompted, then reboot. Verify with:

ls /dev/fb0   # should exist
cat /dev/urandom > /dev/fb0   # should show noise on screen (Ctrl+C to stop)

Disable screen blanking

On Raspberry Pi OS Bookworm, edit /boot/firmware/cmdline.txt (older releases: /boot/cmdline.txt) and append to the existing single line:

consoleblank=0 logo.nologo=1

Permissions

The binary needs access to the framebuffer and the touchscreen:

sudo usermod -aG video,input <user>

Log out and back in for the change to take effect.

Touch device

The binary auto-detects the touchscreen by scanning /proc/bus/input/devices for the first device with BTN_TOUCH capability — no manual configuration needed. The selected device is logged at startup:

journalctl -u weather-square | grep '\[touch\]'
# [touch] auto-discovered device: /dev/input/event2
# [touch] opened /dev/input/event2

If you ever need to override it, set TOUCH_PATH=/dev/input/eventN in the systemd service.


Dependencies

Crate Purpose
fontdue Software font rasterization
chrono Local time and date parsing
minreq Minimal HTTPS client (rustls)
serde + serde_json JSON deserialization

No GPU, no windowing system, no async runtime.


Fonts

Bundled in assets/fonts/:


Built with Claude Code

This project was implemented exclusively using Claude Code as an agentic coding assistant — from the initial Rust code through hardware debugging, cross-compilation, deployment, and open-sourcing. It was a deliberate experiment to see how far agentic AI can take an embedded systems project end-to-end.


License

MIT

About

Rust weather display for Raspberry Pi Zero 2W + HyperPixel 4 Square — live 10-day forecast, renders directly to framebuffer, no GUI stack

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages