π Language: English Β· Π ΡΡΡΠΊΠΈΠΉ
WEC-style real-time telemetry dashboard for Le Mans Ultimate (rFactor 2 engine). Built for endurance racing β your remote strategist watches the same data as a real pit-wall engineer.
A self-hosted alternative to services like mylmu. Reads the rF2 Shared Memory Map Plugin sections directly, streams a compact JSON snapshot over WebSocket at 50 Hz, and renders it as a hardcore monospace dashboard that mirrors the look of a real WEC pit wall.
- Live telemetry @ 50 Hz β gear, RPM, speed, throttle/brake/clutch, steering
- 4-wheel tire panel β inner/center/outer temperatures with coldβoptimalβhot colour mapping, pressure (PSI + kPa), wear, carcass and brake temps
- Car status β fuel (with low/critical warning), water temp, oil temp, turbo boost
- Timing tower β position, lap, current/last/best times, full S1/S2/S3 table with delta column, session-best (magenta) highlighting, active sector indicator
- Strategy assist β rolling fuel-per-lap, laps-left estimate, stop count, penalties, gap to ahead/leader
- Flag strip β LIVE / PIT / SPDLIM / OVERHEAT / FUEL! / YELLOW
- Auto-reconnect WebSocket with exponential backoff
--demomode β runs without LMU, perfect for testing the UI on macOS/Linux- Single-file frontend β no build step, no npm, no framework
ββββββββββββββββ Shared Memory ββββββββββββββββ WebSocket 50Hz ββββββββββββββββ
β Le Mans β βββββββββββββββββββΊ β server.py β ββββββββββββββββββΊ β index.html β
β Ultimate + β $rFactor2SMMP_ β FastAPI + β ws:// β Vanilla JS β
β rF2 SMMP β Telemetry$ β ctypes β /ws β Monospace β
β Plugin β Scoring$ β parser β β Dashboard β
ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ
ngrok / cloudflared
β
βΌ
Strategist's browser anywhere
- Le Mans Ultimate installed (Windows).
- rF2 Shared Memory Map Plugin (TheIronWolfMod) β required so that the
$rFactor2SMMP_Telemetry$/$rFactor2SMMP_Scoring$sections exist:- download
rF2SharedMemoryMapPlugin64.dllfrom the original repo - drop it into
<LMU install>\Bin64\Plugins\ - enable the plugin inside the game (
Settings β Plugins)
- download
- Python 3.10+.
git clone https://github.com/<your-user>/le-mans-ultimate-telemetry.git
cd le-mans-ultimate-telemetry
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install fastapi "uvicorn[standard]"# Demo mode β synthetic data, no LMU required (great for UI checks)
python server.py --demo
# Production β LMU is running, plugin is loaded
python server.py
# Custom port / rate
python server.py --host 0.0.0.0 --port 8000 --hz 60Open http://127.0.0.1:8000/ β you should see the full dashboard. If LMU is in
the main menu the UI will display AWAITING TELEMETRY; the server itself
will not crash.
The backend must stay on the racing PC β only that machine has access to LMU's Shared Memory. Two pieces have to be live during a race:
# terminal 1
python server.py
# terminal 2
ngrok http 8000
# β https://<random>.ngrok-free.appFor 24h races, reserve a fixed ngrok subdomain so the URL never changes:
ngrok http --domain=your-reserved-name.ngrok-free.app 8000The dashboard is already live at https://lmu-pitwall.pages.dev/. Your strategist opens that URL from anywhere. On the first visit they enter the WebSocket address once (or you send them a pre-baked link):
https://lmu-pitwall.pages.dev/?ws=wss://your-reserved-name.ngrok-free.app/ws
The URL is remembered in localStorage, so refreshes / reboots Just Work.
A β CONNECTION button in the footer lets them change it at any time.
A complete operating manual lives in two languages: STRATEGIST_GUIDE.md (English) / STRATEGIST_GUIDE.ru.md (Russian). Each covers the screen layout, tire-colour cheat sheet, lap-time colour code, 7 typical race scenarios and what to radio in each, troubleshooting, and a pit journal template. Send the right language to your engineer before the race.
Inside the dashboard, the ? GUIDE button (footer) opens an in-app
condensed version of the same cheat sheet β strategist never has to leave
the screen during a stint.
After cloning the repo:
npm install # one-time, installs wrangler locally
npx wrangler login # one-time, opens Cloudflare OAuth in browser
npm run deploy # deploys static/ to https://lmu-pitwall.pages.devUseful follow-ups:
npm run list # list past deployments
npm run tail # live tail logs (HTTP requests, errors)
npm run deploy:preview # deploy to a preview branch URL- In the Cloudflare dashboard: Workers & Pages β lmu-pitwall β Custom domains β Set up a custom domain.
- Enter
pitwall.your-domain.com(or apexyour-domain.com). - If the domain's DNS is already on Cloudflare, it's wired automatically. If
not, add a CNAME record pointing to
lmu-pitwall.pages.devat your registrar.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β LMU PIT WALL Β· CKT Β· CAR Β· DRV Β· CLS Β· AIR/TRK/WET Β· sessionclock β
ββββββββββββββββββββββββββββββ¬βββββββββββββββββββ¬βββββββββββββββββββββββββββββββ€
β VITALS β TIRES β TIMING TOWER β
β β ββββββ ββββββ β ββββββββββββ ββββββββββββ β
β βββββββββββββββββββββ β β FL β β FR β β β POSITION β β LAP β β
β β β β ββββββ ββββββ β β 03 β β 47 β β
β β 6 β β ββββββ ββββββ β ββββββββββββ΄ββ΄βββββββββββ€ β
β β β β β RL β β RR β β β CURR 3:31.423 β β
β βββββββββββββββββββββ β ββββββ ββββββ β β LAST 3:30.124 β β
β [ββββ shift lights] β β β BEST 3:28.912 β β
β ββββββββββββββββββββ€ ββββββββββββββββββββββββββββ€
β THR BRK CLT β CAR STATUS β β S1 / S2 / S3 / Ξ β β
β β FUEL 84.3L β β ... β β
β [ββ STEERING ββ] β WATER 88Β° OIL 96β β GAPS Β· FLAGS β β
ββββββββββββββββββββββββββββββ΄βββββββββββββββββββ΄βββββββββββββββββββββββββββββββ
le-mans-ultimate-telemetry/
βββ server.py # FastAPI + ctypes SMMP reader + WebSocket stream
βββ static/
β βββ index.html # Monolithic frontend (HTML + CSS + JS)
βββ package.json # npm scripts for wrangler deploy
βββ wrangler.toml # Cloudflare Pages config
βββ STRATEGIST_GUIDE.md # Full strategist manual (English)
βββ STRATEGIST_GUIDE.ru.md # Full strategist manual (Russian)
βββ README.md # This file (English)
βββ README.ru.md # This file (Russian)
βββ LICENSE
βββ .gitignore
| Variable | Where | Default | What it controls |
|---|---|---|---|
STREAM_HZ (CLI --hz) |
server.py |
50 | WebSocket frame rate |
tireColor() thresholds |
index.html JS |
60 / 80β100 / 115 Β°C | Cold / optimal / hot tire colour bands |
fuel low / critical |
index.html JS |
25 / 10 L | When the FUEL card turns orange / blinks red |
ovh threshold |
index.html JS |
water > 110 Β°C or oil > 130 Β°C | Activates OVHEAT flag |
- "AWAITING TELEMETRY" stays forever β the SMMP plugin DLL is not loaded.
Verify the path (
<LMU>\Bin64\Plugins\) and that LMU has loaded it (Settings β Pluginscheckbox). ModuleNotFoundError: No module named 'fastapi'β activate your venv, thenpip install fastapi "uvicorn[standard]".- Strategist gets "Mixed Content" error β ngrok HTTPS forwards to plain
HTTP backend, this is normal; the frontend uses
wss://so it works. - Wrong tire temperatures β values are converted from Kelvin in
_wheel_to_dict(). Double-checkKELVINconstant if your readings look off by ~273Β°.
- Shared memory layout based on rF2SharedMemoryMapPlugin by TheIronWolfMod
- Visual language inspired by FIA WEC / F1 pit-wall engineer dashboards