- background page (4th tile): built-in or any GIF in /gifs on the SD card - chosen GIF is copied into a raw 11.9 MB 'bggif' flash partition (header written last) and played memory-mapped from flash; SD only needed when choosing or when the file changed (checked at boot in the background) - own partitions.csv: 4 MB app + bggif + NVS - tools/gif_to_360.py: convert GIFs to 360x360 keeping frame timing; converted output (12-OBD-Speed/sd/) is git-ignored Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.8 KiB
OBD Speed (JC3636W518)
Vehicle speed from an ELM327 over BLE, shown as a big number + arc gauge on top of an animated GIF.
Uses the shared board library and LVGL 9.6 (../shared), NimBLE-Arduino 2.5.1.
Use
- Speed page — speed in km/h (
--= no data: not connected, or ignition off), arc gauge 0–200 km/h, status pill below the number (adapter name when running, otherwise what it is doing). Battery voltage (ATRV, every 2 s) as a small arc in the bottom gap (11–15 V) + number; color: red < 11.8 V, orange < 12.2 V, green < 13.0 V (resting OK), blue ≤ 14.8 V (charging), red above (overcharge). - Swipe left → adapter menu — scans while open. OBD-like adapters (name OBD/ELM/…, or service FFF0/FFE0/18F0) are listed first in green. Tap one to select it: it is remembered (NVS) and connected immediately. Forget clears the remembered adapter, Done (or swipe right) returns to the speed page.
- Swipe left again → settings — screen rotation 0 / 90 / 180 / 270 degrees, and screen off without data Off / 2 / 5 / 10 min (default 2). Both remembered in NVS.
- Swipe left once more → background —
Built-inplus every GIF in/gifson the SD card (size and dimensions shown; not 360×360 in orange). Tap one: it is copied into the device's flash (progress shown) and played from there, so the SD card is not needed afterwards. At boot the device checks (in the background) whether the chosen file on the SD card changed (size/date) and re-copies it. Rescan re-reads the card. - Idle — after that time without speed data (ignition off, adapter gone) the screen goes dark, the GIF pauses and
OBD polling stops; only
ATRVevery 30 s (answered by the adapter itself, doesn't wake the car's bus). Wakes on a touch (the touch is swallowed) or by itself when the voltage rises above 13.2 V (engine started). Not used while no adapter is chosen. - On power-up the remembered adapter is connected automatically; if the link drops or the adapter is not there (car off), it retries every 3 s. With no adapter remembered, the device starts on the menu page.
How it talks to the ELM327
Service FFF0, notifications + commands on FFF1 (verified with the user's "OBDII" adapter, see
docs/2026-10-23_ble_scanner_car_test.txt, made with the BLE scanner tool that was removed afterwards — in git history); other adapters: first notify+write pair.
Init: ATZ, ATE0, ATL0, ATS0, ATH0, ATSP0, 0100; then 010D (speed) is polled continuously.
Serial (115200) prints status changes as [obd] ....
Files
| File | What |
|---|---|
src/main.cpp |
LVGL UI (tileview: speed page + menu page) |
src/obd_link.cpp/.h |
BLE scan, connect/reconnect, ELM327 init and speed polling (background task on core 0) |
src/font_speed_120.c |
Montserrat Medium 120 px, digits and -, 4 bpp (generated with lv_font_conv, see header) |
src/bg_store.cpp/.h |
Background GIF from the SD card: list /gifs, copy into the bggif flash partition (header written last), mmap for playback, change check at boot (background task) |
partitions.csv |
4 MB app (no OTA) + 11.9 MB bggif raw area + NVS |
data/bg.gif |
Built-in background (ezgif-5-cb56986bc7.gif, 360×360), linked into the firmware via board_build.embed_files |
sd/gifs/ |
(not in git) GIFs converted with ../tools/gif_to_360.py, ready to copy to the SD card |
GIFs for the SD card
Convert any GIF to 360×360 (scale to cover, center crop, frame timing kept) with
pip install pillow
python ../tools/gif_to_360.py <gif files or folders> -o sd/gifs
and copy the files into a folder gifs on the SD card. Max ~11.5 MB per GIF. GIFs are played from flash at their own
frame rate (360×360: ~10–12 ms decode per frame).
Replace data/bg.gif to change the built-in background.