BikeControl (SwiftControl)
Use Zwift Click, Zwift Play, Shimano Di2, or any Bluetooth controller with MyWhoosh, Rouvy, Zwift, and more. Free to try on iOS, Android, Windows, and macOS.
翻訳待ち
Opensource Eink bike computer
翻訳待ち
Loading the full README. The saved excerpt is shown below.
OpenTrailPaper — a DIY e-paper bike GPS head unit for the LilyGO T5S3 4.7" e-paper PRO,
plus companion apps for maps, routes and settings: SwiftUI on iOS
and Jetpack Compose on Android.
→ Project site — feature tour
and an in-browser Web Serial firmware flasher (Chrome/Edge, no toolchain needed).
Source in docs/.
The iOS app is on the App Store.
The Android app is a sideloadable APK that CI builds and signs for each android-v* tag:
grab it from the project site
or from the android-v* entries on the Releases page.Read the full README ↗OpenTrailPaper — a DIY e-paper bike GPS head unit for the LilyGO T5S3 4.7" e-paper PRO, plus companion apps for maps, routes and settings: SwiftUI on iOS and Jetpack Compose on Android.
→ Project site — feature tour
and an in-browser Web Serial firmware flasher (Chrome/Edge, no toolchain needed).
Source in docs/.
The iOS app is on the App Store. The Android app is on Google Play.
The board has everything onboard: ESP32-S3 (16 MB flash / 8 MB PSRAM, BLE 5), 960×540 e-paper (driven in 540×960 portrait) with GT911 touch, GPS (u-blox MIA-M10Q or L76K/CASIC — autodetected), SD card slot, PCF8563 RTC, BQ25896 charger and BQ27220 fuel gauge.
The reference hardware is the LilyGO T5S3 4.7" e-paper PRO — everything is onboard, nothing to wire. The firmware targets it directly, but the hardware-specific pieces are small and isolated, so alternative boards are intended to be supportable.
A candidate board needs, at minimum:
src/epd_compat.*, which
has two backends: EPD_Painter (the shipping one — pio run) and
epdiy (pio run -e t5s3-pro), so a panel
needs a board definition for whichever you use. The layout assumes ~4.7" /
960×540; a different size means reworking src/ui_render.cpp.Porting is mostly re-pointing three things:
src/config.h — every GPIO (GPS UART, shared I²C, SD SPI,
buttons, backlight) and the display rotation.src/board_power.* — power rails and sleep. On the reference board the
GPS 3V3 rail is gated behind pin 0 of the XL9555 I²C expander, so the
receiver stays dark until that's switched on — an easy thing to miss on a port.platformio.ini) — how the display is driven.The non-essential peripherals (RTC, fuel gauge, charger, frontlight) degrade gracefully if a board lacks them.
The board has no pressure sensor, and the GPS chip's own altitude (geometric, no barometric aiding) is far too noisy to derive climb from — tens of metres of jitter while standing still. So the device ignores GPS altitude entirely.
Instead, elevation is baked into the map tiles. When the app builds a tile it
also fetches a coarse DEM (digital elevation model) for that area from
Open-Meteo and appends it as an ELV1 block (~20×20
samples, ≈350 m spacing — see Tile format).
At runtime the device reads its altitude by bilinearly interpolating that grid at
the current GPS position and accumulates climb from it — a smooth, real elevation
profile that needs only a horizontal fix. The trade-off: elevation exists only
where you've downloaded tiles.
A receiver that has no idea where or when it is — a cold start, on first power-on or after its almanac goes stale — can take many minutes to fix: it blindly searches the whole sky. Two things cut that down:
AID-INI or a u-blox
UBX aiding frame depending on the detected chip (see
src/gps_service.cpp) — so the receiver knows where to
look and locks on fast. The phone location also stands in as the map position
until the device's own fix lands.The reference board works well, but a few of its choices are compromises the firmware works around. A future revision — or a custom board — could improve on them:
This is the beginning of the README. Read the rest at the original. Read the full README ↗