An ESP32-based departure board that displays real-time Swiss public transport connections on a 2.9" E-Paper display. Uses the Swiss Public Transport API to show upcoming departures with platform, line, and countdown information.
- Real-time departure information from any Swiss station
- Multiple routes displayed simultaneously (sorted by departure time)
- Delay information displayed
- Low power E-Paper display (retains image without power)
- Desktop simulator for development without hardware
- Configurable update intervals (API fetch vs display refresh)
| Component | Model |
|---|---|
| Microcontroller | ESP32-C3-SuperMini |
| Display | 2.9" E-Paper (SSD1680, 296x128, B/W) |
| E-Paper Pin | ESP32-C3 GPIO |
|---|---|
| CLK (SCK) | GPIO4 |
| DIN (MOSI) | GPIO6 |
| CS | GPIO7 |
| DC | GPIO5 |
| RST | GPIO3 |
| BUSY | GPIO2 |
- PlatformIO (recommended) or Arduino IDE
- ESP32 board support
- GCC compiler
- SDL2 library (
sudo apt install libsdl2-dev) - libcurl (
sudo apt install libcurl4-openssl-dev)
git clone https://github.com/yourusername/SBB-Tafel.git
cd SBB-TafelCopy the example configuration and edit with your settings:
cp include/config.h.example include/config.hEdit include/config.h:
// WiFi credentials
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASS "YOUR_WIFI_PASSWORD"
// Route configuration
#define ROUTE_1_FROM "Zürich Altstetten"
#define ROUTE_1_TO "Zürich HB"
#define ROUTE_1_COUNT 6
#define ROUTE_2_FROM "Zürich, Altstetten"
#define ROUTE_2_TO "Zürich, Bäckeranlage"
#define ROUTE_2_COUNT 6Station names must match the Swiss Public Transport API format.
# Build
pio run
# Upload to ESP32
pio run --target upload
# Monitor serial output
pio device monitorBuild and run the simulator to test without hardware:
cd simulator
# Build with real API data
make
# Or build with mock data (no network required)
make mock
# Run
./sbb_simThe simulator opens an SDL window showing the display output.
Edit include/config.h to customize:
| Option | Default | Description |
|---|---|---|
NUM_ROUTES |
2 | Number of routes to display |
MAX_CONNECTIONS |
6 | Connections to cache per route |
DISPLAY_CONNECTIONS |
5 | Connections shown on display |
API_FETCH_INTERVAL_MS |
300000 (5 min) | How often to fetch new data |
DISPLAY_UPDATE_INTERVAL_MS |
60000 (1 min) | How often to refresh display |
SBB-Tafel/
├── include/
│ ├── config.h.example # Configuration template
│ ├── connection.h # Data structures
│ └── display.h # Display interface
├── src/
│ ├── main.cpp # ESP32 main loop
│ ├── api_esp32.cpp # WiFi & API (ESP32)
│ ├── display_esp32.cpp # E-Paper driver (ESP32)
│ └── render.c # Shared rendering logic
├── simulator/
│ ├── src/ # Simulator-specific code
│ ├── u8g2/ # U8g2 graphics library
│ └── Makefile # Simulator build
└── platformio.ini # PlatformIO configuration
- Startup: Connects to WiFi, initializes E-Paper display
- API Fetch (every 5 min): Fetches departure data from transport.opendata.ch
- Display Refresh (every 1 min): Recalculates countdown times from cached timestamps
- Rendering: Merges all routes, sorts by departure time, displays top 5
The split between API fetch and display refresh reduces API calls while keeping the countdown accurate.
Uses the free Swiss Public Transport API:
GET https://transport.opendata.ch/v1/connections?from=X&to=Y&limit=6
No API key required.
- GxEPD2 - E-Paper display driver
- ArduinoJson - JSON parsing
- U8g2_for_Adafruit_GFX - Fonts
MIT License - see LICENSE file.
- Swiss Public Transport API for free access to schedule data
- GxEPD2 for the excellent E-Paper library
- U8g2 for fonts and graphics primitives
